File indexing completed on 2024-04-28 04:32:23

0001 /*
0002  * SPDX-FileCopyrightText: 2008 Kare Sars <kare dot sars at iki dot fi>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005  */
0006 
0007 #include "selectionitem.h"
0008 #include <QGraphicsView>
0009 #include <QGraphicsScene>
0010 #include <QCursor>
0011 #include <QList>
0012 
0013 namespace KSaneIface
0014 {
0015 
0016 static const qreal selMargin = 4.0;
0017 static const QPointF boundMargin(selMargin, selMargin);
0018 static const qreal addRemMargin = 8.0;
0019 static const QPointF addRemMarginPoint(addRemMargin, addRemMargin);
0020 
0021 struct SelectionItem::Private {
0022     QPen       penDark;
0023     QPen       penLight;
0024     QPen       penAddRemFg;
0025     QRectF     rect;
0026     qreal      maxX;
0027     qreal      maxY;
0028     bool       hasMaxX;
0029     bool       hasMaxY;
0030     bool       hasMax;
0031     bool       isSaved;
0032     bool       showAddRem;
0033     qreal      invZoom;
0034     qreal      selMargin;
0035     QRectF     addRemRect;
0036     qreal      devicePixelRatio;
0037 
0038     bool       addButtonEnabled = true;
0039 };
0040 
0041 SelectionItem::SelectionItem(const QRectF &rect) : QGraphicsItem(), d(new Private)
0042 {
0043     d->hasMaxX = false;
0044     d->hasMaxY = false;
0045     d->hasMax = false;
0046     setRect(rect);
0047 
0048     d->penDark.setColor(Qt::black);
0049     d->penDark.setStyle(Qt::SolidLine);
0050     d->penDark.setWidth(0);
0051     d->penLight.setColor(Qt::white);
0052     d->penLight.setStyle(Qt::DashLine);
0053     d->penLight.setWidth(0);
0054 
0055     // FIXME We should probably use some standard KDE color here and not hard code it
0056     d->penAddRemFg.setColor(Qt::darkGreen);
0057     d->penAddRemFg.setStyle(Qt::SolidLine);
0058     d->penAddRemFg.setWidth(3);
0059 
0060     d->isSaved = false;
0061     d->showAddRem = false;
0062     d->invZoom = 1;
0063     d->selMargin = selMargin;
0064 
0065     d->addRemRect = QRectF(0, 0, 0, 0);
0066 
0067     d->devicePixelRatio = 1.0;
0068 }
0069 
0070 SelectionItem::~SelectionItem()
0071 {
0072     delete d;
0073 }
0074 
0075 void SelectionItem::saveZoom(qreal zoom)
0076 {
0077     if (zoom < 0.00001) {
0078         zoom = 0.00001;
0079     }
0080     d->invZoom = 1 / zoom;
0081 
0082     d->selMargin = selMargin * d->invZoom;
0083 
0084     qreal margin = addRemMargin * d->invZoom;
0085     QPointF pMargin = addRemMarginPoint * d->invZoom;
0086     d->addRemRect = QRectF(d->rect.center() / d->devicePixelRatio - pMargin, QSizeF(margin * 2.0, margin * 2.0));
0087     d->penAddRemFg.setWidthF(3.0 * d->invZoom);
0088 }
0089 
0090 void SelectionItem::setSaved(bool isSaved)
0091 {
0092     if (isSaved) {
0093         d->penDark.setColor(Qt::darkBlue);
0094         d->penLight.setColor(Qt::red);
0095         d->penAddRemFg.setColor(Qt::darkRed);
0096         d->isSaved = true;
0097     } else {
0098         d->penDark.setColor(Qt::black);
0099         d->penLight.setColor(Qt::white);
0100         d->penAddRemFg.setColor(Qt::darkGreen);
0101         d->isSaved = false;
0102     }
0103 }
0104 
0105 void SelectionItem::setMaxRight(qreal maxX)
0106 {
0107     d->maxX = maxX;
0108     d->hasMaxX = true;
0109     if (d->hasMaxY) {
0110         d->hasMax = true;
0111     }
0112 }
0113 
0114 void SelectionItem::setMaxBottom(qreal maxY)
0115 {
0116     d->maxY = maxY;
0117     d->hasMaxY = true;
0118     if (d->hasMaxX) {
0119         d->hasMax = true;
0120     }
0121 }
0122 
0123 SelectionItem::Intersects SelectionItem::intersects(const QPointF &point)
0124 {
0125     bool oldState = d->showAddRem;
0126     d->showAddRem = false;
0127 
0128     if ((point.x() < (d->rect.left() - d->selMargin)) ||
0129             (point.x() > (d->rect.right() + d->selMargin)) ||
0130             (point.y() < (d->rect.top() - d->selMargin)) ||
0131             (point.y() > (d->rect.bottom() + d->selMargin))) {
0132         if (oldState != d->showAddRem) {
0133             update();
0134         }
0135         return None;
0136     }
0137 
0138     if (point.x() < (d->rect.left() + d->selMargin)) {
0139         if (oldState != d->showAddRem) {
0140             update();
0141         }
0142         if (point.y() < (d->rect.top() + d->selMargin)) {
0143             return TopLeft;
0144         }
0145         if (point.y() > (d->rect.bottom() - d->selMargin)) {
0146             return BottomLeft;
0147         }
0148         return Left;
0149     }
0150 
0151     if (point.x() > (d->rect.right() - d->selMargin)) {
0152         if (oldState != d->showAddRem) {
0153             update();
0154         }
0155         if (point.y() < (d->rect.top() + d->selMargin)) {
0156             return TopRight;
0157         }
0158         if (point.y() > (d->rect.bottom() - d->selMargin)) {
0159             return BottomRight;
0160         }
0161         return Right;
0162     }
0163 
0164     if (point.y() < (d->rect.top() + d->selMargin)) {
0165         if (oldState != d->showAddRem) {
0166             update();
0167         }
0168         return Top;
0169     }
0170     if (point.y() > (d->rect.bottom() - d->selMargin)) {
0171         if (oldState != d->showAddRem) {
0172             update();
0173         }
0174         return Bottom;
0175     }
0176 
0177     d->showAddRem = d->addButtonEnabled;
0178     if (oldState != d->showAddRem) {
0179         update();
0180     }
0181 
0182     if (d->addButtonEnabled && d->addRemRect.contains(point / d->devicePixelRatio)) {
0183         return AddRemove;
0184     }
0185     return Move;
0186 }
0187 
0188 void SelectionItem::setRect(const QRectF &rect)
0189 {
0190     prepareGeometryChange();
0191     d->rect = rect;
0192     d->rect = d->rect.normalized();
0193     if (d->hasMax) {
0194         if (d->rect.top() < 0) {
0195             d->rect.setTop(0);
0196         }
0197         if (d->rect.left() < 0) {
0198             d->rect.setLeft(0);
0199         }
0200         if (d->rect.right() > d->maxX) {
0201             d->rect.setRight(d->maxX);
0202         }
0203         if (d->rect.bottom() > d->maxY) {
0204             d->rect.setBottom(d->maxY);
0205         }
0206     }
0207 
0208     // calculate the add/remove rectangle
0209     qreal margin = addRemMargin * d->invZoom;
0210     QPointF pMargin = addRemMarginPoint * d->invZoom;
0211     d->addRemRect = QRectF(d->rect.center() / d->devicePixelRatio - pMargin, QSizeF(margin * 2, margin * 2));
0212 }
0213 
0214 QPointF SelectionItem::fixTranslation(QPointF dp)
0215 {
0216     if ((d->rect.left()   + dp.x()) < 0) {
0217         dp.setX(-d->rect.left());
0218     }
0219     if ((d->rect.top()    + dp.y()) < 0) {
0220         dp.setY(-d->rect.top());
0221     }
0222     if ((d->rect.right()  + dp.x()) > d->maxX) {
0223         dp.setX(d->maxX - d->rect.right());
0224     }
0225     if ((d->rect.bottom() + dp.y()) > d->maxY) {
0226         dp.setY(d->maxY - d->rect.bottom());
0227     }
0228     return dp;
0229 }
0230 
0231 QRectF SelectionItem::rect()
0232 {
0233     return d->rect;
0234 }
0235 
0236 qreal SelectionItem::devicePixelRatio() const
0237 {
0238     return d->devicePixelRatio;
0239 }
0240 
0241 void SelectionItem::setDevicePixelRatio(qreal dpr)
0242 {
0243     d->devicePixelRatio = dpr;
0244 }
0245 
0246 QRectF SelectionItem::boundingRect() const
0247 {
0248     const auto dpr = d->devicePixelRatio;
0249     QRectF tmp(d->rect.topLeft() / dpr - boundMargin, d->rect.bottomRight() / dpr + boundMargin);
0250     return tmp.united(d->addRemRect);
0251 }
0252 
0253 void SelectionItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
0254 {
0255     const auto dpr = d->devicePixelRatio;
0256     QRectF rect(d->rect.topLeft() / dpr, d->rect.size() / dpr);
0257 
0258     painter->setPen(d->penDark);
0259     painter->drawRect(rect);
0260 
0261     painter->setPen(d->penLight);
0262     painter->drawRect(rect);
0263 
0264     if (d->showAddRem) {
0265         painter->fillRect(d->addRemRect, QBrush(Qt::white));
0266         QLineF minus(d->addRemRect.left() + 3 * d->invZoom, d->addRemRect.center().y(),
0267                      d->addRemRect.right() - 3 * d->invZoom, d->addRemRect.center().y());
0268         painter->setPen(d->penAddRemFg);
0269 
0270         painter->drawLine(minus);
0271 
0272         if (!d->isSaved) {
0273             QLineF plus(d->addRemRect.center().x(), d->addRemRect.top() + 3 * d->invZoom,
0274                         d->addRemRect.center().x(), d->addRemRect.bottom() - 3 * d->invZoom);
0275             painter->drawLine(plus);
0276         }
0277     }
0278 }
0279 
0280 void SelectionItem::setAddButtonEnabled(bool enabled)
0281 {
0282     d->addButtonEnabled = enabled;
0283 }
0284 
0285 
0286 }  // NameSpace KSaneIface