labplot  2.8.2
About: LabPlot is an application for plotting and analysis of 2D and 3D functions and data. It is a complete rewrite of LabPlot1 and lacks in the first release a lot of features available in the predecessor. On the other hand, the GUI and the usability is more superior.
  Fossies Dox: labplot-2.8.2.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

CustomPoint.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  File : CustomPoint.cpp
3  Project : LabPlot
4  Description : Custom user-defined point on the plot
5  --------------------------------------------------------------------
6  Copyright : (C) 2015 Ankit Wagadre (wagadre.ankit@gmail.com)
7  Copyright : (C) 2015-2020 Alexander Semke (alexander.semke@web.de)
8  ***************************************************************************/
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  * This program is distributed in the hope that it will be useful, *
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19  * GNU General Public License for more details. *
20  * *
21  * You should have received a copy of the GNU General Public License *
22  * along with this program; if not, write to the Free Software *
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
24  * Boston, MA 02110-1301 USA *
25  * *
26  ***************************************************************************/
27 
28 #include "CustomPoint.h"
29 #include "CustomPointPrivate.h"
35 
36 #include <QPainter>
37 #include <QMenu>
38 #include <QGraphicsSceneMouseEvent>
39 
40 #include <KConfig>
41 #include <KConfigGroup>
42 #include <KLocalizedString>
43 
44 
45 /**
46  * \class CustomPoint
47  * \brief A customizable point.
48  *
49  * The position can be either specified by mouse events or by providing the
50  * x- and y- coordinates in parent's coordinate system
51  */
52 
53 CustomPoint::CustomPoint(const CartesianPlot* plot, const QString& name)
54  : WorksheetElement(name, AspectType::CustomPoint), d_ptr(new CustomPointPrivate(this, plot)) {
55 
56  init();
57 }
58 
60  : WorksheetElement(name, AspectType::CustomPoint), d_ptr(dd) {
61 
62  init();
63 }
64 
65 //no need to delete the d-pointer here - it inherits from QGraphicsItem
66 //and is deleted during the cleanup in QGraphicsScene
67 CustomPoint::~CustomPoint() = default;
68 
70  Q_D(CustomPoint);
71 
72  KConfig config;
73  KConfigGroup group;
74  group = config.group("CustomPoint");
75  d->position.setX( group.readEntry("PositionXValue", d->plot->xMin() + (d->plot->xMax()-d->plot->xMin())/2) );
76  d->position.setY( group.readEntry("PositionYValue", d->plot->yMin() + (d->plot->yMax()-d->plot->yMin())/2) );
77 
78  d->symbolStyle = (Symbol::Style)group.readEntry("SymbolStyle", (int)Symbol::Style::Circle);
79  d->symbolSize = group.readEntry("SymbolSize", Worksheet::convertToSceneUnits(5, Worksheet::Unit::Point));
80  d->symbolRotationAngle = group.readEntry("SymbolRotation", 0.0);
81  d->symbolOpacity = group.readEntry("SymbolOpacity", 1.0);
82  d->symbolBrush.setStyle( (Qt::BrushStyle)group.readEntry("SymbolFillingStyle", (int)Qt::SolidPattern) );
83  d->symbolBrush.setColor( group.readEntry("SymbolFillingColor", QColor(Qt::red)) );
84  d->symbolPen.setStyle( (Qt::PenStyle)group.readEntry("SymbolBorderStyle", (int)Qt::SolidLine) );
85  d->symbolPen.setColor( group.readEntry("SymbolBorderColor", QColor(Qt::black)) );
86  d->symbolPen.setWidthF( group.readEntry("SymbolBorderWidth", Worksheet::convertToSceneUnits(0.0, Worksheet::Unit::Point)) );
87 
88  this->initActions();
89 }
90 
92  visibilityAction = new QAction(i18n("Visible"), this);
93  visibilityAction->setCheckable(true);
94  connect(visibilityAction, &QAction::triggered, this, &CustomPoint::visibilityChanged);
95 }
96 
97 /*!
98  Returns an icon to be used in the project explorer.
99 */
100 QIcon CustomPoint::icon() const {
101  return QIcon::fromTheme("draw-cross");
102 }
103 
105  QMenu* menu = WorksheetElement::createContextMenu();
106  QAction* firstAction = menu->actions().at(1); //skip the first action because of the "title-action"
107  visibilityAction->setChecked(isVisible());
108  menu->insertAction(firstAction, visibilityAction);
109 
110  return menu;
111 }
112 
113 QGraphicsItem* CustomPoint::graphicsItem() const {
114  return d_ptr;
115 }
116 
118  Q_D(CustomPoint);
119  d->retransform();
120 }
121 
122 void CustomPoint::handleResize(double horizontalRatio, double verticalRatio, bool pageResize) {
123  Q_UNUSED(horizontalRatio);
124  Q_UNUSED(verticalRatio);
125  Q_UNUSED(pageResize);
126 }
127 
128 /* ============================ getter methods ================= */
129 CLASS_SHARED_D_READER_IMPL(CustomPoint, QPointF, position, position)
130 
131 //symbols
132 BASIC_SHARED_D_READER_IMPL(CustomPoint, Symbol::Style, symbolStyle, symbolStyle)
133 BASIC_SHARED_D_READER_IMPL(CustomPoint, qreal, symbolOpacity, symbolOpacity)
134 BASIC_SHARED_D_READER_IMPL(CustomPoint, qreal, symbolRotationAngle, symbolRotationAngle)
135 BASIC_SHARED_D_READER_IMPL(CustomPoint, qreal, symbolSize, symbolSize)
136 CLASS_SHARED_D_READER_IMPL(CustomPoint, QBrush, symbolBrush, symbolBrush)
137 CLASS_SHARED_D_READER_IMPL(CustomPoint, QPen, symbolPen, symbolPen)
138 
139 /* ============================ setter methods and undo commands ================= */
140 STD_SETTER_CMD_IMPL_F_S(CustomPoint, SetPosition, QPointF, position, retransform)
141 void CustomPoint::setPosition(QPointF position) {
142  Q_D(CustomPoint);
143  if (position != d->position)
144  exec(new CustomPointSetPositionCmd(d, position, ki18n("%1: set position")));
145 }
146 
147 //Symbol
148 STD_SETTER_CMD_IMPL_F_S(CustomPoint, SetSymbolStyle, Symbol::Style, symbolStyle, recalcShapeAndBoundingRect)
149 void CustomPoint::setSymbolStyle(Symbol::Style style) {
150  Q_D(CustomPoint);
151  if (style != d->symbolStyle)
152  exec(new CustomPointSetSymbolStyleCmd(d, style, ki18n("%1: set symbol style")));
153 }
154 
155 STD_SETTER_CMD_IMPL_F_S(CustomPoint, SetSymbolSize, qreal, symbolSize, recalcShapeAndBoundingRect)
156 void CustomPoint::setSymbolSize(qreal size) {
157  Q_D(CustomPoint);
158  if (!qFuzzyCompare(1 + size, 1 + d->symbolSize))
159  exec(new CustomPointSetSymbolSizeCmd(d, size, ki18n("%1: set symbol size")));
160 }
161 
162 STD_SETTER_CMD_IMPL_F_S(CustomPoint, SetSymbolRotationAngle, qreal, symbolRotationAngle, recalcShapeAndBoundingRect)
163 void CustomPoint::setSymbolRotationAngle(qreal angle) {
164  Q_D(CustomPoint);
165  if (!qFuzzyCompare(1 + angle, 1 + d->symbolRotationAngle))
166  exec(new CustomPointSetSymbolRotationAngleCmd(d, angle, ki18n("%1: rotate symbols")));
167 }
168 
169 STD_SETTER_CMD_IMPL_F_S(CustomPoint, SetSymbolBrush, QBrush, symbolBrush, update)
170 void CustomPoint::setSymbolBrush(const QBrush &brush) {
171  Q_D(CustomPoint);
172  if (brush != d->symbolBrush)
173  exec(new CustomPointSetSymbolBrushCmd(d, brush, ki18n("%1: set symbol filling")));
174 }
175 
176 STD_SETTER_CMD_IMPL_F_S(CustomPoint, SetSymbolPen, QPen, symbolPen, recalcShapeAndBoundingRect)
177 void CustomPoint::setSymbolPen(const QPen &pen) {
178  Q_D(CustomPoint);
179  if (pen != d->symbolPen)
180  exec(new CustomPointSetSymbolPenCmd(d, pen, ki18n("%1: set symbol outline style")));
181 }
182 
183 STD_SETTER_CMD_IMPL_F_S(CustomPoint, SetSymbolOpacity, qreal, symbolOpacity, update)
184 void CustomPoint::setSymbolOpacity(qreal opacity) {
185  Q_D(CustomPoint);
186  if (opacity != d->symbolOpacity)
187  exec(new CustomPointSetSymbolOpacityCmd(d, opacity, ki18n("%1: set symbol opacity")));
188 }
189 
190 STD_SWAP_METHOD_SETTER_CMD_IMPL_F(CustomPoint, SetVisible, bool, swapVisible, update);
191 void CustomPoint::setVisible(bool on) {
192  Q_D(CustomPoint);
193  exec(new CustomPointSetVisibleCmd(d, on, on ? ki18n("%1: set visible") : ki18n("%1: set invisible")));
194 }
195 
197  Q_D(const CustomPoint);
198  return d->isVisible();
199 }
200 
202  Q_D(CustomPoint);
203  d->m_printing = on;
204 }
205 
206 //##############################################################################
207 //###### SLOTs for changes triggered via QActions in the context menu ########
208 //##############################################################################
210  Q_D(const CustomPoint);
211  this->setVisible(!d->isVisible());
212 }
213 
214 //##############################################################################
215 //####################### Private implementation ###############################
216 //##############################################################################
217 CustomPointPrivate::CustomPointPrivate(CustomPoint* owner, const CartesianPlot* p) : plot(p), q(owner) {
218  setFlag(QGraphicsItem::ItemSendsGeometryChanges);
219  setFlag(QGraphicsItem::ItemIsMovable);
220  setFlag(QGraphicsItem::ItemIsSelectable);
221  setAcceptHoverEvents(true);
222 }
223 
224 QString CustomPointPrivate::name() const {
225  return q->name();
226 }
227 
228 /*!
229  calculates the position and the bounding box of the item/point. Called on geometry or properties changes.
230  */
233  return;
234 
235  //calculate the point in the scene coordinates
236  const auto* cSystem = dynamic_cast<const CartesianCoordinateSystem*>(plot->coordinateSystem());
237  QVector<QPointF> listScene = cSystem->mapLogicalToScene(QVector<QPointF>{position});
238  if (!listScene.isEmpty()) {
239  m_visible = true;
240  positionScene = listScene.at(0);
242  setPos(positionScene);
243  suppressItemChangeEvent = false;
244  } else
245  m_visible = false;
246 
248 }
249 
251  bool oldValue = isVisible();
252 
253  //When making a graphics item invisible, it gets deselected in the scene.
254  //In this case we don't want to deselect the item in the project explorer.
255  //We need to supress the deselection in the view.
256  auto* worksheet = static_cast<Worksheet*>(q->parent(AspectType::Worksheet));
257  worksheet->suppressSelectionChangedEvent(true);
258  setVisible(on);
259  worksheet->suppressSelectionChangedEvent(false);
260 
261  emit q->changed();
262  emit q->visibleChanged(on);
263  return oldValue;
264 }
265 
266 /*!
267  Returns the outer bounds of the item as a rectangle.
268  */
271 }
272 
273 /*!
274  Returns the shape of this item as a QPainterPath in local coordinates.
275 */
276 QPainterPath CustomPointPrivate::shape() const {
277  return pointShape;
278 }
279 
280 /*!
281  recalculates the outer bounds and the shape of the item.
282 */
284  prepareGeometryChange();
285 
286  pointShape = QPainterPath();
288  QPainterPath path = Symbol::pathFromStyle(symbolStyle);
289 
290  QTransform trafo;
291  trafo.scale(symbolSize, symbolSize);
292  path = trafo.map(path);
293  trafo.reset();
294 
295  if (symbolRotationAngle != 0) {
296  trafo.rotate(symbolRotationAngle);
297  path = trafo.map(path);
298  }
299 
300  pointShape.addPath(WorksheetElement::shapeFromPath(trafo.map(path), symbolPen));
301  transformedBoundingRectangle = pointShape.boundingRect();
302  }
303 }
304 
305 void CustomPointPrivate::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) {
306  Q_UNUSED(option)
307  Q_UNUSED(widget)
308 
309  if (!m_visible)
310  return;
311 
313  painter->setOpacity(symbolOpacity);
314  painter->setPen(symbolPen);
315  painter->setBrush(symbolBrush);
316  painter->drawPath(pointShape);
317  }
318 
319  if (m_hovered && !isSelected() && !m_printing) {
320  painter->setPen(QPen(QApplication::palette().color(QPalette::Shadow), 2, Qt::SolidLine));
321  painter->drawPath(pointShape);
322  }
323 
324  if (isSelected() && !m_printing) {
325  painter->setPen(QPen(QApplication::palette().color(QPalette::Highlight), 2, Qt::SolidLine));
326  painter->drawPath(pointShape);
327  }
328 }
329 
330 QVariant CustomPointPrivate::itemChange(GraphicsItemChange change, const QVariant &value) {
332  return value;
333 
334  if (change == QGraphicsItem::ItemPositionChange) {
335  //emit the signals in order to notify the UI.
336  //we don't set the position related member variables during the mouse movements.
337  //this is done on mouse release events only.
338  const auto* cSystem = dynamic_cast<const CartesianCoordinateSystem*>(plot->coordinateSystem());
339  emit q->positionChanged(cSystem->mapSceneToLogical(value.toPointF()));
340  }
341 
342  return QGraphicsItem::itemChange(change, value);
343 }
344 
345 void CustomPointPrivate::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) {
346  //position was changed -> set the position member variables
347  suppressRetransform = true;
348  const auto* cSystem = dynamic_cast<const CartesianCoordinateSystem*>(plot->coordinateSystem());
349  q->setPosition(cSystem->mapSceneToLogical(pos()));
350  suppressRetransform = false;
351 
352  QGraphicsItem::mouseReleaseEvent(event);
353 }
354 
355 void CustomPointPrivate::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) {
356  q->createContextMenu()->exec(event->screenPos());
357 }
358 
359 void CustomPointPrivate::hoverEnterEvent(QGraphicsSceneHoverEvent*) {
360  if (!isSelected()) {
361  m_hovered = true;
362  emit q->hovered();
363  update();
364  }
365 }
366 
367 void CustomPointPrivate::hoverLeaveEvent(QGraphicsSceneHoverEvent*) {
368  if (m_hovered) {
369  m_hovered = false;
370  emit q->unhovered();
371  update();
372  }
373 }
374 
375 //##############################################################################
376 //################## Serialization/Deserialization ###########################
377 //##############################################################################
378 //! Save as XML
379 void CustomPoint::save(QXmlStreamWriter* writer) const {
380  Q_D(const CustomPoint);
381 
382  writer->writeStartElement("customPoint");
383  writeBasicAttributes(writer);
384  writeCommentElement(writer);
385 
386  //geometry
387  writer->writeStartElement("geometry");
388  writer->writeAttribute( "x", QString::number(d->position.x()) );
389  writer->writeAttribute( "y", QString::number(d->position.y()) );
390  writer->writeAttribute( "visible", QString::number(d->isVisible()) );
391  writer->writeEndElement();
392 
393  //Symbols
394  writer->writeStartElement("symbol");
395  writer->writeAttribute( "symbolStyle", QString::number(static_cast<int>(d->symbolStyle)) );
396  writer->writeAttribute( "opacity", QString::number(d->symbolOpacity) );
397  writer->writeAttribute( "rotation", QString::number(d->symbolRotationAngle) );
398  writer->writeAttribute( "size", QString::number(d->symbolSize) );
399  WRITE_QBRUSH(d->symbolBrush);
400  WRITE_QPEN(d->symbolPen);
401  writer->writeEndElement();
402 
403  writer->writeEndElement(); // close "CustomPoint" section
404 }
405 
406 //! Load from XML
407 bool CustomPoint::load(XmlStreamReader* reader, bool preview) {
408  Q_D(CustomPoint);
409 
410  if (!readBasicAttributes(reader))
411  return false;
412 
413  KLocalizedString attributeWarning = ki18n("Attribute '%1' missing or empty, default value is used");
414  QXmlStreamAttributes attribs;
415  QString str;
416 
417  while (!reader->atEnd()) {
418  reader->readNext();
419  if (reader->isEndElement() && reader->name() == "customPoint")
420  break;
421 
422  if (!reader->isStartElement())
423  continue;
424 
425  if (!preview && reader->name() == "comment") {
426  if (!readCommentElement(reader)) return false;
427  } else if (!preview && reader->name() == "geometry") {
428  attribs = reader->attributes();
429 
430  str = attribs.value("x").toString();
431  if (str.isEmpty())
432  reader->raiseWarning(attributeWarning.subs("x").toString());
433  else
434  d->position.setX(str.toDouble());
435 
436  str = attribs.value("y").toString();
437  if (str.isEmpty())
438  reader->raiseWarning(attributeWarning.subs("y").toString());
439  else
440  d->position.setY(str.toDouble());
441 
442  str = attribs.value("visible").toString();
443  if (str.isEmpty())
444  reader->raiseWarning(attributeWarning.subs("visible").toString());
445  else
446  d->setVisible(str.toInt());
447  } else if (!preview && reader->name() == "symbol") {
448  attribs = reader->attributes();
449 
450  READ_INT_VALUE("symbolStyle", symbolStyle, Symbol::Style);
451  READ_DOUBLE_VALUE("opacity", symbolOpacity);
452  READ_DOUBLE_VALUE("rotation", symbolRotationAngle);
453  READ_DOUBLE_VALUE("size", symbolSize);
454  READ_QBRUSH(d->symbolBrush);
455  READ_QPEN(d->symbolPen);
456  } else { // unknown element
457  reader->raiseWarning(i18n("unknown element '%1'", reader->name().toString()));
458  if (!reader->skipToEndElement()) return false;
459  }
460  }
461 
462  retransform();
463  return true;
464 }
AspectType
STD_SWAP_METHOD_SETTER_CMD_IMPL_F(CustomPoint, SetVisible, bool, swapVisible, update)
static const QRgb black
Definition: ImageEditor.cpp:38
bool readCommentElement(XmlStreamReader *)
Load comment from an XML element.
AbstractAspect * parent(AspectType type) const
In the parent-child hierarchy, return the first parent of type.
QString name() const
void writeBasicAttributes(QXmlStreamWriter *) const
Save name and creation time to XML.
void exec(QUndoCommand *)
Execute the given command, pushing it on the undoStack() if available.
bool readBasicAttributes(XmlStreamReader *)
Load name and creation time from XML.
void writeCommentElement(QXmlStreamWriter *) const
Save the comment to XML.
AbstractAspectPrivate * d
AbstractCoordinateSystem * coordinateSystem() const
Cartesian coordinate system for plots.
A xy-plot.
Definition: CartesianPlot.h:58
void contextMenuEvent(QGraphicsSceneContextMenuEvent *) override
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *widget=nullptr) override
void hoverLeaveEvent(QGraphicsSceneHoverEvent *) override
Symbol::Style symbolStyle
virtual void recalcShapeAndBoundingRect()
CustomPointPrivate(CustomPoint *, const CartesianPlot *)
bool swapVisible(bool)
const CartesianPlot * plot
QRectF boundingRect() const override
void mouseReleaseEvent(QGraphicsSceneMouseEvent *) override
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override
void hoverEnterEvent(QGraphicsSceneHoverEvent *) override
CustomPoint *const q
QPainterPath shape() const override
QString name() const
A customizable point.
Definition: CustomPoint.h:41
CustomPoint(const CartesianPlot *, const QString &)
Definition: CustomPoint.cpp:53
void setVisible(bool on) override
Show/hide the element.
void save(QXmlStreamWriter *) const override
Save as XML.
QAction * visibilityAction
Definition: CustomPoint.h:84
void setPrinting(bool) override
Switches the printing mode on/off.
friend class CustomPointSetPositionCmd
Definition: CustomPoint.h:87
void visibleChanged(bool)
QIcon icon() const override
void handleResize(double horizontalRatio, double verticalRatio, bool pageResize) override
void visibilityChanged()
void changed()
void positionChanged(const QPointF &)
QGraphicsItem * graphicsItem() const override
Return the graphics item representing this element.
QMenu * createContextMenu() override
Return a new context menu.
bool load(XmlStreamReader *, bool preview) override
Load from XML.
void retransform() override
Tell the element to newly transform its graphics item into its coordinate system.
void initActions()
Definition: CustomPoint.cpp:91
bool isVisible() const override
Return whether the element is (at least) partially visible.
CustomPointPrivate *const d_ptr
Definition: CustomPoint.h:76
~CustomPoint() override
static QPainterPath pathFromStyle(Symbol::Style)
Definition: Symbol.cpp:43
Style
Definition: Symbol.h:38
Base class for all Worksheet children.
static QPainterPath shapeFromPath(const QPainterPath &, const QPen &)
QMenu * createContextMenu() override
Return a new context menu.
Top-level container for worksheet elements like plot, labels, etc.
Definition: Worksheet.h:46
void suppressSelectionChangedEvent(bool)
Definition: Worksheet.cpp:408
static double convertToSceneUnits(const double value, const Worksheet::Unit unit)
Definition: Worksheet.cpp:113
XML stream parser that supports errors as well as warnings. This class also adds line and column numb...
void raiseWarning(const QString &)
#define READ_DOUBLE_VALUE(name, var)
Definition: macros.h:475
#define CLASS_SHARED_D_READER_IMPL(classname, type, method, var)
Definition: macros.h:154
#define STD_SETTER_CMD_IMPL_F_S(class_name, cmd_name, value_type, field_name, finalize_method)
Definition: macros.h:215
#define READ_INT_VALUE(name, var, type)
Definition: macros.h:468
#define READ_QPEN(pen)
Definition: macros.h:324
#define WRITE_QPEN(pen)
Definition: macros.h:315
#define READ_QBRUSH(brush)
Definition: macros.h:418
#define BASIC_SHARED_D_READER_IMPL(classname, type, method, var)
Definition: macros.h:127
#define WRITE_QBRUSH(brush)
Definition: macros.h:410
@ Shadow
Definition: OriginObj.h:71
#define i18n(m)
Definition: nsl_common.h:38