on xenial help sign in
Cursor: make its size grid unit based

So that it scales along with the rest of the UI (LP: #1604014) Approved by: Albert Astals Cid, Unity8 CI Bot

commit280e594bb9c3db29b45b8a0ba60b519285c5635b authorDaniel d'Andrada <daniel.dandrada@canonical.com> dateWed 3 Aug 2016, 15:52 (10 years ago) parent92093d8f5cb9e2
7 files changed+88−31
plugins/Cursor/Cursor.qml+5−2 plugins/Cursor/CursorImageInfo.cpp+21−1 plugins/Cursor/CursorImageInfo.h+10 plugins/Cursor/CursorImageProvider.cpp+33−21 plugins/Cursor/CursorImageProvider.h+9−6 qml/Shell.qml+2 tests/plugins/Cursor/tst_Cursor.qml+8−1
plugins/Cursor/Cursor.qml+5−2
@@ -25,6 +25,7 @@ MousePointer {
2525 id: imageInfo
2626 themeName: mousePointer.themeName
2727 cursorName: mousePointer.cursorName
28+ cursorHeight: mousePointer.height
2829 }
2930
3031 Loader {
@@ -32,7 +33,7 @@ MousePointer {
3233 sourceComponent: AnimatedSprite {
3334 x: -imageInfo.hotspot.x
3435 y: -imageInfo.hotspot.y
35− source: "image://cursor/" + mousePointer.themeName + "/" + mousePointer.cursorName
36+ source: imageInfo.imageSource
3637
3738 interpolate: false
3839
@@ -53,7 +54,9 @@ MousePointer {
5354 sourceComponent: Image {
5455 x: -imageInfo.hotspot.x
5556 y: -imageInfo.hotspot.y
56− source: "image://cursor/" + mousePointer.themeName + "/" + mousePointer.cursorName
57+ source: imageInfo.imageSource
58+ width: sourceSize.width
59+ height: sourceSize.height
5760 }
5861 }
5962}
plugins/Cursor/CursorImageInfo.cpp+21−1
@@ -28,6 +28,15 @@ void CursorImageInfo::setCursorName(const QString &cursorName)
2828 update();
2929 Q_EMIT cursorNameChanged();
3030 }
31+
32+}
33+void CursorImageInfo::setCursorHeight(qreal cursorHeight)
34+{
35+ if (cursorHeight != m_cursorHeight) {
36+ m_cursorHeight = cursorHeight;
37+ update();
38+ Q_EMIT cursorHeightChanged();
39+ }
3140}
3241
3342void CursorImageInfo::setThemeName(const QString &themeName)
@@ -41,13 +50,14 @@ void CursorImageInfo::setThemeName(const QString &themeName)
4150
4251void CursorImageInfo::update()
4352{
44− m_cursorImage = CursorImageProvider::instance()->fetchCursor(m_themeName, m_cursorName);
53+ m_cursorImage = CursorImageProvider::instance()->fetchCursor(m_themeName, m_cursorName, (int) m_cursorHeight);
4554
4655 Q_EMIT hotspotChanged();
4756 Q_EMIT frameWidthChanged();
4857 Q_EMIT frameHeightChanged();
4958 Q_EMIT frameCountChanged();
5059 Q_EMIT frameDurationChanged();
60+ Q_EMIT imageSourceChanged();
5161}
5262
5363QPoint CursorImageInfo::hotspot() const
@@ -94,3 +104,13 @@ int CursorImageInfo::frameDuration() const
94104 return 0;
95105 }
96106}
107+
108+QUrl CursorImageInfo::imageSource() const
109+{
110+ auto urlString = QString("image://cursor/%1/%2/%3")
111+ .arg(m_themeName)
112+ .arg(m_cursorName)
113+ .arg(m_cursorHeight);
114+
115+ return QUrl(urlString);
116+}
plugins/Cursor/CursorImageInfo.h+10
@@ -21,6 +21,7 @@
2121
2222#include <QObject>
2323#include <QString>
24+#include <QUrl>
2425
2526class CursorImageInfo : public QObject
2627{
@@ -28,12 +29,14 @@ class CursorImageInfo : public QObject
2829
2930 Q_PROPERTY(QString themeName READ themeName WRITE setThemeName NOTIFY themeNameChanged)
3031 Q_PROPERTY(QString cursorName READ cursorName WRITE setCursorName NOTIFY cursorNameChanged)
32+ Q_PROPERTY(qreal cursorHeight READ cursorHeight WRITE setCursorHeight NOTIFY cursorHeightChanged)
3133
3234 Q_PROPERTY(QPoint hotspot READ hotspot NOTIFY hotspotChanged)
3335 Q_PROPERTY(qreal frameWidth READ frameWidth NOTIFY frameWidthChanged)
3436 Q_PROPERTY(qreal frameHeight READ frameHeight NOTIFY frameHeightChanged)
3537 Q_PROPERTY(int frameCount READ frameCount NOTIFY frameCountChanged)
3638 Q_PROPERTY(int frameDuration READ frameDuration NOTIFY frameDurationChanged)
39+ Q_PROPERTY(QUrl imageSource READ imageSource NOTIFY imageSourceChanged)
3740
3841public:
3942 CursorImageInfo(QObject *parent = nullptr);
@@ -44,20 +47,26 @@ public:
4447 QString cursorName() const { return m_cursorName; }
4548 void setCursorName(const QString &);
4649
50+ qreal cursorHeight() const { return m_cursorHeight; }
51+ void setCursorHeight(qreal);
52+
4753 QPoint hotspot() const;
4854 qreal frameWidth() const;
4955 qreal frameHeight() const;
5056 int frameCount() const;
5157 int frameDuration() const;
58+ QUrl imageSource() const;
5259
5360Q_SIGNALS:
5461 void themeNameChanged();
5562 void cursorNameChanged();
63+ void cursorHeightChanged();
5664 void hotspotChanged();
5765 void frameWidthChanged();
5866 void frameHeightChanged();
5967 void frameCountChanged();
6068 void frameDurationChanged();
69+ void imageSourceChanged();
6170
6271private Q_SLOTS:
6372 void update();
@@ -65,6 +74,7 @@ private Q_SLOTS:
6574private:
6675 QString m_themeName;
6776 QString m_cursorName;
77+ qreal m_cursorHeight{0};
6878
6979 CursorImage *m_cursorImage{nullptr};
7080};
plugins/Cursor/CursorImageProvider.cpp+33−21
@@ -27,7 +27,7 @@ CursorImageProvider *CursorImageProvider::m_instance = nullptr;
2727/////
2828// BuiltInCursorImage
2929
30−BuiltInCursorImage::BuiltInCursorImage()
30+BuiltInCursorImage::BuiltInCursorImage(int cursorHeight)
3131{
3232 const char *svgString =
3333 "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>"
@@ -42,12 +42,14 @@ BuiltInCursorImage::BuiltInCursorImage()
4242 " d=\"M 20.504,50.94931 460.42533,518.14486 266.47603,515.61948 366.48114,719.16522 274.05218,770.68296 172.53185,559.56112 20.504,716.13476 Z\" />"
4343 "</svg>";
4444
45− qimage = QImage(20, 32, QImage::Format_ARGB32);
45+ // NB: Original image dimension is 20x32. Ensure aspect ratio is kept
46+ qimage = QImage((20./32.)*cursorHeight, cursorHeight, QImage::Format_ARGB32);
4647 qimage.fill(Qt::transparent);
4748 QPainter imagePainter(&qimage);
4849
4950 frameWidth = qimage.width();
5051 frameHeight = qimage.height();
52+ requestedHeight = cursorHeight;
5153
5254 QSvgRenderer *svgRenderer = new QSvgRenderer(QByteArray(svgString));
5355 svgRenderer->render(&imagePainter);
@@ -81,11 +83,9 @@ CustomCursorImage::CustomCursorImage(const QCursor &cursor)
8183/////
8284// XCursorImage
8385
84−XCursorImage::XCursorImage(const QString &theme, const QString &file)
86+XCursorImage::XCursorImage(const QString &theme, const QString &file, int preferredCursorHeightPx)
8587{
86− // TODO: Consider grid unit value
87− // Hardcoding to a medium size for now
88− int preferredCursorHeightPx = 32;
88+ requestedHeight = preferredCursorHeightPx;
8989
9090 XcursorImages *xcursorImages = XcursorLibraryLoadImages(QFile::encodeName(file), QFile::encodeName(theme),
9191 preferredCursorHeightPx);
@@ -96,7 +96,7 @@ XCursorImage::XCursorImage(const QString &theme, const QString &file)
9696 frameCount = xcursorImages->nimage;
9797
9898 for (int i = 0; i < xcursorImages->nimage; ++i) {
99− XcursorImage *xcursorImage = xcursorImages->images[0];
99+ XcursorImage *xcursorImage = xcursorImages->images[i];
100100 if (frameWidth < (int)xcursorImage->width) {
101101 frameWidth = xcursorImage->width;
102102 }
@@ -235,34 +235,43 @@ CursorImageProvider::~CursorImageProvider()
235235 m_instance = nullptr;
236236}
237237
238−QImage CursorImageProvider::requestImage(const QString &cursorThemeAndName, QSize *size, const QSize & /*requestedSize*/)
238+QImage CursorImageProvider::requestImage(const QString &cursorThemeAndNameAndHeight, QSize *size, const QSize & /*requestedSize*/)
239239{
240− CursorImage *cursorImage = fetchCursor(cursorThemeAndName);
240+ CursorImage *cursorImage = fetchCursor(cursorThemeAndNameAndHeight);
241241 size->setWidth(cursorImage->qimage.width());
242242 size->setHeight(cursorImage->qimage.height());
243243
244244 return cursorImage->qimage;
245245}
246246
247−CursorImage *CursorImageProvider::fetchCursor(const QString &cursorThemeAndName)
247+CursorImage *CursorImageProvider::fetchCursor(const QString &cursorThemeAndNameAndHeight)
248248{
249249 QString themeName;
250250 QString cursorName;
251+ int cursorHeight;
251252 {
252− QStringList themeAndNameList = cursorThemeAndName.split('/');
253− if (themeAndNameList.size() != 2) {
253+ QStringList themeAndNameList = cursorThemeAndNameAndHeight.split('/');
254+ if (themeAndNameList.size() != 3) {
254255 return nullptr;
255256 }
256257 themeName = themeAndNameList[0];
257258 cursorName = themeAndNameList[1];
259+
260+ bool ok;
261+ cursorHeight = themeAndNameList[2].toInt(&ok);
262+ if (!ok) {
263+ cursorHeight = 32;
264+ qWarning().nospace() << "CursorImageProvider: invalid cursor height ("<<themeAndNameList[2]<<")."
265+ " Falling back to "<<cursorHeight<<" pixels";
266+ }
258267 }
259268
260− return fetchCursor(themeName, cursorName);
269+ return fetchCursor(themeName, cursorName, cursorHeight);
261270}
262271
263−CursorImage *CursorImageProvider::fetchCursor(const QString &themeName, const QString &cursorName)
272+CursorImage *CursorImageProvider::fetchCursor(const QString &themeName, const QString &cursorName, int cursorHeight)
264273{
265− CursorImage *cursorImage = fetchCursorHelper(themeName, cursorName);
274+ CursorImage *cursorImage = fetchCursorHelper(themeName, cursorName, cursorHeight);
266275
267276 // Try some fallbacks
268277 if (cursorImage->qimage.isNull()) {
@@ -271,7 +280,7 @@ CursorImage *CursorImageProvider::fetchCursor(const QString &themeName, const QS
271280 int i = 0;
272281 while (cursorImage->qimage.isNull() && i < fallbackNames.count()) {
273282 qDebug().nospace() << "CursorImageProvider: "<< cursorName <<" not found, trying " << fallbackNames.at(i);
274− cursorImage = fetchCursorHelper(themeName, fallbackNames.at(i));
283+ cursorImage = fetchCursorHelper(themeName, fallbackNames.at(i), cursorHeight);
275284 ++i;
276285 }
277286 }
@@ -281,14 +290,14 @@ CursorImage *CursorImageProvider::fetchCursor(const QString &themeName, const QS
281290 if (cursorImage->qimage.isNull() && cursorName != QLatin1String("left_ptr")) {
282291 qDebug() << "CursorImageProvider:" << cursorName
283292 << "not found (nor its fallbacks, if any). Going for \"left_ptr\" as a last resort.";
284− cursorImage = fetchCursorHelper(themeName, QStringLiteral("left_ptr"));
293+ cursorImage = fetchCursorHelper(themeName, QStringLiteral("left_ptr"), cursorHeight);
285294 }
286295
287296 if (cursorImage->qimage.isNull()) {
288297 // finally, go for the built-in cursor
289298 qWarning() << "CursorImageProvider: couldn't find any cursors. Using the built-in one";
290− if (!m_builtInCursorImage) {
291− m_builtInCursorImage.reset(new BuiltInCursorImage);
299+ if (!m_builtInCursorImage || m_builtInCursorImage->requestedHeight != cursorHeight) {
300+ m_builtInCursorImage.reset(new BuiltInCursorImage(cursorHeight));
292301 }
293302 cursorImage = m_builtInCursorImage.data();
294303 }
@@ -296,7 +305,7 @@ CursorImage *CursorImageProvider::fetchCursor(const QString &themeName, const QS
296305 return cursorImage;
297306}
298307
299−CursorImage *CursorImageProvider::fetchCursorHelper(const QString &themeName, const QString &cursorName)
308+CursorImage *CursorImageProvider::fetchCursorHelper(const QString &themeName, const QString &cursorName, int cursorHeight)
300309{
301310 if (cursorName == QLatin1String("blank")) {
302311 return &m_blankCursorImage;
@@ -306,7 +315,10 @@ CursorImage *CursorImageProvider::fetchCursorHelper(const QString &themeName, co
306315 QMap<QString, CursorImage*> &themeCursors = m_cursors[themeName];
307316
308317 if (!themeCursors.contains(cursorName)) {
309− themeCursors[cursorName] = new XCursorImage(themeName, cursorName);
318+ themeCursors[cursorName] = new XCursorImage(themeName, cursorName, cursorHeight);
319+ } else if (themeCursors[cursorName]->requestedHeight != cursorHeight) {
320+ delete themeCursors.take(cursorName);
321+ themeCursors[cursorName] = new XCursorImage(themeName, cursorName, cursorHeight);
310322 }
311323
312324 return themeCursors[cursorName];
plugins/Cursor/CursorImageProvider.h+9−6
@@ -42,17 +42,20 @@ public:
4242 int frameHeight{0};
4343 int frameCount{1};
4444 int frameDuration{40};
45+
46+ // Requested height when creating this cursor.
47+ int requestedHeight{0};
4548};
4649
4750class XCursorImage : public CursorImage {
4851public:
49− XCursorImage(const QString &theme, const QString &file);
52+ XCursorImage(const QString &theme, const QString &file, int preferredCursorHeightPx);
5053 virtual ~XCursorImage();
5154};
5255
5356class BuiltInCursorImage : public CursorImage {
5457public:
55− BuiltInCursorImage();
58+ BuiltInCursorImage(int cursorHeight);
5659};
5760
5861class BlankCursorImage : public CursorImage {
@@ -74,15 +77,15 @@ public:
7477 static CursorImageProvider *instance() { return m_instance; }
7578
7679
77− QImage requestImage(const QString &cursorName, QSize *size, const QSize &requestedSize) override;
80+ QImage requestImage(const QString &cursorThemeAndNameAndHeight, QSize *size, const QSize &requestedSize) override;
7881
79− CursorImage *fetchCursor(const QString &themeName, const QString &cursorName);
82+ CursorImage *fetchCursor(const QString &themeName, const QString &cursorName, int cursorHeight);
8083
8184 void setCustomCursor(const QCursor &customCursor);
8285
8386private:
84− CursorImage *fetchCursor(const QString &cursorThemeAndName);
85− CursorImage *fetchCursorHelper(const QString &themeName, const QString &cursorName);
87+ CursorImage *fetchCursor(const QString &cursorThemeAndNameAndHeight);
88+ CursorImage *fetchCursorHelper(const QString &themeName, const QString &cursorName, int cursorHeight);
8689
8790 // themeName -> (cursorName -> cursorImage)
8891 // TODO: discard old, unused, cursors
qml/Shell.qml+2
@@ -775,6 +775,8 @@ StyledItem {
775775 when: cursor.mouseNeverMoved && cursor.visible
776776 }
777777
778+ height: units.gu(3)
779+
778780 onPushedLeftBoundary: {
779781 if (buttons === Qt.NoButton) {
780782 launcher.pushEdge(amount);
tests/plugins/Cursor/tst_Cursor.qml+8−1
@@ -26,11 +26,13 @@ Rectangle {
2626
2727 property string themeName: "default"
2828 property string cursorName: "left_ptr"
29+ property string cursorHeight: "32"
2930
3031 CursorImageInfo {
3132 id: imageInfo
3233 themeName: root.themeName
3334 cursorName: root.cursorName
35+ cursorHeight: root.cursorHeight
3436 }
3537
3638 Item {
@@ -43,7 +45,7 @@ Rectangle {
4345
4446 x: -imageInfo.hotspot.x
4547 y: -imageInfo.hotspot.y
46− source: "image://cursor/" + root.themeName + "/" + root.cursorName
48+ source: "image://cursor/" + root.themeName + "/" + root.cursorName + "/" + root.cursorHeight
4749
4850 interpolate: false
4951
@@ -110,6 +112,10 @@ Rectangle {
110112
111113 Item {width: 10; height: 40}
112114
115+ TextEntry { id: cursorHeightEntry; name: "cursorHeight"; value: "32" }
116+
117+ Item {width: 10; height: 40}
118+
113119 Rectangle {
114120 color: applyMouseArea.pressed ? "green" : "lightslategray"
115121 width: parent.width - 20
@@ -121,6 +127,7 @@ Rectangle {
121127 onClicked: {
122128 root.themeName = themeNameEntry.value;
123129 root.cursorName = cursorNameEntry.value;
130+ root.cursorHeight = cursorHeightEntry.value;
124131 }
125132 }
126133 }