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"