File indexing completed on 2024-05-12 03:47:30

0001 /*
0002     File                 : Segment.cpp
0003     Project              : LabPlot
0004     Description          : Graphics-item for curve of Datapicker
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2015 Ankit Wagadre <wagadre.ankit@gmail.com>
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 
0010 #include "Segment.h"
0011 #include "SegmentPrivate.h"
0012 #include "backend/datapicker/Datapicker.h"
0013 #include "backend/datapicker/DatapickerImage.h"
0014 #include "backend/datapicker/DatapickerPoint.h"
0015 #include "backend/worksheet/Worksheet.h"
0016 
0017 #include <QGraphicsScene>
0018 #include <QPainter>
0019 #include <QPalette>
0020 #include <QScreen>
0021 
0022 #include <KLocalizedString>
0023 
0024 /**
0025  * \class Segment
0026  * \brief graphics-item class for curve-segment
0027  */
0028 
0029 Segment::Segment(DatapickerImage* image)
0030     : m_image(image)
0031     , d_ptr(new SegmentPrivate(this)) {
0032     m_image->scene()->addItem(this->graphicsItem());
0033 }
0034 
0035 QGraphicsItem* Segment::graphicsItem() const {
0036     return d_ptr;
0037 }
0038 
0039 void Segment::setParentGraphicsItem(QGraphicsItem* item) {
0040     Q_D(Segment);
0041     d->setParentItem(item);
0042 }
0043 
0044 void Segment::retransform() {
0045     Q_D(Segment);
0046     d->retransform();
0047 }
0048 
0049 bool Segment::isVisible() const {
0050     Q_D(const Segment);
0051     return d->isVisible();
0052 }
0053 
0054 void Segment::setVisible(bool on) {
0055     Q_D(Segment);
0056     d->setVisible(on);
0057 }
0058 
0059 // ##############################################################################
0060 // ####################### Private implementation ###############################
0061 // ##############################################################################
0062 SegmentPrivate::SegmentPrivate(Segment* owner)
0063     : scaleFactor(Worksheet::convertToSceneUnits(1, Worksheet::Unit::Inch) / QApplication::primaryScreen()->physicalDotsPerInchX())
0064     , q(owner) {
0065     setFlag(QGraphicsItem::ItemIsSelectable);
0066     setFlag(QGraphicsItem::ItemSendsGeometryChanges);
0067     setAcceptHoverEvents(true);
0068     setVisible(false);
0069 
0070     pen = QPen(Qt::green, 3, Qt::SolidLine);
0071 }
0072 
0073 /*!
0074     calculates the position and the bounding box of the item. Called on geometry or properties changes.
0075  */
0076 void SegmentPrivate::retransform() {
0077     QTransform matrix;
0078     matrix.scale(scaleFactor, scaleFactor);
0079     for (auto* line : q->path) {
0080         const QLine& scaledLine = matrix.map(*line);
0081         linePath.moveTo(scaledLine.p1());
0082         linePath.lineTo(scaledLine.p2());
0083     }
0084     recalcShapeAndBoundingRect();
0085 }
0086 
0087 /*!
0088     Returns the outer bounds of the item as a rectangle.
0089  */
0090 QRectF SegmentPrivate::boundingRect() const {
0091     return boundingRectangle;
0092 }
0093 
0094 /*!
0095     Returns the shape of this item as a QPainterPath in local coordinates.
0096 */
0097 QPainterPath SegmentPrivate::shape() const {
0098     return itemShape;
0099 }
0100 
0101 /*!
0102   recalculates the outer bounds and the shape of the item.
0103 */
0104 void SegmentPrivate::recalcShapeAndBoundingRect() {
0105     prepareGeometryChange();
0106     boundingRectangle = linePath.boundingRect();
0107     itemShape = QPainterPath();
0108     itemShape.addRect(boundingRectangle);
0109 }
0110 
0111 void SegmentPrivate::paint(QPainter* painter, const QStyleOptionGraphicsItem* /*option*/, QWidget*) {
0112     painter->setPen(pen);
0113     painter->drawPath(linePath);
0114 
0115     if (m_hovered && !isSelected()) {
0116         painter->setPen(QPen(QApplication::palette().color(QPalette::Highlight), 2, Qt::SolidLine));
0117         painter->drawPath(linePath);
0118     }
0119 
0120     //  if (isSelected()) {
0121     //      painter->setPen(QPen(QApplication::palette().color(QPalette::Highlight), 2, Qt::SolidLine));
0122     //      painter->setOpacity(selectedOpacity);
0123     //      painter->drawPath(itemShape);
0124     //  }
0125 }
0126 
0127 void SegmentPrivate::hoverEnterEvent(QGraphicsSceneHoverEvent*) {
0128     if (!isSelected()) {
0129         m_hovered = true;
0130         update();
0131     }
0132 }
0133 
0134 void SegmentPrivate::hoverLeaveEvent(QGraphicsSceneHoverEvent*) {
0135     if (m_hovered) {
0136         m_hovered = false;
0137         update();
0138     }
0139 }
0140 
0141 QVariant SegmentPrivate::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant& value) {
0142     if (change == QGraphicsItem::ItemSelectedChange && value == true) {
0143         auto* datapicker = static_cast<Datapicker*>(q->m_image->parentAspect());
0144         if (datapicker->activeCurve()) {
0145             int count = 0;
0146             QList<QPointF> posList;
0147             posList.clear();
0148             for (QLine* line : q->path) {
0149                 const int l = (line->y1() > line->y2()) ? line->y2() : line->y1();
0150                 const int h = (line->y1() > line->y2()) ? line->y1() : line->y2();
0151 
0152                 for (int i = l; i <= h; ++i) {
0153                     if (count % q->m_image->pointSeparation() == 0) {
0154                         bool positionUsed = false;
0155                         const auto points = datapicker->activeCurve()->children<DatapickerPoint>(AbstractAspect::ChildIndexFlag::IncludeHidden);
0156                         for (const auto* point : points) {
0157                             if (point->position() == QPoint(line->x1(), i) * scaleFactor)
0158                                 positionUsed = true;
0159                         }
0160 
0161                         if (!positionUsed)
0162                             posList << QPoint(line->x1(), i) * scaleFactor;
0163                     }
0164                     count++;
0165                 }
0166             }
0167 
0168             if (!posList.isEmpty()) {
0169                 auto* curve = datapicker->activeCurve();
0170                 curve->beginMacro(i18n("%1: draw points over segment", datapicker->activeCurve()->name()));
0171                 curve->suppressUpdatePoint(true);
0172                 for (const QPointF& pos : posList)
0173                     datapicker->addNewPoint(pos, curve);
0174                 curve->suppressUpdatePoint(false);
0175                 curve->endMacro();
0176             }
0177         }
0178 
0179         // no need to keep segment selected
0180         return false;
0181     }
0182 
0183     return QGraphicsItem::itemChange(change, value);
0184 }