File indexing completed on 2024-05-12 08:34:14
0001 /* SPDX-FileCopyrightText: 2023 Noah Davis <noahadvs@gmail.com> 0002 * SPDX-License-Identifier: LGPL-2.0-or-later 0003 */ 0004 0005 #pragma once 0006 0007 #include <QObject> 0008 0009 #include <memory> 0010 0011 class QPointF; 0012 class QRectF; 0013 class QSizeF; 0014 0015 /** 0016 * This is a class for processing geometry. 0017 * 0018 * This class has functionality for converting between logical screen coordinates 0019 * and platform native screen coordinates. For Wayland, there is no difference. 0020 * 0021 * On X11, QScreen::geometry has the raw size (in hardware pixels) scaled down by 0022 * the device pixel ratio (DPR), but the position is still the screen's raw position. 0023 * 0024 * On Wayland, QScreen::geometry has the raw size scaled down by the DPR and 0025 * the position is also adjusted so that each QScreen::geometry matches the 0026 * layout used by the Wayland compositor (almost, see the next paragraph). 0027 * This kind of geometry is sometimes called "logical" geometry. 0028 * 0029 * QScreen::geometry is a QRect, which means some precision is lost when the 0030 * raw size is scale down. If QScreen::geometry is scaled back up, it may not 0031 * match the raw size, especially when fractional scale factors are used or the 0032 * resolution has an odd width/height. 0033 */ 0034 class Geometry : public QObject 0035 { 0036 Q_OBJECT 0037 public: 0038 static Geometry *instance(); 0039 0040 /** 0041 * This returns the logical size of a raw device pixel based on the given device pixel ratio. 0042 * This has a short name so that it doesn't make lines of code really long. 0043 */ 0044 [[nodiscard]] Q_INVOKABLE static qreal dpx(qreal dpr); 0045 0046 /** 0047 * This rounds a logical axis value to a value that should be aligned to hardware pixels 0048 * if the given device pixel ratio is correct. 0049 */ 0050 [[nodiscard]] Q_INVOKABLE static qreal dprRound(qreal value, qreal dpr); 0051 0052 /** 0053 * This converts an X11 screen axis value to a logical screen axis value. 0054 * Otherwise, it returns the value as it already was. 0055 */ 0056 [[nodiscard]] Q_INVOKABLE static qreal mapFromPlatformValue(qreal value, qreal dpr); 0057 0058 /** 0059 * This converts an X11 screen point to a logical screen point. 0060 * Otherwise, it returns the point as it already was. 0061 */ 0062 [[nodiscard]] Q_INVOKABLE static QPointF mapFromPlatformPoint(const QPointF &point, qreal dpr); 0063 0064 /** 0065 * This converts an X11 screen rect to a logical screen rect. 0066 * Otherwise, it returns the rect as it already was. 0067 */ 0068 [[nodiscard]] Q_INVOKABLE static QRectF mapFromPlatformRect(const QRectF &rect, qreal dpr); 0069 0070 /** 0071 * This returns the union of all logical screen rects. 0072 * 0073 * NOTE: Not perfectly accurate with some device pixel ratios 0074 * and resolutions due to QScreen::geometry being a QRect. 0075 */ 0076 [[nodiscard]] Q_INVOKABLE static QRectF logicalScreensRect(); 0077 0078 /** 0079 * This converts a logical screen axis value to a platform screen axis value. 0080 * On Wayland, it returns the value as it already was. 0081 */ 0082 [[nodiscard]] Q_INVOKABLE static qreal mapToPlatformValue(qreal value, qreal dpr); 0083 0084 /** 0085 * This converts a logical screen point to a platform screen point. 0086 * On Wayland, it returns the point as it already was. 0087 */ 0088 [[nodiscard]] Q_INVOKABLE static QPointF mapToPlatformPoint(const QPointF &point, qreal dpr); 0089 0090 /** 0091 * This converts a logical screen rect to a platform screen rect. 0092 * On Wayland, it returns the rect as it already was. 0093 */ 0094 [[nodiscard]] Q_INVOKABLE static QRectF mapToPlatformRect(const QRectF &rect, qreal dpr); 0095 0096 /** 0097 * This returns the union of all platform screen rects. 0098 * 0099 * NOTE: Not perfectly accurate with some device pixel ratios 0100 * and resolutions due to QScreen::geometry being a QRect. 0101 */ 0102 [[nodiscard]] Q_INVOKABLE static QRectF platformUnifiedRect(); 0103 0104 /** 0105 * This returns a raw size for a logical size by multiplying by the DPR. 0106 * NOTE: The value will only be correct if no precision was lost prior to running the function. 0107 */ 0108 [[nodiscard]] Q_INVOKABLE static QSize rawSize(const QSizeF &size, qreal dpr); 0109 0110 /// Get the rectangle with adjusted left, top, right and bottom sides. 0111 [[nodiscard]] Q_INVOKABLE static QRectF rectAdjusted(const QRectF &rect, qreal xp1, qreal yp1, qreal xp2, qreal yp2); 0112 0113 /** 0114 * Get the rectangle with adjusted left, top, right and bottom sides. 0115 * This affects the sides of invalid rectangles as if they were normalized. 0116 * If the rect is invalid, that will be preserved. 0117 */ 0118 [[nodiscard]] Q_INVOKABLE static QRectF rectAdjustedVisually(const QRectF &rect, qreal xp1, qreal yp1, qreal xp2, qreal yp2); 0119 0120 /// Get a rect with a size and position multiplied by the scale. 0121 [[nodiscard]] Q_INVOKABLE static QRectF rectScaled(const QRectF &rect, qreal scale); 0122 0123 /// Get the intersection of two rectangles. 0124 [[nodiscard]] Q_INVOKABLE static QRectF rectIntersected(const QRectF &rect1, const QRectF &rect2); 0125 0126 /** 0127 * Try to make the rect positioned fully inside boundsRect without clipping on the given axes. 0128 * The rect may still be out of bounds if the size is too large. 0129 * If the rect is invalid, that will be preserved. 0130 */ 0131 [[nodiscard]] Q_INVOKABLE static QRectF rectBounded(const QRectF &rect, const QRectF &boundsRect, // 0132 Qt::Orientations orientations = Qt::Horizontal | Qt::Vertical); 0133 [[nodiscard]] Q_INVOKABLE static QRectF rectBounded(qreal x, qreal y, qreal width, qreal height, const QRectF &boundsRect, // 0134 Qt::Orientations orientations = Qt::Horizontal | Qt::Vertical); 0135 0136 /** 0137 * Clip the rect to the clipRect on the given axes. 0138 * If the rect does not intersect with the clipRect, 0139 * it will become an empty rect on the edge of clipRect nearest to the original position. 0140 * If the rect is invalid, that will be preserved. 0141 */ 0142 [[nodiscard]] Q_INVOKABLE static QRectF rectClipped(const QRectF &rect, const QRectF &clipRect, // 0143 Qt::Orientations orientations = Qt::Horizontal | Qt::Vertical); 0144 0145 /// Check if the rectangle contains the value on the given axes. 0146 [[nodiscard]] Q_INVOKABLE static bool rectContains(const QRectF &rect, qreal v, // 0147 Qt::Orientations orientations = Qt::Horizontal | Qt::Vertical); 0148 /// Check if the rectangle contains the point. 0149 [[nodiscard]] Q_INVOKABLE static bool rectContains(const QRectF &rect, qreal x, qreal y); 0150 [[nodiscard]] Q_INVOKABLE static bool rectContains(const QRectF &rect, const QPointF& point); 0151 /// Check if the first rectangle contains the second rectangle. 0152 [[nodiscard]] Q_INVOKABLE static bool rectContains(const QRectF &rect1, const QRectF& rect2); 0153 [[nodiscard]] Q_INVOKABLE static bool rectContains(const QRectF &rect, qreal x, qreal y, qreal w, qreal h); 0154 0155 /// Check if the ellipse contains the point. 0156 [[nodiscard]] Q_INVOKABLE static bool ellipseContains(qreal ellipseX, qreal ellipseY, 0157 qreal ellipseWidth, qreal ellipseHeight, 0158 qreal x, qreal y); 0159 /// Assuming the rectangle represents an ellipse's bounding box, check if it contains the point. 0160 [[nodiscard]] Q_INVOKABLE static bool ellipseContains(const QRectF &rect, qreal x, qreal y); 0161 [[nodiscard]] Q_INVOKABLE static bool ellipseContains(const QRectF &rect, const QPointF &point); 0162 0163 /// Check if two rectangles intersect. 0164 [[nodiscard]] Q_INVOKABLE static bool rectIntersects(const QRectF &rect1, const QRectF& rect2); 0165 [[nodiscard]] Q_INVOKABLE static bool rectIntersects(const QRectF &rect, qreal x, qreal y, qreal w, qreal h); 0166 0167 /// Is width or height less than or equal to 0 0168 [[nodiscard]] Q_INVOKABLE static bool isEmpty(qreal w, qreal h); 0169 [[nodiscard]] Q_INVOKABLE static bool isEmpty(const QSizeF &size); 0170 [[nodiscard]] Q_INVOKABLE static bool isEmpty(const QRectF &rect); 0171 0172 /// Are width and height equal to 0 0173 [[nodiscard]] Q_INVOKABLE static bool isNull(qreal w, qreal h); 0174 [[nodiscard]] Q_INVOKABLE static bool isNull(const QSizeF &size); 0175 [[nodiscard]] Q_INVOKABLE static bool isNull(const QRectF &rect); 0176 0177 private: 0178 explicit Geometry(QObject *parent = nullptr); 0179 Geometry(const Geometry &) = delete; 0180 Geometry(Geometry &&) = delete; 0181 Geometry &operator=(const Geometry &) = delete; 0182 Geometry &operator=(Geometry &&) = delete; 0183 friend class GeometrySingleton; 0184 };