Added Win32 implementation

This commit is contained in:
Marco Antognini 2017-03-04 00:10:57 +01:00 committed by Lukas Dürrenberger
parent f65459d0e1
commit b0b1f13269
6 changed files with 165 additions and 126 deletions

View File

@ -56,18 +56,18 @@ public:
/// Type | Linux | Mac OS X | Windows
/// ------------------------------------|:-----:|:--------:|:--------:
/// sf::Cursor::Arrow | yes | yes | yes
/// sf::Cursor::ArrowWait | no | no | no
/// sf::Cursor::Wait | no | no | no
/// sf::Cursor::Text | no | yes | no
/// sf::Cursor::Hand | no | yes | no
/// sf::Cursor::SizeHorizontal | no | yes | no
/// sf::Cursor::SizeVertical | no | yes | no
/// sf::Cursor::SizeTopLeftBottomRight | no | no | no
/// sf::Cursor::SizeBottomLeftTopRight | no | no | no
/// sf::Cursor::SizeAll | no | no | no
/// sf::Cursor::Cross | no | yes | no
/// sf::Cursor::Help | no | no | no
/// sf::Cursor::NotAllowed | no | yes | no
/// sf::Cursor::ArrowWait | no | no | yes
/// sf::Cursor::Wait | no | no | yes
/// sf::Cursor::Text | no | yes | yes
/// sf::Cursor::Hand | no | yes | yes
/// sf::Cursor::SizeHorizontal | no | yes | yes
/// sf::Cursor::SizeVertical | no | yes | yes
/// sf::Cursor::SizeTopLeftBottomRight | no | no | yes
/// sf::Cursor::SizeBottomLeftTopRight | no | no | yes
/// sf::Cursor::SizeAll | no | no | yes
/// sf::Cursor::Cross | no | yes | yes
/// sf::Cursor::Help | no | no | yes
/// sf::Cursor::NotAllowed | no | yes | yes
///
////////////////////////////////////////////////////////////
enum Type
@ -195,8 +195,8 @@ private:
/// with either loadFromPixels() or loadFromSystem(), the
/// cursor can be changed with sf::Window::setMouseCursor().
///
/// \todo Does Windows or Linux requires the Cursor instance
/// to outlive it's usage?
/// The behaviour is undefined if the cursor is destroyed while
/// in use by the window.
///
/// Usage example:
/// \code

View File

@ -367,6 +367,9 @@ public:
///
/// Upon window creation, the arrow cursor is used by default.
///
/// \warning The cursor must not be destroyed while in use by
/// the window.
///
/// \warning Features related to Cursor are not supported on
/// iOS and Android.
///

127
src/SFML/Window/Win32/CursorImpl.cpp Normal file → Executable file
View File

