Utility: Rework cursors

-Rename WindowCursor to SystemCursor
-Merged Cursor class with SystemCursor enum
This commit is contained in:
Lynix 2017-01-16 00:32:59 +01:00
parent 954298dc1e
commit f406068c45
16 changed files with 281 additions and 202 deletions

View File

@ -251,7 +251,7 @@ int main()
}
// On fait disparaître le curseur de la souris
window.SetCursor(Nz::WindowCursor_None);
window.SetCursor(Nz::SystemCursor_None);
// On lie la caméra à la fenêtre
cameraComp.SetTarget(&window);

View File

@ -644,7 +644,7 @@ void SpacebattleExample::Enter(Ndk::StateMachine& fsm)
m_turretReloadSound.LoadFromFile("resources/turretReload.wav");
//m_onMouseMoved.Connect(m_shared.target->GetEventHandler().OnMouseMoved, this, &SpacebattleExample::OnMouseMoved);
//m_shared.target->SetCursor(Nz::WindowCursor_None);
//m_shared.target->SetCursor(Nz::SystemCursor_None);
//////////////////////////////////////////////////////////////////////////

View File

@ -22,18 +22,32 @@ namespace Nz
public:
inline Cursor();
inline Cursor(SystemCursor systemCursor); //< implicit conversion intended
Cursor(const Cursor&) = delete;
inline Cursor(Cursor&& cursor) noexcept;
inline ~Cursor();
bool Create(const Image& cursor, int hotSpotX = 0, int hotSpotY = 0);
bool Create(const Image& cursor, const Vector2i& hotSpot);
bool Create(SystemCursor cursor);
void Destroy();
inline const Image& GetImage() const;
inline SystemCursor GetSystemCursor() const;
inline bool IsValid() const;
Cursor& operator=(const Cursor&) = delete;
inline Cursor& operator=(Cursor&& cursor);
private:
static bool Initialize();
static void Uninitialize();
Image m_cursorImage;
SystemCursor m_systemCursor;
CursorImpl* m_impl;
bool m_usesSystemCursor;
};
}

View File

