on xenial help sign in
Cursor: make its size grid unit based
commitef73617efe4419dedeaad4f351ad9be90b296564 authorDaniel d'Andrada <daniel.dandrada@canonical.com> dateThu 14 Jul 2016, 17:43 (10 years ago) parent65b1efb
7 files changed+79−31
plugins/Cursor/Cursor.qml+11−2 plugins/Cursor/CursorImageInfo.cpp+10−1 plugins/Cursor/CursorImageInfo.h+6 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+11−2
@@ -25,6 +25,13 @@ MousePointer {
2525 id: imageInfo
2626 themeName: mousePointer.themeName
2727 cursorName: mousePointer.cursorName
28+ cursorHeight: mousePointer.height
29+ }
30+
31+ QtObject {
32+ id: d
33+ readonly property url imageSource: "image://cursor/" + mousePointer.themeName + "/" + mousePointer.cursorName
34+ + "/" + mousePointer.height
2835 }
2936
3037 Loader {
@@ -32,7 +39,7 @@ MousePointer {
3239 sourceComponent: AnimatedSprite {
3340 x: -imageInfo.hotspot.x
3441 y: -imageInfo.hotspot.y
35− source: "image://cursor/" + mousePointer.themeName + "/" + mousePointer.cursorName
42+ source: d.imageSource
3643
3744 interpolate: false
3845
@@ -53,7 +60,9 @@ MousePointer {
5360 sourceComponent: Image {
5461 x: -imageInfo.hotspot.x
5562 y: -imageInfo.hotspot.y
56− source: "image://cursor/" + mousePointer.themeName + "/" + mousePointer.cursorName
63+ source: d.imageSource
64+ width: sourceSize.width
65+ height: sourceSize.height
5766 }
5867 }
5968}
plugins/Cursor/CursorImageInfo.cpp+10−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,7 +50,7 @@ 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();
plugins/Cursor/CursorImageInfo.h+6
@@ -28,6 +28,7 @@ class CursorImageInfo : public QObject
2828
2929 Q_PROPERTY(QString themeName READ themeName WRITE setThemeName NOTIFY themeNameChanged)
3030 Q_PROPERTY(QString cursorName READ cursorName WRITE setCursorName NOTIFY cursorNameChanged)
31+ Q_PROPERTY(qreal cursorHeight READ cursorHeight WRITE setCursorHeight NOTIFY cursorHeightChanged)
3132
3233 Q_PROPERTY(QPoint hotspot READ hotspot NOTIFY hotspotChanged)
3334 Q_PROPERTY(qreal frameWidth READ frameWidth NOTIFY frameWidthChanged)
@@ -44,6 +45,9 @@ public:
4445 QString cursorName() const { return m_cursorName; }
4546 void setCursorName(const QString &);
4647
48+ qreal cursorHeight() const { return m_cursorHeight; }
49+ void setCursorHeight(qreal);
50+
4751 QPoint hotspot() const;
4852 qreal frameWidth() const;
4953 qreal frameHeight() const;
@@ -53,6 +57,7 @@ public:
5357Q_SIGNALS:
5458 void themeNameChanged();
5559 void cursorNameChanged();
60+ void cursorHeightChanged();
5661 void hotspotChanged();
5762 void frameWidthChanged();
5863 void frameHeightChanged();
@@ -65,6 +70,7 @@ private Q_SLOTS:
6570private:
6671 QString m_themeName;
6772 QString m_cursorName;
73+ qreal m_cursorHeight{0};
6874
6975 CursorImage *m_cursorImage{nullptr};
7076};
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 }