@ -26,6 +26,8 @@
// Headers
////////////////////////////////////////////////////////////
#include <SFML/Window/Win32/CursorImpl.hpp>
#include <SFML/System/Err.hpp>
#include <cstring>
namespace sf
{
@ -33,32 +35,147 @@ namespace priv
{
////////////////////////////////////////////////////////////
CursorImpl::CursorImpl()
CursorImpl::CursorImpl() :
m_cursor(NULL)
{
// TODO
// That's it.
}
////////////////////////////////////////////////////////////
CursorImpl::~CursorImpl()
{
// TODO
release();
}
////////////////////////////////////////////////////////////
bool CursorImpl::loadFromPixels(const Uint8* pixels, Vector2u size, Vector2u hotspot)
{
// TODO
release();
// Create the bitmap that will hold our color data
BITMAPV5HEADER bitmapHeader;
std::memset(&bitmapHeader, 0, sizeof(BITMAPV5HEADER));
bitmapHeader.bV5Size = sizeof(BITMAPV5HEADER);
bitmapHeader.bV5Width = size.x;
bitmapHeader.bV5Height = -static_cast<int>(size.y); // Negative indicates origin is in upper-left corner
bitmapHeader.bV5Planes = 1;
bitmapHeader.bV5BitCount = 32;
bitmapHeader.bV5Compression = BI_BITFIELDS;
bitmapHeader.bV5RedMask = 0x00ff0000;
bitmapHeader.bV5GreenMask = 0x0000ff00;
bitmapHeader.bV5BlueMask = 0x000000ff;
bitmapHeader.bV5AlphaMask = 0xff000000;
Uint8* bitmapData = NULL;
HDC screenDC = GetDC(NULL);
HBITMAP color = CreateDIBSection(
screenDC,
reinterpret_cast<const BITMAPINFO*>(&bitmapHeader),
DIB_RGB_COLORS,
reinterpret_cast<void**>(&bitmapData),
NULL,
0
);
ReleaseDC(NULL, screenDC);
if (!color)
{
err() << "Failed to create cursor color bitmap" << std::endl;
return false;
}
// Fill our bitmap with the cursor color data
std::memcpy(bitmapData, pixels, size.x * size.y * 4);
// Create a dummy mask bitmap (it won't be used)
HBITMAP mask = CreateBitmap(size.x, size.y, 1, 1, NULL);
if (!mask)
{
DeleteObject(color);
err() << "Failed to create cursor mask bitmap" << std::endl;
return false;
}
// Create the structure that describes our cursor
ICONINFO cursorInfo;
std::memset(&cursorInfo, 0, sizeof(ICONINFO));
cursorInfo.fIcon = FALSE; // This is a cursor and not an icon
cursorInfo.xHotspot = hotspot.x;
cursorInfo.yHotspot = hotspot.y;
cursorInfo.hbmColor = color;
cursorInfo.hbmMask = mask;
// Create the cursor
m_cursor = reinterpret_cast<HCURSOR>(CreateIconIndirect(&cursorInfo));
// The data has been copied into the cursor, so get rid of these
DeleteObject(color);
DeleteObject(mask);
if (m_cursor)
{
return true;
}
else
{
err() << "Failed to create cursor from bitmaps" << std::endl;
return false;
}
}
////////////////////////////////////////////////////////////
bool CursorImpl::loadFromSystem(Cursor::Type type)
{
// TODO
release();
LPCTSTR shape;
switch (type)
{
case Cursor::Arrow: shape = IDC_ARROW; break;
case Cursor::ArrowWait: shape = IDC_APPSTARTING; break;
case Cursor::Wait: shape = IDC_WAIT; break;
case Cursor::Text: shape = IDC_IBEAM; break;
case Cursor::Hand: shape = IDC_HAND; break;
case Cursor::SizeHorizontal: shape = IDC_SIZEWE; break;
case Cursor::SizeVertical: shape = IDC_SIZENS; break;
case Cursor::SizeTopLeftBottomRight: shape = IDC_SIZENWSE; break;
case Cursor::SizeBottomLeftTopRight: shape = IDC_SIZENESW; break;
case Cursor::SizeAll: shape = IDC_SIZEALL; break;
case Cursor::Cross: shape = IDC_CROSS; break;
case Cursor::Help: shape = IDC_HELP; break;
case Cursor::NotAllowed: shape = IDC_NO; break;
}
// Create a copy of the shared system cursor that we can destroy later
m_cursor = CopyCursor(LoadCursor(NULL, shape));
if (m_cursor)
{
return true;
}
else
{
err() << "Could not create copy of a system cursor" << std::endl;
return false;
}
}
////////////////////////////////////////////////////////////
void CursorImpl::release()
{
if (m_cursor) {
DestroyCursor(m_cursor);
m_cursor = NULL;
}
}
} // namespace priv

8
src/SFML/Window/Win32/CursorImpl.hpp Normal file → Executable file
View File

@ -32,6 +32,7 @@
#include <SFML/System/NonCopyable.hpp>
#include <SFML/System/Vector2.hpp>
#include <windows.h>
namespace sf
{
@ -82,9 +83,16 @@ private:
friend class WindowImplWin32;
////////////////////////////////////////////////////////////
/// \brief Release the cursor, if we have loaded one.
///
////////////////////////////////////////////////////////////
void release();
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
HCURSOR m_cursor;
};
} // namespace priv

121
src/SFML/Window/Win32/WindowImplWin32.cpp Normal file → Executable file
View File

