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