@ -3,15 +3,30 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Utility/Cursor.hpp>
#include <Nazara/Core/ErrorFlags.hpp>
#include <Nazara/Utility/Debug.hpp>
namespace Nz
{
inline Cursor::Cursor() :
m_impl(nullptr)
m_impl(nullptr),
m_usesSystemCursor(false)
{
}
inline Cursor::Cursor(SystemCursor systemCursor) :
Cursor()
{
ErrorFlags flags(ErrorFlag_ThrowException, true);
Create(systemCursor);
}
inline Cursor::Cursor(Cursor&& cursor) noexcept :
Cursor()
{
operator=(std::move(cursor));
}
inline Cursor::~Cursor()
{
Destroy();
@ -19,13 +34,36 @@ namespace Nz
inline const Image& Cursor::GetImage() const
{
NazaraAssert(IsValid(), "Invalid cursor");
NazaraAssert(!m_usesSystemCursor, "System cursors have no image");
return m_cursorImage;
}
inline SystemCursor Cursor::GetSystemCursor() const
{
NazaraAssert(IsValid(), "Invalid cursor");
NazaraAssert(m_usesSystemCursor, "Custom cursor uses an image");
return m_systemCursor;
}
inline bool Cursor::IsValid() const
{
return m_impl != nullptr;
}
inline Cursor& Cursor::operator=(Cursor&& cursor)
{
m_cursorImage = std::move(cursor.m_cursorImage);
m_systemCursor = cursor.m_systemCursor;
m_impl = cursor.m_impl;
m_usesSystemCursor = cursor.m_usesSystemCursor;
cursor.m_impl = nullptr;
return *this;
}
}
#include <Nazara/Utility/DebugOff.hpp>

View File

@ -307,6 +307,31 @@ namespace Nz
SamplerWrap_Max = SamplerWrap_Repeat
};
enum SystemCursor
{
SystemCursor_None,
SystemCursor_Default,
SystemCursor_Crosshair,
SystemCursor_Hand,
SystemCursor_Help,
SystemCursor_Move,
SystemCursor_Pointer,
SystemCursor_Progress,
SystemCursor_ResizeE,
SystemCursor_ResizeN,
SystemCursor_ResizeNE,
SystemCursor_ResizeNW,
SystemCursor_ResizeS,
SystemCursor_ResizeSE,
SystemCursor_ResizeSW,
SystemCursor_ResizeW,
SystemCursor_Text,
SystemCursor_Wait,
SystemCursor_Max = SystemCursor_Wait
};
enum StencilOperation
{
StencilOperation_Decrement,
@ -393,31 +418,6 @@ namespace Nz
VertexLayout_Max = VertexLayout_Matrix4
};
enum WindowCursor
{
WindowCursor_None,
WindowCursor_Default,
WindowCursor_Crosshair,
WindowCursor_Hand,
WindowCursor_Help,
WindowCursor_Move,
WindowCursor_Pointer,
WindowCursor_Progress,
WindowCursor_ResizeE,
WindowCursor_ResizeN,
WindowCursor_ResizeNE,
WindowCursor_ResizeNW,
WindowCursor_ResizeS,
WindowCursor_ResizeSE,
WindowCursor_ResizeSW,
WindowCursor_ResizeW,
WindowCursor_Text,
WindowCursor_Wait,
WindowCursor_Max = WindowCursor_Wait
};
enum WindowEventType
{
WindowEventType_GainedFocus,

View File

@ -79,7 +79,6 @@ namespace Nz
void ProcessEvents(bool block = false);
void SetCursor(WindowCursor cursor);
void SetCursor(const Cursor& cursor);
void SetEventListener(bool listener);
void SetFocus();

View File

@ -16,28 +16,39 @@
namespace Nz
{
bool Cursor::Create(const Image& cursor, int hotSpotX, int hotSpotY)
bool Cursor::Create(const Image& cursor, const Vector2i& hotSpot)
{
Destroy();
m_impl = new CursorImpl;
if (!m_impl->Create(cursor, hotSpotX, hotSpotY))
std::unique_ptr<CursorImpl> impl(new CursorImpl);
if (!impl->Create(cursor, hotSpot.x, hotSpot.y))
{
NazaraError("Failed to create cursor implementation");
delete m_impl;
m_impl = nullptr;
return false;
}
m_cursorImage = cursor;
m_impl = impl.release();
return true;
}
bool Cursor::Create(const Image& cursor, const Vector2i& hotSpot)
inline bool Cursor::Create(SystemCursor cursor)
{
return Create(cursor, hotSpot.x, hotSpot.y);
Destroy();
std::unique_ptr<CursorImpl> impl(new CursorImpl);
if (!impl->Create(cursor))
{
NazaraError("Failed to create cursor implementation");
return false;
}
m_impl = impl.release();
m_systemCursor = cursor;
m_usesSystemCursor = true;
return true;
}
void Cursor::Destroy()
@ -49,5 +60,17 @@ namespace Nz
delete m_impl;
m_impl = nullptr;
}
m_usesSystemCursor = false;
}
bool Cursor::Initialize()
{
return CursorImpl::Initialize();
}
void Cursor::Uninitialize()
{
CursorImpl::Uninitialize();
}
}

View File

@ -30,27 +30,77 @@ namespace Nz
iconInfo.hbmMask = monoBitmap;
iconInfo.hbmColor = bitmap;
m_cursor = CreateIconIndirect(&iconInfo);
m_icon = CreateIconIndirect(&iconInfo);
DeleteObject(bitmap);
DeleteObject(monoBitmap);
if (!m_cursor)
if (!m_icon)
{
NazaraError("Failed to create cursor: " + Error::GetLastSystemError());
return false;
}
m_cursor = m_icon;
return true;
}
bool CursorImpl::Create(SystemCursor cursor)
{
if (cursor != SystemCursor_Move)
m_cursor = static_cast<HCURSOR>(LoadImage(nullptr, s_systemCursorIds[cursor], IMAGE_CURSOR, 0, 0, LR_SHARED));
else
m_cursor = nullptr;
// No need to free the cursor if shared
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms648045(v=vs.85).aspx
m_icon = nullptr;
return true;
}
void CursorImpl::Destroy()
{
DestroyIcon(m_cursor);
if (m_icon)
DestroyIcon(m_icon);
}
HCURSOR CursorImpl::GetCursor()
{
return m_cursor;
}
bool CursorImpl::Initialize()
{
return true;
}
void CursorImpl::Uninitialize()
{
}
std::array<LPTSTR, SystemCursor_Max + 1> CursorImpl::s_systemCursorIds =
{
IDC_CROSS, // SystemCursor_Crosshair
IDC_ARROW, // SystemCursor_Default
IDC_HAND, // SystemCursor_Hand
IDC_HELP, // SystemCursor_Help
IDC_SIZEALL, // SystemCursor_Move
nullptr, // SystemCursor_None
IDC_HAND, // SystemCursor_Pointer
IDC_APPSTARTING, // SystemCursor_Progress
IDC_SIZEWE, // SystemCursor_ResizeE
IDC_SIZENS, // SystemCursor_ResizeN
IDC_SIZENESW, // SystemCursor_ResizeNE
IDC_SIZENWSE, // SystemCursor_ResizeNW
IDC_SIZENS, // SystemCursor_ResizeS
IDC_SIZENWSE, // SystemCursor_ResizeSE
IDC_SIZENESW, // SystemCursor_ResizeSW
IDC_SIZEWE, // SystemCursor_ResizeW
IDC_IBEAM, // SystemCursor_Text
IDC_WAIT // SystemCursor_Wait
};
static_assert(SystemCursor_Max + 1 == 18, "System cursor array is incomplete");
}

