Windows: Add non-standard mouse cursors

Windows does not provide SplitVCursor, SplitHCursor,
OpenHandCursor, ClosedHandCursor, DragCopyCursor,
DragMoveCursor, DragLinkCursor.

This change adds those mouse cursors mimicking the look
of the standard Aero cursors. 32px, 48px and 64px for
each one.

For WinCE or if Qt is configured without png support, the
behavior should not be changed by this patch.

Task-number: QTBUG-38993
Change-Id: Ic0f739d7c5031168b7d105b4d41271a9359d0728
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
This commit is contained in:
Alessandro Portale 2014-07-02 17:52:06 +02:00
parent 0831cb26f4
commit 7de95ede1b
25 changed files with 136 additions and 30 deletions

View File

@ -0,0 +1,25 @@
<RCC>
<qresource prefix="/qt-project.org/windows/cursors">
<file>images/closedhandcursor_32.png</file>
<file>images/closedhandcursor_48.png</file>
<file>images/closedhandcursor_64.png</file>
<file>images/dragcopycursor_32.png</file>
<file>images/dragcopycursor_48.png</file>
<file>images/dragcopycursor_64.png</file>
<file>images/draglinkcursor_32.png</file>
<file>images/draglinkcursor_48.png</file>
<file>images/draglinkcursor_64.png</file>
<file>images/dragmovecursor_32.png</file>
<file>images/dragmovecursor_48.png</file>
<file>images/dragmovecursor_64.png</file>
<file>images/openhandcursor_32.png</file>
<file>images/openhandcursor_48.png</file>
<file>images/openhandcursor_64.png</file>
<file>images/splithcursor_32.png</file>
<file>images/splithcursor_48.png</file>
<file>images/splithcursor_64.png</file>
<file>images/splitvcursor_32.png</file>
<file>images/splitvcursor_48.png</file>
<file>images/splitvcursor_64.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 350 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 470 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 463 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 452 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

View File