@ -132,8 +132,8 @@ namespace priv
WindowImplWin32::WindowImplWin32(WindowHandle handle) :
m_handle (handle),
m_callback (0),
m_cursor (NULL),
m_loadedCursor (NULL),
m_cursorVisible (true), // might need to call GetCursorInfo
m_lastCursor (LoadCursor(NULL, IDC_ARROW)),
m_icon (NULL),
m_keyRepeatEnabled(true),
m_lastSize (0, 0),
@ -165,8 +165,8 @@ m_cursorGrabbed (false)
WindowImplWin32::WindowImplWin32(VideoMode mode, const String& title, Uint32 style, const ContextSettings& /*settings*/) :
m_handle (NULL),
m_callback (0),
m_cursor (NULL),
m_loadedCursor (NULL),
m_cursorVisible (true), // might need to call GetCursorInfo
m_lastCursor (LoadCursor(NULL, IDC_ARROW)),
m_icon (NULL),
m_keyRepeatEnabled(true),
m_lastSize (mode.width, mode.height),
@ -241,9 +241,7 @@ m_cursorGrabbed (m_fullscreen)
////////////////////////////////////////////////////////////
WindowImplWin32::~WindowImplWin32()
{
// Destroy the cursor
if (m_loadedCursor)
DestroyCursor(m_loadedCursor);
// TODO should we restore the cursor shape and visibility?
// Destroy the custom icon, if any
if (m_icon)
@ -396,16 +394,14 @@ void WindowImplWin32::setVisible(bool visible)
////////////////////////////////////////////////////////////
void WindowImplWin32::setMouseCursorVisible(bool visible)
{
// Set the default mouse cursor if none has been loaded yet
if (!m_loadedCursor)
setMouseCursor(Window::Arrow);
if (visible)
m_cursor = m_loadedCursor;
else
m_cursor = NULL;
SetCursor(m_cursor);
// Don't call twice ShowCursor with the same parameter value;
// we don't want to increment/decrement the internal counter
// more than once.
if (visible != m_cursorVisible)
{
m_cursorVisible = visible;
ShowCursor(visible);
}
}
@ -420,93 +416,8 @@ void WindowImplWin32::setMouseCursorGrabbed(bool grabbed)
////////////////////////////////////////////////////////////
void WindowImplWin32::setMouseCursor(const CursorImpl& cursor)
{
}
////////////////////////////////////////////////////////////
void WindowImplWin32::setMouseCursor(const Uint8* pixels, unsigned int width, unsigned int height, Uint16 hotspotX, Uint16 hotspotY)
{
// Create the bitmap that will hold our color data
BITMAPV5HEADER bitmapHeader;
std::memset(&bitmapHeader, 0, sizeof(BITMAPV5HEADER));
bitmapHeader.bV5Size = sizeof(BITMAPV5HEADER);
bitmapHeader.bV5Width = width;
bitmapHeader.bV5Height = -height; // Negative indicates origin is in upper-left corner
bitmapHeader.bV5Planes = 1;
bitmapHeader.bV5BitCount = 32;
bitmapHeader.bV5Compression = BI_BITFIELDS;
bitmapHeader.bV5RedMask = 0x00ff0000;
bitmapHeader.bV5GreenMask = 0x0000ff00;
bitmapHeader.bV5BlueMask = 0x000000ff;
bitmapHeader.bV5AlphaMask = 0xff000000;
Uint8* bitmapData = NULL;
HDC screenDC = GetDC(NULL);
HBITMAP color = CreateDIBSection(
screenDC,
reinterpret_cast<const BITMAPINFO*>(&bitmapHeader),
DIB_RGB_COLORS,
reinterpret_cast<void**>(&bitmapData),
NULL,
0
);
ReleaseDC(NULL, screenDC);
if (!color)
{
err() << "Failed to create cursor color bitmap" << std::endl;
return;
}
// Fill our bitmap with the cursor color data
std::memcpy(bitmapData, pixels, width * height * 4);
// Create a dummy mask bitmap (it won't be used)
HBITMAP mask = CreateBitmap(width, height, 1, 1, NULL);
if (!mask)
{
DeleteObject(color);
err() << "Failed to create cursor mask bitmap" << std::endl;
return;
}
// Create the structure that describes our cursor
ICONINFO cursorInfo;
std::memset(&cursorInfo, 0, sizeof(ICONINFO));
cursorInfo.fIcon = FALSE; // This is a cursor and not an icon
cursorInfo.xHotspot = hotspotX;
cursorInfo.yHotspot = hotspotY;
cursorInfo.hbmColor = color;
cursorInfo.hbmMask = mask;
// Create the cursor
HCURSOR newCursor = reinterpret_cast<HCURSOR>(CreateIconIndirect(&cursorInfo));
// The data has been copied into the cursor, so get rid of these
DeleteObject(color);
DeleteObject(mask);
if (!newCursor)
{
err() << "Failed to create cursor from bitmaps" << std::endl;
return;
}
HCURSOR oldCursor = m_loadedCursor;
m_loadedCursor = newCursor;
if (m_cursor)
{
m_cursor = m_loadedCursor;
SetCursor(m_cursor);
}
if (oldCursor)
DestroyCursor(oldCursor);
m_lastCursor = cursor.m_cursor;
SetCursor(m_lastCursor);
}
@ -671,7 +582,7 @@ void WindowImplWin32::processEvent(UINT message, WPARAM wParam, LPARAM lParam)
{
// The mouse has moved, if the cursor is in our window we must refresh the cursor
if (LOWORD(lParam) == HTCLIENT)
SetCursor(m_cursor);
SetCursor(m_lastCursor);
break;
}

4
src/SFML/Window/Win32/WindowImplWin32.hpp Normal file → Executable file
View File

@ -274,8 +274,8 @@ private:
////////////////////////////////////////////////////////////
HWND m_handle; ///< Win32 handle of the window
LONG_PTR m_callback; ///< Stores the original event callback function of the control
HCURSOR m_cursor; ///< The system cursor currently displayed into the window, NULL if hidden
HCURSOR m_loadedCursor; ///< The system cursor selected to be displayed into the window
bool m_cursorVisible; ///< Is the cursor visible or hidden?
HCURSOR m_lastCursor; ///< Last cursor used -- this data is not owned by the window and is required to be always valid
HICON m_icon; ///< Custom icon assigned to the window
bool m_keyRepeatEnabled; ///< Automatic key-repeat state for keydown events
Vector2u m_lastSize; ///< The last handled size of the window