View File

@ -8,6 +8,8 @@
#define NAZARA_CURSORIMPL_HPP
#include <Nazara/Prerequesites.hpp>
#include <Nazara/Utility/Enums.hpp>
#include <array>
#include <windows.h>
namespace Nz
@ -16,14 +18,24 @@ namespace Nz
class CursorImpl
{
friend class Cursor;
public:
bool Create(const Image& image, int hotSpotX, int hotSpotY);
bool Create(SystemCursor cursor);
void Destroy();
HCURSOR GetCursor();
private:
HICON m_cursor = nullptr;
static bool Initialize();
static void Uninitialize();
HCURSOR m_cursor = nullptr;
HICON m_icon = nullptr;
static std::array<LPTSTR, SystemCursor_Max + 1> s_systemCursorIds;
};
}

View File

@ -4,8 +4,6 @@
// Un grand merci à Laurent Gomila pour la SFML qui m'aura bien aidé à réaliser cette implémentation
#define OEMRESOURCE
#include <Nazara/Utility/Win32/WindowImpl.hpp>
#include <Nazara/Core/ConditionVariable.hpp>
#include <Nazara/Core/Error.hpp>
@ -38,30 +36,6 @@ namespace Nz
{
namespace
{
LPTSTR windowsCursors[] =
{
IDC_CROSS, // WindowCursor_Crosshair
IDC_ARROW, // WindowCursor_Default
IDC_HAND, // WindowCursor_Hand
IDC_HAND, // WindowCursor_Pointer
IDC_HELP, // WindowCursor_Help
IDC_SIZEALL, // WindowCursor_Move
nullptr, // WindowCursor_None
IDC_APPSTARTING, // WindowCursor_Progress
IDC_SIZENS, // WindowCursor_ResizeN
IDC_SIZENS, // WindowCursor_ResizeS
IDC_SIZENWSE, // WindowCursor_ResizeNW
IDC_SIZENWSE, // WindowCursor_ResizeSE
IDC_SIZENESW, // WindowCursor_ResizeNE
IDC_SIZENESW, // WindowCursor_ResizeSW
IDC_SIZEWE, // WindowCursor_ResizeE
IDC_SIZEWE, // WindowCursor_ResizeW
IDC_IBEAM, // WindowCursor_Text
IDC_WAIT // WindowCursor_Wait
};
static_assert(sizeof(windowsCursors)/sizeof(LPTSTR) == WindowCursor_Max+1, "Cursor type array is incomplete");
const wchar_t* className = L"Nazara Window";
WindowImpl* fullscreenWindow = nullptr;
}
@ -321,26 +295,6 @@ namespace Nz
}
}
void WindowImpl::SetCursor(WindowCursor cursor)
{
#ifdef NAZARA_DEBUG
if (cursor > WindowCursor_Max)
{
NazaraError("Window cursor out of enum");
return;
}
#endif
if (cursor != WindowCursor_None)
m_cursor = static_cast<HCURSOR>(LoadImage(nullptr, windowsCursors[cursor], IMAGE_CURSOR, 0, 0, LR_SHARED));
else
m_cursor = nullptr;
// Pas besoin de libérer le curseur par la suite s'il est partagé
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms648045(v=vs.85).aspx
::SetCursor(m_cursor);
}
void WindowImpl::SetCursor(const Cursor& cursor)
{
m_cursor = cursor.m_impl->GetCursor();

View File

@ -27,7 +27,7 @@ namespace Nz
class Mutex;
class Window;
#undef IsMinimized // Conflit avec la méthode du même nom
#undef IsMinimized // Conflits with windows.h redefinition
class WindowImpl
{
@ -62,7 +62,6 @@ namespace Nz
void ProcessEvents(bool block);
void SetCursor(WindowCursor cursor);
void SetCursor(const Cursor& cursor);
void SetEventListener(bool listener);
void SetFocus();

View File

@ -90,7 +90,7 @@ namespace Nz
// Paramètres par défaut
m_impl->EnableKeyRepeat(true);
m_impl->EnableSmoothScrolling(false);
m_impl->SetCursor(WindowCursor_Default);
m_impl->SetCursor(SystemCursor_Default);
m_impl->SetMaximumSize(-1, -1);
m_impl->SetMinimumSize(-1, -1);
m_impl->SetVisible(true);
@ -350,34 +350,10 @@ namespace Nz
}
}
void Window::SetCursor(WindowCursor cursor)
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Window not created");
return;
}
#endif
m_impl->SetCursor(cursor);
}
void Window::SetCursor(const Cursor& cursor)
{
#if NAZARA_UTILITY_SAFE
if (!m_impl)
{
NazaraError("Window not created");
return;
}
if (!cursor.IsValid())
{
NazaraError("Cursor is not valid");
return;
}
#endif
NazaraAssert(m_impl, "Window not created");
NazaraAssert(cursor.IsValid(), "Invalid cursor");
m_impl->SetCursor(cursor);
}