@ -208,12 +208,13 @@ static HCURSOR createBitmapCursor(const QImage &bbits, const QImage &mbits,
static inline QSize systemCursorSize() { return QSize(GetSystemMetrics(SM_CXCURSOR), GetSystemMetrics(SM_CYCURSOR)); }
static inline QSize standardCursorSize() { return QSize(32, 32); }
#if defined (Q_OS_WINCE) || defined (QT_NO_IMAGEFORMAT_PNG)
// Create pixmap cursors from data and scale the image if the cursor size is
// higher than the standard 32. Note that bitmap cursors as produced by
// createBitmapCursor() only work for standard sizes (32,48,64...), which does
// not work when scaling the 16x16 openhand cursor bitmaps to 150% (resulting
// in a non-standard 24x24 size).
static HCURSOR createPixmapCursorFromData(const QSize &systemCursorSize,
static QCursor createPixmapCursorFromData(const QSize &systemCursorSize,
// The cursor size the bitmap is targeted for
const QSize &bitmapTargetCursorSize,
// The actual size of the bitmap data
@ -231,33 +232,11 @@ static HCURSOR createPixmapCursorFromData(const QSize &systemCursorSize,
rawImage = rawImage.transformed(transform, Qt::SmoothTransformation);
}
const QPoint hotSpot(rawImage.width() / 2, rawImage.height() / 2);
return QWindowsCursor::createPixmapCursor(rawImage, hotSpot);
return QCursor(rawImage, hotSpot.x(), hotSpot.y());
}
struct QWindowsStandardCursorMapping {
Qt::CursorShape shape;
LPCWSTR resource;
};
HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c)
QCursor QWindowsCursor::customCursor(Qt::CursorShape cursorShape)
{
static const QWindowsStandardCursorMapping standardCursors[] = {
{ Qt::ArrowCursor, IDC_ARROW},
{ Qt::UpArrowCursor, IDC_UPARROW },
{ Qt::CrossCursor, IDC_CROSS },
{ Qt::WaitCursor, IDC_WAIT },
{ Qt::IBeamCursor, IDC_IBEAM },
{ Qt::SizeVerCursor, IDC_SIZENS },
{ Qt::SizeHorCursor, IDC_SIZEWE },
{ Qt::SizeBDiagCursor, IDC_SIZENESW },
{ Qt::SizeFDiagCursor, IDC_SIZENWSE },
{ Qt::SizeAllCursor, IDC_SIZEALL },
{ Qt::ForbiddenCursor, IDC_NO },
{ Qt::WhatsThisCursor, IDC_HELP },
{ Qt::BusyCursor, IDC_APPSTARTING },
{ Qt::PointingHandCursor, IDC_HAND }
};
// Non-standard Windows cursors are created from bitmaps
static const uchar vsplit_bits[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -324,6 +303,107 @@ HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c)
0xf0,0x7f,0xf8,0x7f,0xfc,0x7f,0xfc,0x3f,0xf8,0x3f,0xf0,0x1f,
0xe0,0x1f,0xe0,0x1f,0x00,0x00,0x00,0x00};
switch (cursorShape) {
case Qt::SplitVCursor:
return createPixmapCursorFromData(systemCursorSize(), standardCursorSize(), 32, vsplit_bits, vsplitm_bits);
case Qt::SplitHCursor:
return createPixmapCursorFromData(systemCursorSize(), standardCursorSize(), 32, hsplit_bits, hsplitm_bits);
case Qt::OpenHandCursor:
return createPixmapCursorFromData(systemCursorSize(), standardCursorSize(), 16, openhand_bits, openhandm_bits);
case Qt::ClosedHandCursor:
return createPixmapCursorFromData(systemCursorSize(), standardCursorSize(), 16, closedhand_bits, closedhandm_bits);
case Qt::DragCopyCursor:
case Qt::DragMoveCursor:
case Qt::DragLinkCursor:
return QCursor(QGuiApplicationPrivate::instance()->getPixmapCursor(cursorShape), 0, 0);
}
return QCursor();
}
#else // Q_OS_WINCE || QT_NO_IMAGEFORMAT_PNG
struct QWindowsCustomPngCursor {
Qt::CursorShape shape;
int size;
const char *fileName;
int hotSpotX;
int hotSpotY;
};
QCursor QWindowsCursor::customCursor(Qt::CursorShape cursorShape)
{
static const QWindowsCustomPngCursor pngCursors[] = {
{ Qt::SplitVCursor, 32, "splitvcursor_32.png", 11, 11 },
{ Qt::SplitVCursor, 48, "splitvcursor_48.png", 16, 17 },
{ Qt::SplitVCursor, 64, "splitvcursor_64.png", 22, 22 },
{ Qt::SplitHCursor, 32, "splithcursor_32.png", 11, 11 },
{ Qt::SplitHCursor, 48, "splithcursor_48.png", 16, 17 },
{ Qt::SplitHCursor, 64, "splithcursor_64.png", 22, 22 },
{ Qt::OpenHandCursor, 32, "openhandcursor_32.png", 10, 12 },
{ Qt::OpenHandCursor, 48, "openhandcursor_48.png", 15, 16 },
{ Qt::OpenHandCursor, 64, "openhandcursor_64.png", 20, 24 },
{ Qt::ClosedHandCursor, 32, "closedhandcursor_32.png", 10, 12 },
{ Qt::ClosedHandCursor, 48, "closedhandcursor_48.png", 15, 16 },
{ Qt::ClosedHandCursor, 64, "closedhandcursor_64.png", 20, 24 },
{ Qt::DragCopyCursor, 32, "dragcopycursor_32.png", 0, 0 },
{ Qt::DragCopyCursor, 48, "dragcopycursor_48.png", 0, 0 },
{ Qt::DragCopyCursor, 64, "dragcopycursor_64.png", 0, 0 },
{ Qt::DragMoveCursor, 32, "dragmovecursor_32.png", 0, 0 },
{ Qt::DragMoveCursor, 48, "dragmovecursor_48.png", 0, 0 },
{ Qt::DragMoveCursor, 64, "dragmovecursor_64.png", 0, 0 },
{ Qt::DragLinkCursor, 32, "draglinkcursor_32.png", 0, 0 },
{ Qt::DragLinkCursor, 48, "draglinkcursor_48.png", 0, 0 },
{ Qt::DragLinkCursor, 64, "draglinkcursor_64.png", 0, 0 }
};
const int cursorSize = GetSystemMetrics(SM_CXCURSOR);
const QWindowsCustomPngCursor *sEnd = pngCursors + sizeof(pngCursors) / sizeof(pngCursors[0]);
const QWindowsCustomPngCursor *bestFit = 0;
int sizeDelta = INT_MAX;
for (const QWindowsCustomPngCursor *s = pngCursors; s < sEnd; ++s) {
if (s->shape != cursorShape)
continue;
const int currentSizeDelta = qMax(s->size, cursorSize) - qMin(s->size, cursorSize);
if (currentSizeDelta < sizeDelta) {
bestFit = s;
if (currentSizeDelta == 0)
break; // Perfect match found
sizeDelta = currentSizeDelta;
}
}
if (!bestFit)
return QCursor();
const QPixmap rawImage(QStringLiteral(":/qt-project.org/windows/cursors/images/") +
QString::fromLatin1(bestFit->fileName));
return QCursor(rawImage, bestFit->hotSpotX, bestFit->hotSpotY);
}
#endif // Q_OS_WINCE || QT_NO_IMAGEFORMAT_PNG
struct QWindowsStandardCursorMapping {
Qt::CursorShape shape;
LPCWSTR resource;
};
HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c)
{
static const QWindowsStandardCursorMapping standardCursors[] = {
{ Qt::ArrowCursor, IDC_ARROW},
{ Qt::UpArrowCursor, IDC_UPARROW },
{ Qt::CrossCursor, IDC_CROSS },
{ Qt::WaitCursor, IDC_WAIT },
{ Qt::IBeamCursor, IDC_IBEAM },
{ Qt::SizeVerCursor, IDC_SIZENS },
{ Qt::SizeHorCursor, IDC_SIZEWE },
{ Qt::SizeBDiagCursor, IDC_SIZENESW },
{ Qt::SizeFDiagCursor, IDC_SIZENWSE },
{ Qt::SizeAllCursor, IDC_SIZEALL },
{ Qt::ForbiddenCursor, IDC_NO },
{ Qt::WhatsThisCursor, IDC_HELP },
{ Qt::BusyCursor, IDC_APPSTARTING },
{ Qt::PointingHandCursor, IDC_HAND }
};
const Qt::CursorShape cursorShape = c.shape();
switch (cursorShape) {
case Qt::BitmapCursor: {
@ -342,17 +422,13 @@ HCURSOR QWindowsCursor::createSystemCursor(const QCursor &c)
return createBitmapCursor(blank, blank);
}
case Qt::SplitVCursor:
return createPixmapCursorFromData(systemCursorSize(), standardCursorSize(), 32, vsplit_bits, vsplitm_bits);
case Qt::SplitHCursor:
return createPixmapCursorFromData(systemCursorSize(), standardCursorSize(), 32, hsplit_bits, hsplitm_bits);
case Qt::OpenHandCursor:
return createPixmapCursorFromData(systemCursorSize(), standardCursorSize(), 16, openhand_bits, openhandm_bits);
case Qt::ClosedHandCursor:
return createPixmapCursorFromData(systemCursorSize(), standardCursorSize(), 16, closedhand_bits, closedhandm_bits);
case Qt::DragCopyCursor:
case Qt::DragMoveCursor:
case Qt::DragLinkCursor:
return createPixmapCursor(QGuiApplicationPrivate::instance()->getPixmapCursor(cursorShape), c.hotSpot());
return createSystemCursor(customCursor(cursorShape));
default:
break;
}

View File

@ -107,6 +107,7 @@ public:
static HCURSOR createPixmapCursor(const QPixmap &pixmap, const QPoint &hotSpot);
static HCURSOR createSystemCursor(const QCursor &c);
static QCursor customCursor(Qt::CursorShape cursorShape);
static QPoint mousePosition();
static CursorState cursorState();

View File

@ -113,6 +113,10 @@ contains(QT_CONFIG,dynamicgl) {
HEADERS += $$PWD/qwindowssessionmanager.h
}
!wince*:!contains( DEFINES, QT_NO_IMAGEFORMAT_PNG ) {
RESOURCES += $$PWD/cursors.qrc
}
contains(QT_CONFIG, freetype) {
DEFINES *= QT_NO_FONTCONFIG
QT_FREETYPE_DIR = $$QT_SOURCE_TREE/src/3rdparty/freetype