QElectroTech  0.70
partrectangle.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 "partrectangle.h"
19 #include "elementscene.h"
23 
30 PartRectangle::PartRectangle(QETElementEditor *editor, QGraphicsItem *parent) :
31  CustomElementGraphicPart(editor, parent)
32 {}
33 
38  removeHandler();
39 }
40 
48 void PartRectangle::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget)
49 {
50  Q_UNUSED(widget);
51  applyStylesToQPainter(*painter);
52  QPen t = painter -> pen();
53  t.setCosmetic(options && options -> levelOfDetail < 1.0);
54 
55  if (isSelected())
56  t.setColor(Qt::red);
57 
58  t.setJoinStyle(Qt::MiterJoin);
59 
60  //Force the pen to width 0 if one of dimension is null
61  if (!rect().width() || !rect().height())
62  t.setWidth(0);
63 
64  painter->setPen(t);
65  painter->drawRoundedRect(m_rect, m_xRadius, m_yRadius);
66 
67  if (m_hovered)
68  drawShadowShape(painter);
69 
70  if (isSelected())
71  drawCross(m_rect.center(), painter);
72 }
73 
80 const QDomElement PartRectangle::toXml(QDomDocument &xml_document) const
81 {
82  QDomElement xml_element = xml_document.createElement("rect");
83  QPointF top_left(sceneTopLeft());
84  xml_element.setAttribute("x", QString("%1").arg(top_left.x()));
85  xml_element.setAttribute("y", QString("%1").arg(top_left.y()));
86  xml_element.setAttribute("width", QString("%1").arg(m_rect.width()));
87  xml_element.setAttribute("height", QString("%1").arg(m_rect.height()));
88 
89  QRectF rect = m_rect.normalized();
90  qreal x = m_xRadius;
91  if (x > rect.width()/2) {
92  x = rect.width()/2;
93  }
94  qreal y = m_yRadius;
95  if (y > rect.height()/2) {
96  y = rect.height()/2;
97  }
98 
99  xml_element.setAttribute("rx", QString::number(m_xRadius));
100  xml_element.setAttribute("ry", QString::number(m_yRadius));
101 
102  stylesToXml(xml_element);
103  return(xml_element);
104 }
105 
111 void PartRectangle::fromXml(const QDomElement &qde)
112 {
113  stylesFromXml(qde);
114  setPos(mapFromScene(qde.attribute("x", "0").toDouble(),
115  qde.attribute("y", "0").toDouble()));
116 
117  QRectF rect(QPointF(0,0), QSizeF(qde.attribute("width", "0").toDouble(),
118  qde.attribute("height", "0").toDouble()));
119 
120  setRect(rect.normalized());
121  setXRadius(qde.attribute("rx", "0").toDouble());
122  setYRadius(qde.attribute("ry", "0").toDouble());
123 }
124 
129 QRectF PartRectangle::rect() const {
130  return m_rect;
131 }
132 
138 void PartRectangle::setRect(const QRectF &rect)
139 {
140  if (rect == m_rect) return;
141  prepareGeometryChange();
142  m_rect = rect;
144  emit rectChanged();
145 }
146 
148 {
149  m_xRadius = X;
150  update();
152  emit XRadiusChanged();
153 }
154 
156 {
157  m_yRadius = Y;
158  update();
160  emit YRadiusChanged();
161 }
162 
171  return(mapToScene(rect()).boundingRect());
172 }
173 
179  return(mapToScene(rect().topLeft()));
180 }
181 
186 QPainterPath PartRectangle::shape() const
187 {
188  QPainterPath shape;
189  shape.addRoundedRect(m_rect, m_xRadius, m_yRadius);
190 
191  QPainterPathStroker pps;
192  pps.setWidth(m_hovered? penWeight()+SHADOWS_HEIGHT : penWeight());
193  shape = pps.createStroke(shape);
194 
195  return shape;
196 }
197 
198 QPainterPath PartRectangle::shadowShape() const
199 {
200  QPainterPath shape;
201  shape.addRoundedRect(m_rect, m_xRadius, m_yRadius);
202 
203  QPainterPathStroker pps;
204  pps.setWidth(penWeight());
205 
206  return (pps.createStroke(shape));
207 }
208 
214 {
215  qreal adjust = (SHADOWS_HEIGHT + penWeight()) / 2;
216  //We add 0.5 because CustomElementGraphicPart::drawShadowShape
217  //draw a shape bigger of 0.5 when pen weight is to 0.
218  if (penWeight() == 0) adjust += 0.5;
219 
220  QRectF r = m_rect.normalized();
221  r.adjust(-adjust, -adjust, adjust, adjust);
222 
223  return(r);
224 }
225 
232  return(rect().isNull());
233 }
234 
241 void PartRectangle::startUserTransformation(const QRectF &initial_selection_rect)
242 {
243  Q_UNUSED(initial_selection_rect)
244  // we keep track of our own rectangle at the moment in scene coordinates too
245  saved_points_.clear();
246  saved_points_ << mapToScene(rect().topLeft()) << mapToScene(rect().bottomRight());
247 }
248 
255 void PartRectangle::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect)
256 {
257  QList<QPointF> mapped_points = mapPoints(initial_selection_rect, new_selection_rect, saved_points_);
258  setRect(QRectF(mapFromScene(mapped_points.at(0)), mapFromScene(mapped_points.at(1))));
259 }
260 
266 void PartRectangle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
267 {
268  if (event->button() == Qt::LeftButton && event->buttonDownPos(Qt::LeftButton) == event->pos())
270 
272 }
273 
280 QVariant PartRectangle::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
281 {
282  if (change == ItemSelectedHasChanged && scene())
283  {
284  if (value.toBool() == true)
285  {
286  //When item is selected, he must to be up to date whene the selection in the scene change, for display or not the handler,
287  //according to the number of selected items.
288  connect(scene(), &QGraphicsScene::selectionChanged, this, &PartRectangle::sceneSelectionChanged);
289 
290  if (scene()->selectedItems().size() == 1)
291  addHandler();
292  }
293  else
294  {
295  disconnect(scene(), &QGraphicsScene::selectionChanged, this, &PartRectangle::sceneSelectionChanged);
296  removeHandler();
297  }
298  }
299  else if (change == ItemPositionHasChanged)
300  {
302  }
303  else if (change == ItemSceneChange)
304  {
305  if(scene())
306  disconnect(scene(), &QGraphicsScene::selectionChanged, this, &PartRectangle::sceneSelectionChanged);
307 
308  setSelected(false); //This item is removed from scene, then we deselect this, and so, the handlers is also removed.
309  }
310 
311  return QGraphicsItem::itemChange(change, value);
312 }
313 
320 bool PartRectangle::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
321 {
322  //Watched must be an handler
323  if(watched->type() == QetGraphicsHandlerItem::Type)
324  {
325  QetGraphicsHandlerItem *qghi = qgraphicsitem_cast<QetGraphicsHandlerItem *>(watched);
326 
327  if(m_handler_vector.contains(qghi)) //Handler must be in m_vector_index, then we can start resize
328  {
329  m_vector_index = m_handler_vector.indexOf(qghi);
330  if (m_vector_index != -1)
331  {
332  if(event->type() == QEvent::GraphicsSceneMousePress) //Click
333  {
334  handlerMousePressEvent(qghi, static_cast<QGraphicsSceneMouseEvent *>(event));
335  return true;
336  }
337  else if(event->type() == QEvent::GraphicsSceneMouseMove) //Move
338  {
339  handlerMouseMoveEvent(qghi, static_cast<QGraphicsSceneMouseEvent *>(event));
340  return true;
341  }
342  else if (event->type() == QEvent::GraphicsSceneMouseRelease) //Release
343  {
344  handlerMouseReleaseEvent(qghi, static_cast<QGraphicsSceneMouseEvent *>(event));
345  return true;
346  }
347  }
348  }
349  }
350 
351  return false;
352 }
353 
358 {
359  if (m_resize_mode == 1)
360  {
361  m_resize_mode = 2;
363  qghi->setColor(Qt::darkGreen);
364  }
365  else if (m_resize_mode == 2)
366  {
367  m_resize_mode = 3;
368  qDeleteAll(m_handler_vector);
369  m_handler_vector.clear();
370  addHandler();
372  qghi->setColor(Qt::magenta);
373  }
374  }
375  else if (m_resize_mode == 3)
376  {
377  m_resize_mode = 1;
378  qDeleteAll(m_handler_vector);
379  m_handler_vector.clear();
380  addHandler();
382  qghi->setColor(Qt::blue);
383  }
384  }
385 }
386 
391 {
392  if (m_handler_vector.isEmpty()) {
393  return;
394  }
395 
396  QVector <QPointF> points_vector;
397 
398  if(m_resize_mode != 3) {
400  }
401  else {
403  }
404 
405  if (m_handler_vector.size() == points_vector.size())
406  {
407  points_vector = mapToScene(points_vector);
408  for (int i = 0 ; i < points_vector.size() ; ++i)
409  m_handler_vector.at(i)->setPos(points_vector.at(i));
410  }
411  else
412  {
413  qDeleteAll(m_handler_vector);
414  m_handler_vector.clear();
415  addHandler();
416  }
417 }
418 
424 void PartRectangle::handlerMousePressEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
425 {
426  Q_UNUSED(qghi)
427  Q_UNUSED(event)
428 
429  m_old_rect = m_rect;
432  if(m_xRadius == 0 && m_yRadius == 0) {
434  }
435 }
436 
442 void PartRectangle::handlerMouseMoveEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
443 {
444  Q_UNUSED(qghi)
445 
446  QPointF new_pos = event->scenePos();
447  if (event->modifiers() != Qt::ControlModifier)
448  new_pos = elementScene()->snapToGrid(event->scenePos());
449  new_pos = mapFromScene(new_pos);
450 
451  if (m_resize_mode == 1)
453  else if (m_resize_mode == 2)
455  else
456  {
459  setXRadius(radius);
460  setYRadius(radius);
461  }
462  else if(m_vector_index == 0) {
463  setXRadius(radius);
464  }
465  else {
466  setYRadius(radius);
467  }
468  }
469 
471 }
472 
473 void PartRectangle::handlerMouseReleaseEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
474 {
475  Q_UNUSED(qghi)
476  Q_UNUSED(event)
477 
478  m_modifie_radius_equaly = false;
479 
480  QUndoCommand *undo = new QUndoCommand("Modifier un rectangle");
481  if (m_old_rect != m_rect) {
482  QPropertyUndoCommand *u = new QPropertyUndoCommand(this, "rect", QVariant(m_old_rect.normalized()), QVariant(m_rect.normalized()), undo);
483  u->setAnimated(true, false);
484  }
485  if (m_old_xRadius != m_xRadius) {
486  QPropertyUndoCommand *u = new QPropertyUndoCommand(this, "xRadius", QVariant(m_old_xRadius), QVariant(m_xRadius), undo);
487  u->setAnimated();
488  }
489  if (m_old_yRadius != m_yRadius) {
490  QPropertyUndoCommand *u = new QPropertyUndoCommand(this, "yRadius", QVariant(m_old_yRadius), QVariant(m_yRadius), undo);
491  u->setAnimated();
492  }
493 
494  elementScene()->undoStack().push(undo);
495  m_vector_index = -1;
496 }
497 
503 {
504  if (this->isSelected() && scene()->selectedItems().size() == 1)
505  addHandler();
506  else
507  removeHandler();
508 }
509 
515 {
516  if (m_handler_vector.isEmpty() && scene())
517  {
518  if (m_resize_mode != 3) {
520  }
521  else {
523  }
524 
526  {
527  QColor color;
528  if(m_resize_mode == 1) {color = Qt::blue;}
529  else if (m_resize_mode == 2) {color = Qt::darkGreen;}
530  else {color = Qt::magenta;}
531 
532  handler->setColor(color);
533  scene()->addItem(handler);
534  handler->installSceneEventFilter(this);
535  handler->setZValue(this->zValue()+1);
536  }
537  }
538 }
539 
545 {
546  if (!m_handler_vector.isEmpty())
547  {
548  qDeleteAll(m_handler_vector);
549  m_handler_vector.clear();
550  }
551 }
void sceneSelectionChanged()
PartRectangle::sceneSelectionChanged When the scene selection change, if there are several primitive ...
The QPropertyUndoCommand class This undo command manage QProperty of a QObject. This undo command can...
void adjusteHandlerPos()
PartRectangle::adjusteHandlerPos.
virtual QPointF sceneTopLeft() const
PartRectangle::sceneTopLeft.
void handlerMouseReleaseEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
bool m_modifie_radius_equaly
QRectF rect() const
QRectF boundingRect() const override
PartRectangle::boundingRect.
const QDomElement toXml(QDomDocument &) const override
PartRectangle::toXml Export this rectangle in xml.
The QetGraphicsHandlerItem class This graphics item represents a point, destined to be used as an han...
PartRectangle(QETElementEditor *, QGraphicsItem *parent=nullptr)
PartRectangle::PartRectangle Constructor.
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *=nullptr) override
PartRectangle::paint Draw this Rectangle.
void XRadiusChanged()
QPainterPath shape() const override
PartRectangle::shape.
static QVector< QPointF > pointForRadiusRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode=Qt::AbsoluteSize)
QetGraphicsHandlerUtility::pointForRadiusRect.
static qreal radiusForPosAtIndex(const QRectF &rect, const QPointF &pos, int index, Qt::SizeMode mode=Qt::AbsoluteSize)
QetGraphicsHandlerUtility::radiusForPosAtIndex.
bool sceneEventFilter(QGraphicsItem *watched, QEvent *event) override
PartRectangle::sceneEventFilter.
void setRect(const QRectF &rect)
PartRectangle::setRect Sets the item&#39;s rectangle to be the given rectangle.
static void drawCross(const QPointF &center, QPainter *painter)
CustomElementGraphicPart::drawCross Draw a cross at pos center.
QList< QPointF > mapPoints(const QRectF &, const QRectF &, const QList< QPointF > &)
The CustomElementGraphicPart class This class is the base for all home-made primitive like line...
QUndoStack & undoStack()
void handlerMouseMoveEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
PartRectangle::handlerMouseMoveEvent.
static QRectF mirrorRectForPosAtIndex(const QRectF &old_rect, const QPointF &pos, int index)
QetGraphicsHandlerUtility::mirrorRectForPosAtIndex Return a rectangle after modification of the point...
void stylesToXml(QDomElement &) const
CustomElementGraphicPart::stylesToXml Write the curent style to xml element. The style are stored lik...
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 addHandler()
PartRectangle::addHandler Add handlers for this item.
QList< QPointF > saved_points_
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override
void setYRadius(qreal Y)
void setXRadius(qreal X)
void fromXml(const QDomElement &) override
PartRectangle::fromXml Import the properties of this rectangle from a xml element.
void YRadiusChanged()
void handleUserTransformation(const QRectF &, const QRectF &) override
PartRectangle::handleUserTransformation Handle the user-induced transformation from initial_selection...
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override
PartRectangle::mouseReleaseEvent Handle mouse release event.
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override
PartRectangle::itemChange.
void rectChanged()
void removeHandler()
PartRectangle::removeHandler Remove the handlers of this item.
QPainterPath shadowShape() const override
bool isUseless() const override
PartRectangle::isUseless.
void stylesFromXml(const QDomElement &)
CustomElementGraphicPart::stylesFromXml Read the style used by this, from a xml element.
static QVector< QPointF > pointsForRect(const QRectF &rect)
QetGraphicsHandlerUtility::pointsForRect Return the keys points of the rectangle, stored in a vector...
~PartRectangle() override
PartRectangle::~PartRectangle.
QVector< QetGraphicsHandlerItem * > m_handler_vector
QRectF sceneGeometricRect() const override
PartRectangle::sceneGeometricRect.
void handlerMousePressEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
PartRectangle::handlerMousePressEvent.
void switchResizeMode()
PartRectangle::switchResizeMode.
virtual ElementScene * elementScene() const
#define SHADOWS_HEIGHT
static QVector< QetGraphicsHandlerItem * > handlerForPoint(const QVector< QPointF > &points, int size=10)
QetGraphicsHandlerItem::handlerForPoint.
void setAnimated(bool animate=true, bool first_time=true)
QPropertyUndoCommand::setAnimated.
qreal penWeight() const
CustomElementGraphicPart::penWeight.
void startUserTransformation(const QRectF &) override
PartRectangle::startUserTransformation Start the user-induced transformation, provided this primitive...
void applyStylesToQPainter(QPainter &) const
CustomElementGraphicPart::applyStylesToQPainter Apply the current style to the QPainter.
QPointF snapToGrid(QPointF point)
void drawShadowShape(QPainter *painter)
CustomElementGraphicPart::drawShadowShape Draw a transparent blue shadow arround the shape of this it...