View File

@ -159,16 +159,96 @@ namespace Nz
return true;
}
bool CursorImpl::Create(SystemCursor cursor)
{
ScopedXCBConnection connection;
if (xcb_cursor_context_new(connection, m_screen, &m_cursorContext) >= 0)
m_cursor = xcb_cursor_load_cursor(ctx, s_systemCursorIds[cursor]);
return true;
}
void CursorImpl::Destroy()
{
ScopedXCBConnection connection;
xcb_free_cursor(connection, m_cursor);
m_cursor = 0;
if (m_cursorContext)
xcb_cursor_context_free(m_cursorContext);
}
xcb_cursor_t CursorImpl::GetCursor()
{
return m_cursor;
}
bool CursorImpl::Initialize()
{
ScopedXCBConnection connection;
XCBPixmap cursorPixmap(connection);
xcb_window_t window = X11::XCBDefaultRootWindow(connection);
if (!cursorPixmap.Create(1, window, 1, 1))
{
NazaraError("Failed to create pixmap for hidden cursor");
return false;
}
hiddenCursor = xcb_generate_id(connection);
// Create the cursor, using the pixmap as both the shape and the mask of the cursor
if (!X11::CheckCookie(
connection, xcb_create_cursor(connection,
hiddenCursor,
cursorPixmap,
cursorPixmap,
0, 0, 0, // Foreground RGB color
0, 0, 0, // Background RGB color
0, // X
0 // Y
)))
{
NazaraError("Failed to create hidden cursor");
return false;
}
return true;
}
void CursorImpl::Uninitialize()
{
if (s_hiddenCursor)
{
ScopedXCBConnection connection;
xcb_free_cursor(connection, s_hiddenCursor);
s_hiddenCursor = 0;
}
}
std::array<const char*, SystemCursor_Max + 1> CursorImpl::s_systemCursorIds =
{
// http://gnome-look.org/content/preview.php?preview=1&id=128170&file1=128170-1.png&file2=&file3=&name=Dummy+X11+cursors&PHPSESSID=6
"crosshair", // SystemCursor_Crosshair
"left_ptr", // SystemCursor_Default
"hand", // SystemCursor_Hand
"help", // SystemCursor_Help
"fleur", // SystemCursor_Move
nullptr, // SystemCursor_None
"hand", // SystemCursor_Pointer
"watch", // SystemCursor_Progress
"right_side", // SystemCursor_ResizeE
"top_side", // SystemCursor_ResizeN
"top_right_corner", // SystemCursor_ResizeNE
"top_left_corner", // SystemCursor_ResizeNW
"bottom_side", // SystemCursor_ResizeS
"bottom_right_corner", // SystemCursor_ResizeSE
"bottom_left_corner", // SystemCursor_ResizeSW
"left_side", // SystemCursor_ResizeW
"xterm", // SystemCursor_Text
"watch" // SystemCursor_Wait
};
static_assert(SystemCursor_Max + 1 == 18, "System cursor array is incomplete");
}

View File

@ -8,6 +8,7 @@
#define NAZARA_CURSORIMPL_HPP
#include <Nazara/Prerequesites.hpp>
#include <Nazara/Utility/Enums.hpp>
#include <xcb/xcb_cursor.h>
namespace Nz
@ -16,14 +17,24 @@ namespace Nz
class CursorImpl
{
friend class Cursor;
public:
bool Create(const Image& image, int hotSpotX, int hotSpotY);
bool Create(SystemCursor cursor);
void Destroy();
xcb_cursor_t GetCursor();
private:
xcb_cursor_t m_cursor;
static bool Initialize();
static void Uninitialize();
xcb_cursor_t m_cursor = 0;
xcb_cursor_context_t* m_cursorContext = nullptr;
static std::array<const char*, SystemCursor_Max + 1> s_systemCursorIds;
};
}

