File indexing completed on 2025-02-02 04:26:11

0001 /* SPDX-FileCopyrightText: 2022 Noah Davis <noahadvs@gmail.com>
0002  * SPDX-License-Identifier: LGPL-2.0-or-later
0003  */
0004 
0005 #include "Selection.h"
0006 #include "SelectionEditor.h"
0007 #include "Geometry.h"
0008 
0009 #include <QQuickItem>
0010 #include <QtMath>
0011 
0012 using G = Geometry;
0013 
0014 Selection::Selection(SelectionEditor *editor)
0015     : QObject(editor)
0016     , editor(editor)
0017 {
0018 }
0019 
0020 qreal Selection::x() const
0021 {
0022     return selection.x();
0023 }
0024 
0025 void Selection::setX(qreal x)
0026 {
0027     QRectF newRect = selection;
0028     // QRectF::setX is the same as QRectF::setLeft
0029     newRect.moveLeft(x);
0030     setRect(newRect, Qt::Horizontal);
0031 }
0032 
0033 qreal Selection::y() const
0034 {
0035     return selection.y();
0036 }
0037 
0038 void Selection::setY(qreal y)
0039 {
0040     QRectF newRect = selection;
0041     // QRectF::setY is the same as QRectF::setTop
0042     newRect.moveTop(y);
0043     setRect(newRect, Qt::Vertical);
0044 }
0045 
0046 qreal Selection::width() const
0047 {
0048     return selection.width();
0049 }
0050 
0051 void Selection::setWidth(qreal w)
0052 {
0053     QRectF newRect = selection;
0054     newRect.setWidth(w);
0055     setRect(newRect.normalized(), Qt::Horizontal);
0056 }
0057 
0058 qreal Selection::height() const
0059 {
0060     return selection.height();
0061 }
0062 
0063 void Selection::setHeight(qreal h)
0064 {
0065     QRectF newRect = selection;
0066     newRect.setHeight(h);
0067     setRect(newRect.normalized(), Qt::Vertical);
0068 }
0069 
0070 qreal Selection::left() const
0071 {
0072     return selection.left();
0073 }
0074 
0075 void Selection::setLeft(qreal l)
0076 {
0077     QRectF newRect = selection;
0078     newRect.setLeft(l);
0079     setRect(newRect.normalized(), Qt::Horizontal);
0080 }
0081 
0082 qreal Selection::top() const
0083 {
0084     return selection.top();
0085 }
0086 
0087 void Selection::setTop(qreal t)
0088 {
0089     QRectF newRect = selection;
0090     newRect.setTop(t);
0091     setRect(newRect.normalized(), Qt::Vertical);
0092 }
0093 
0094 qreal Selection::right() const
0095 {
0096     return selection.right();
0097 }
0098 
0099 void Selection::setRight(qreal r)
0100 {
0101     QRectF newRect = selection;
0102     newRect.setRight(r);
0103     setRect(newRect.normalized(), Qt::Horizontal);
0104 }
0105 
0106 qreal Selection::bottom() const
0107 {
0108     return selection.bottom();
0109 }
0110 
0111 void Selection::setBottom(qreal b)
0112 {
0113     QRectF newRect = selection;
0114     newRect.setBottom(b);
0115     setRect(newRect.normalized(), Qt::Vertical);
0116 }
0117 
0118 qreal Selection::horizontalCenter() const
0119 {
0120     return selection.x() + selection.width() / 2.0;
0121 }
0122 
0123 void Selection::setHorizontalCenter(qreal hc)
0124 {
0125     qreal x = hc - selection.width() / 2.0;
0126     if (x == selection.x()) {
0127         return;
0128     }
0129     setX(x);
0130 }
0131 
0132 qreal Selection::verticalCenter() const
0133 {
0134     return selection.y() + selection.height() / 2.0;
0135 }
0136 
0137 void Selection::setVerticalCenter(qreal vc)
0138 {
0139     qreal y = vc - selection.height() / 2.0;
0140     if (y == selection.y()) {
0141         return;
0142     }
0143     setY(y);
0144 }
0145 
0146 void Selection::moveTo(qreal x, qreal y)
0147 {
0148     QRectF newRect = selection;
0149     newRect.moveTo(x, y);
0150     setRect(newRect, Qt::Horizontal | Qt::Vertical);
0151 }
0152 
0153 void Selection::moveTo(const QPointF &p)
0154 {
0155     QRectF newRect = selection;
0156     newRect.moveTo(p);
0157     setRect(newRect, Qt::Horizontal | Qt::Vertical);
0158 }
0159 
0160 void Selection::setRect(const QRectF &r)
0161 {
0162     setRect(r.normalized(), Qt::Horizontal | Qt::Vertical);
0163 }
0164 
0165 void Selection::setRect(qreal x, qreal y, qreal w, qreal h)
0166 {
0167     setRect(QRectF(x, y, w, h));
0168 }
0169 
0170 void Selection::setRect(const QRectF &newRect, Qt::Orientations orientations)
0171 {
0172     const QRectF oldRect = selection;
0173     const auto &bounds = editor->screensRect();
0174     selection = G::rectClipped(newRect, bounds, orientations);
0175     // Using this instead of just comparing rects to take advantage
0176     // of the qFuzzyCompare calculations we're doing anyway.
0177     bool rectChange = false;
0178     bool sizeChange = false;
0179     // Keeping track of which things change without unnecessarily
0180     // sending signals or sending signals more than once is tough.
0181     if (orientations & Qt::Horizontal) {
0182         if (!qFuzzyCompare(oldRect.x(), selection.x())) {
0183             rectChange = true;
0184             Q_EMIT xChanged();
0185         }
0186         qreal oldHC = oldRect.x() + oldRect.width() / 2.0;
0187         qreal newHC = selection.x() + selection.width() / 2.0;
0188         if (!qFuzzyCompare(oldHC, newHC)) {
0189             rectChange = true;
0190             Q_EMIT horizontalCenterChanged();
0191         }
0192         if (!qFuzzyCompare(oldRect.width(), selection.width())) {
0193             rectChange = true;
0194             sizeChange = true;
0195             Q_EMIT widthChanged();
0196         }
0197         if (!qFuzzyCompare(oldRect.left(), selection.left())) {
0198             rectChange = true;
0199             Q_EMIT leftChanged();
0200         }
0201         if (!qFuzzyCompare(oldRect.right(), selection.right())) {
0202             rectChange = true;
0203             Q_EMIT rightChanged();
0204         }
0205     }
0206     if (orientations & Qt::Vertical) {
0207         if (!qFuzzyCompare(oldRect.y(), selection.y())) {
0208             rectChange = true;
0209             Q_EMIT yChanged();
0210         }
0211         qreal oldVC = oldRect.y() + oldRect.height() / 2.0;
0212         qreal newVC = selection.y() + selection.height() / 2.0;
0213         if (!qFuzzyCompare(oldVC, newVC)) {
0214             rectChange = true;
0215             Q_EMIT verticalCenterChanged();
0216         }
0217         if (!qFuzzyCompare(oldRect.height(), selection.height())) {
0218             rectChange = true;
0219             sizeChange = true;
0220             Q_EMIT heightChanged();
0221         }
0222         if (!qFuzzyCompare(oldRect.top(), selection.top())) {
0223             rectChange = true;
0224             Q_EMIT topChanged();
0225         }
0226         if (!qFuzzyCompare(oldRect.bottom(), selection.bottom())) {
0227             rectChange = true;
0228             Q_EMIT bottomChanged();
0229         }
0230     }
0231     if (rectChange) {
0232         Q_EMIT rectChanged();
0233     }
0234     if (sizeChange) {
0235         Q_EMIT sizeChanged();
0236     }
0237     if (oldRect.isEmpty() != selection.isEmpty()) {
0238         Q_EMIT emptyChanged();
0239     }
0240 }
0241 
0242 QRectF Selection::rectF() const
0243 {
0244     return selection;
0245 }
0246 
0247 QSizeF Selection::sizeF() const
0248 {
0249     return selection.size();
0250 }
0251 
0252 QRectF Selection::normalized() const
0253 {
0254     return selection.normalized();
0255 }
0256 
0257 bool Selection::isEmpty() const
0258 {
0259     return selection.isEmpty();
0260 }
0261 
0262 bool Selection::contains(const QPointF &p) const
0263 {
0264     return selection.contains(p);
0265 }
0266 
0267 QDebug operator<<(QDebug debug, const Selection *selection)
0268 {
0269     QDebugStateSaver stateSaver(debug);
0270     debug.nospace();
0271     debug << selection->metaObject()->className() << '(';
0272     debug << selection->x() << ',' << selection->y() << ' '
0273           << selection->width() << 'x' << selection->height();
0274     const auto editor = qobject_cast<const SelectionEditor *>(selection->parent());
0275     qreal dpr = editor ? editor->devicePixelRatio() : 1;
0276     debug << " dpr=" << dpr;
0277     debug << ')';
0278     return debug;
0279 }
0280 
0281 #include "moc_Selection.cpp"