View File

@ -50,45 +50,7 @@ namespace Nz
XCB_EVENT_MASK_KEY_RELEASE | XCB_EVENT_MASK_STRUCTURE_NOTIFY |
XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW;
xcb_cursor_t hiddenCursor = 0;
xcb_connection_t* connection = nullptr;
void CreateHiddenCursor()
{
XCBPixmap cursorPixmap(connection);
xcb_window_t window = X11::XCBDefaultRootWindow(connection);
if (!cursorPixmap.Create(
1,
window,
1,
1
))
{
NazaraError("Failed to create pixmap for hidden cursor");
return;
}
hiddenCursor = xcb_generate_id(connection);
// Create the cursor, using the pixmap as both the shape and the mask of the cursor
if (!X11::CheckCookie(
connection,
xcb_create_cursor(
connection,
hiddenCursor,
cursorPixmap,
cursorPixmap,
0, 0, 0, // Foreground RGB color
0, 0, 0, // Background RGB color
0, // X
0 // Y
))
)
NazaraError("Failed to create hidden cursor");
}
}
WindowImpl::WindowImpl(Window* parent) :
@ -452,34 +414,13 @@ namespace Nz
}
}
void WindowImpl::SetCursor(Nz::WindowCursor windowCursor)
{
if (windowCursor == Nz::WindowCursor_None)
SetCursor(hiddenCursor);
else
{
const char* name = ConvertWindowCursorToXName(windowCursor);
xcb_cursor_context_t* ctx;
if (xcb_cursor_context_new(connection, m_screen, &ctx) >= 0)
{
xcb_cursor_t cursor = xcb_cursor_load_cursor(ctx, name);
SetCursor(cursor);
xcb_free_cursor(connection, cursor);
xcb_cursor_context_free(ctx);
}
}
}
void WindowImpl::SetCursor(const Cursor& cursor)
{
if (!cursor.IsValid())
{
NazaraError("Cursor is not valid");
return;
}
xcb_cursor_t cursorImpl = cursor.m_impl->GetCursor();
if (!X11::CheckCookie(connection, xcb_change_window_attributes(connection, m_window, XCB_CW_CURSOR, &cursor)))
NazaraError("Failed to change mouse cursor");
SetCursor(cursor.m_impl->GetCursor());
xcb_flush(connection);
}
void WindowImpl::SetEventListener(bool listener)
@ -998,7 +939,7 @@ namespace Nz
}
}
const char* WindowImpl::ConvertWindowCursorToXName(Nz::WindowCursor cursor)
const char* WindowImpl::ConvertWindowCursorToXName(SystemCursor cursor)
{
// http://gnome-look.org/content/preview.php?preview=1&id=128170&file1=128170-1.png&file2=&file3=&name=Dummy+X11+cursors&PHPSESSID=6
switch (cursor)
@ -1444,22 +1385,6 @@ namespace Nz
}
}
void WindowImpl::SetCursor(xcb_cursor_t cursor)
{
if (!X11::CheckCookie(
connection,
xcb_change_window_attributes(
connection,
m_window,
XCB_CW_CURSOR,
&cursor
))
)
NazaraError("Failed to change mouse cursor");
xcb_flush(connection);
}
void WindowImpl::SetMotifHints()
{
ScopedXCB<xcb_generic_error_t> error(nullptr);

View File

@ -60,7 +60,6 @@ namespace Nz
void ProcessEvents(bool block);
void SetCursor(WindowCursor cursor);
void SetCursor(const Cursor& cursor);
void SetEventListener(bool listener);
void SetFocus();
@ -84,7 +83,7 @@ namespace Nz
void CleanUp();
xcb_keysym_t ConvertKeyCodeToKeySym(xcb_keycode_t keycode, uint16_t state);
Keyboard::Key ConvertVirtualKey(xcb_keysym_t symbol);
const char* ConvertWindowCursorToXName(WindowCursor cursor);
const char* ConvertWindowCursorToXName(SystemCursor cursor);
void CommonInitialize();
char32_t GetRepresentation(xcb_keysym_t keysym) const;
@ -93,7 +92,6 @@ namespace Nz
void ResetVideoMode();
void SetCursor(xcb_cursor_t cursor);
void SetMotifHints();
void SetVideoMode(const VideoMode& mode);
void SwitchToFullscreen();