From bcf36e7a14889a3c45d102f3c88b092acd40cad8 Mon Sep 17 00:00:00 2001 From: Lynix Date: Sun, 24 Jun 2012 13:28:24 +0200 Subject: [PATCH] Added support for custom cursor/icon --- build/scripts/module/renderer.lua | 7 ++- build/scripts/module/utility.lua | 1 + include/Nazara/Utility/Cursor.hpp | 35 ++++++++++++++ include/Nazara/Utility/Icon.hpp | 34 ++++++++++++++ include/Nazara/Utility/Window.hpp | 6 +++ src/Nazara/Utility/Cursor.cpp | 61 +++++++++++++++++++++++++ src/Nazara/Utility/Icon.cpp | 56 +++++++++++++++++++++++ src/Nazara/Utility/Win32/CursorImpl.cpp | 52 +++++++++++++++++++++ src/Nazara/Utility/Win32/CursorImpl.hpp | 26 +++++++++++ src/Nazara/Utility/Win32/IconImpl.cpp | 49 ++++++++++++++++++++ src/Nazara/Utility/Win32/IconImpl.hpp | 26 +++++++++++ src/Nazara/Utility/Win32/WindowImpl.cpp | 23 ++++++++-- src/Nazara/Utility/Win32/WindowImpl.hpp | 2 + src/Nazara/Utility/Window.cpp | 35 ++++++++++++++ 14 files changed, 406 insertions(+), 7 deletions(-) create mode 100644 include/Nazara/Utility/Cursor.hpp create mode 100644 include/Nazara/Utility/Icon.hpp create mode 100644 src/Nazara/Utility/Cursor.cpp create mode 100644 src/Nazara/Utility/Icon.cpp create mode 100644 src/Nazara/Utility/Win32/CursorImpl.cpp create mode 100644 src/Nazara/Utility/Win32/CursorImpl.hpp create mode 100644 src/Nazara/Utility/Win32/IconImpl.cpp create mode 100644 src/Nazara/Utility/Win32/IconImpl.hpp diff --git a/build/scripts/module/renderer.lua b/build/scripts/module/renderer.lua index 4945e717e..9529919f7 100644 --- a/build/scripts/module/renderer.lua +++ b/build/scripts/module/renderer.lua @@ -1,9 +1,5 @@ project "NazaraRenderer" -links "gdi32" -links "opengl32" -links "winmm" - files { "../include/Nazara/Renderer/**.hpp", @@ -14,6 +10,9 @@ files if (os.is("windows")) then excludes { "../src/Nazara/Renderer/Posix/*.hpp", "../src/Nazara/Renderer/Posix/*.cpp" } + links "gdi32" + links "opengl32" + links "winmm" else excludes { "../src/Nazara/Renderer/Win32/*.hpp", "../src/Nazara/Renderer/Win32/*.cpp" } end diff --git a/build/scripts/module/utility.lua b/build/scripts/module/utility.lua index 8cadea0b3..183abe974 100644 --- a/build/scripts/module/utility.lua +++ b/build/scripts/module/utility.lua @@ -13,6 +13,7 @@ files if (os.is("windows")) then excludes { "../src/Nazara/Utility/Posix/*.hpp", "../src/Nazara/Utility/Posix/*.cpp" } + links "gdi32" else excludes { "../src/Nazara/Utility/Win32/*.hpp", "../src/Nazara/Utility/Win32/*.cpp" } end diff --git a/include/Nazara/Utility/Cursor.hpp b/include/Nazara/Utility/Cursor.hpp new file mode 100644 index 000000000..56156346f --- /dev/null +++ b/include/Nazara/Utility/Cursor.hpp @@ -0,0 +1,35 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine". +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_CURSOR_HPP +#define NAZARA_CURSOR_HPP + +#include +#include + +class NzCursorImpl; +class NzImage; +class NzWindowImpl; + +class NAZARA_API NzCursor +{ + friend class NzWindowImpl; + + public: + NzCursor(); + ~NzCursor(); + + bool Create(const NzImage& cursor, int hotSpotX = 0, int hotSpotY = 0); + bool Create(const NzImage& cursor, const NzVector2i& hotSpot); + void Destroy(); + + bool IsValid() const; + + private: + NzCursorImpl* m_impl; +}; + +#endif // NAZARA_CURSOR_HPP diff --git a/include/Nazara/Utility/Icon.hpp b/include/Nazara/Utility/Icon.hpp new file mode 100644 index 000000000..fa724a62c --- /dev/null +++ b/include/Nazara/Utility/Icon.hpp @@ -0,0 +1,34 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine". +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_ICON_HPP +#define NAZARA_ICON_HPP + +#include +#include + +class NzImage; +class NzIconImpl; +class NzWindowImpl; + +class NAZARA_API NzIcon +{ + friend class NzWindowImpl; + + public: + NzIcon(); + ~NzIcon(); + + bool Create(const NzImage& icon); + void Destroy(); + + bool IsValid() const; + + private: + NzIconImpl* m_impl; +}; + +#endif // NAZARA_ICON_HPP diff --git a/include/Nazara/Utility/Window.hpp b/include/Nazara/Utility/Window.hpp index d30a9956d..16c258739 100644 --- a/include/Nazara/Utility/Window.hpp +++ b/include/Nazara/Utility/Window.hpp @@ -24,6 +24,7 @@ #include #endif +class NzImage; class NzUtility; class NzWindowImpl; @@ -62,6 +63,9 @@ enum nzWindowStyle nzWindowStyle_Default = nzWindowStyle_Closable | nzWindowStyle_Resizable | nzWindowStyle_Titlebar }; +class NzCursor; +class NzIcon; + class NAZARA_API NzWindow : NzNonCopyable { friend class NzUtility; @@ -97,8 +101,10 @@ class NAZARA_API NzWindow : NzNonCopyable bool PollEvent(NzEvent* event); void SetCursor(nzWindowCursor cursor); + void SetCursor(const NzCursor& cursor); void SetEventListener(bool listener); void SetFocus(); + void SetIcon(const NzIcon& icon); void SetMaximumSize(const NzVector2i& maxSize); void SetMaximumSize(int width, int height); void SetMinimumSize(const NzVector2i& minSize); diff --git a/src/Nazara/Utility/Cursor.cpp b/src/Nazara/Utility/Cursor.cpp new file mode 100644 index 000000000..f19b61cae --- /dev/null +++ b/src/Nazara/Utility/Cursor.cpp @@ -0,0 +1,61 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine". +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include + +#if defined(NAZARA_PLATFORM_WINDOWS) + #include +#elif defined(NAZARA_PLATFORM_LINUX) + #include +#else + #error Lack of implementation: Cursor +#endif + +#include + +NzCursor::NzCursor() : +m_impl(nullptr) +{ +} + +NzCursor::~NzCursor() +{ + Destroy(); +} + +bool NzCursor::Create(const NzImage& cursor, int hotSpotX, int hotSpotY) +{ + Destroy(); + + m_impl = new NzCursorImpl; + if (!m_impl->Create(cursor, hotSpotX, hotSpotY)) + { + NazaraError("Failed to create cursor implementation"); + delete m_impl; + m_impl = nullptr; + return false; + } + + return true; +} + +bool NzCursor::Create(const NzImage& cursor, const NzVector2i& hotSpot) +{ + return Create(cursor, hotSpot.x, hotSpot.y); +} + +void NzCursor::Destroy() +{ + if (m_impl) + { + m_impl->Destroy(); + delete m_impl; + m_impl = nullptr; + } +} + +bool NzCursor::IsValid() const +{ + return m_impl != nullptr; +} diff --git a/src/Nazara/Utility/Icon.cpp b/src/Nazara/Utility/Icon.cpp new file mode 100644 index 000000000..9d9c3bde3 --- /dev/null +++ b/src/Nazara/Utility/Icon.cpp @@ -0,0 +1,56 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine". +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include + +#if defined(NAZARA_PLATFORM_WINDOWS) + #include +#elif defined(NAZARA_PLATFORM_LINUX) + #include +#else + #error Lack of implementation: Icon +#endif + +#include + +NzIcon::NzIcon() : +m_impl(nullptr) +{ +} + +NzIcon::~NzIcon() +{ + Destroy(); +} + +bool NzIcon::Create(const NzImage& icon) +{ + Destroy(); + + m_impl = new NzIconImpl; + if (!m_impl->Create(icon)) + { + NazaraError("Failed to create cursor implementation"); + delete m_impl; + m_impl = nullptr; + return false; + } + + return true; +} + +void NzIcon::Destroy() +{ + if (m_impl) + { + m_impl->Destroy(); + delete m_impl; + m_impl = nullptr; + } +} + +bool NzIcon::IsValid() const +{ + return m_impl != nullptr; +} diff --git a/src/Nazara/Utility/Win32/CursorImpl.cpp b/src/Nazara/Utility/Win32/CursorImpl.cpp new file mode 100644 index 000000000..5461bac51 --- /dev/null +++ b/src/Nazara/Utility/Win32/CursorImpl.cpp @@ -0,0 +1,52 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine". +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include +#include + +bool NzCursorImpl::Create(const NzImage& cursor, int hotSpotX, int hotSpotY) +{ + NzImage windowsCursor(cursor); + if (!windowsCursor.Convert(nzPixelFormat_BGRA8)) + { + NazaraError("Failed to convert cursor to BGRA8"); + return false; + } + + HBITMAP bitmap = CreateBitmap(windowsCursor.GetWidth(), windowsCursor.GetHeight(), 1, 32, windowsCursor.GetConstPixels()); + HBITMAP monoBitmap = CreateBitmap(windowsCursor.GetWidth(), windowsCursor.GetHeight(), 1, 1, nullptr); + + // http://msdn.microsoft.com/en-us/library/windows/desktop/ms648052(v=vs.85).aspx + ICONINFO iconInfo; + iconInfo.fIcon = FALSE; + iconInfo.xHotspot = hotSpotX; + iconInfo.yHotspot = hotSpotY; + iconInfo.hbmMask = monoBitmap; + iconInfo.hbmColor = bitmap; + + m_cursor = CreateIconIndirect(&iconInfo); + + DeleteObject(bitmap); + DeleteObject(monoBitmap); + + if (!m_cursor) + { + NazaraError("Failed to create cursor: " + NzGetLastSystemError()); + return false; + } + + return true; +} + +void NzCursorImpl::Destroy() +{ + DestroyIcon(m_cursor); +} + +HCURSOR NzCursorImpl::GetCursor() +{ + return m_cursor; +} diff --git a/src/Nazara/Utility/Win32/CursorImpl.hpp b/src/Nazara/Utility/Win32/CursorImpl.hpp new file mode 100644 index 000000000..ba9fa63b7 --- /dev/null +++ b/src/Nazara/Utility/Win32/CursorImpl.hpp @@ -0,0 +1,26 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine". +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_CURSORIMPL_HPP +#define NAZARA_CURSORIMPL_HPP + +#include + +class NzImage; + +class NzCursorImpl +{ + public: + bool Create(const NzImage& image, int hotSpotX, int hotSpotY); + void Destroy(); + + HCURSOR GetCursor(); + + private: + HICON m_cursor = nullptr; +}; + +#endif // NAZARA_CURSORIMPL_HPP diff --git a/src/Nazara/Utility/Win32/IconImpl.cpp b/src/Nazara/Utility/Win32/IconImpl.cpp new file mode 100644 index 000000000..b0f383cf2 --- /dev/null +++ b/src/Nazara/Utility/Win32/IconImpl.cpp @@ -0,0 +1,49 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine". +// For conditions of distribution and use, see copyright notice in Config.hpp + +#include +#include +#include + +bool NzIconImpl::Create(const NzImage& icon) +{ + NzImage windowsIcon(icon); + if (!windowsIcon.Convert(nzPixelFormat_BGRA8)) + { + NazaraError("Failed to convert icon to BGRA8"); + return false; + } + + HBITMAP bitmap = CreateBitmap(windowsIcon.GetWidth(), windowsIcon.GetHeight(), 1, 32, windowsIcon.GetConstPixels()); + HBITMAP monoBitmap = CreateBitmap(windowsIcon.GetWidth(), windowsIcon.GetHeight(), 1, 1, nullptr); + + // http://msdn.microsoft.com/en-us/library/windows/desktop/ms648052(v=vs.85).aspx + ICONINFO iconInfo; + iconInfo.fIcon = TRUE; + iconInfo.hbmMask = monoBitmap; + iconInfo.hbmColor = bitmap; + + m_icon = CreateIconIndirect(&iconInfo); + + DeleteObject(bitmap); + DeleteObject(monoBitmap); + + if (!m_icon) + { + NazaraError("Failed to create icon: " + NzGetLastSystemError()); + return false; + } + + return true; +} + +void NzIconImpl::Destroy() +{ + DestroyIcon(m_icon); +} + +HICON NzIconImpl::GetIcon() +{ + return m_icon; +} diff --git a/src/Nazara/Utility/Win32/IconImpl.hpp b/src/Nazara/Utility/Win32/IconImpl.hpp new file mode 100644 index 000000000..9747283c3 --- /dev/null +++ b/src/Nazara/Utility/Win32/IconImpl.hpp @@ -0,0 +1,26 @@ +// Copyright (C) 2012 Jérôme Leclercq +// This file is part of the "Nazara Engine". +// For conditions of distribution and use, see copyright notice in Config.hpp + +#pragma once + +#ifndef NAZARA_ICONIMPL_HPP +#define NAZARA_ICONIMPL_HPP + +#include + +class NzImage; + +class NzIconImpl +{ + public: + bool Create(const NzImage& image); + void Destroy(); + + HICON GetIcon(); + + private: + HICON m_icon = nullptr; +}; + +#endif // NAZARA_ICONIMPL_HPP diff --git a/src/Nazara/Utility/Win32/WindowImpl.cpp b/src/Nazara/Utility/Win32/WindowImpl.cpp index 1039daef1..293d0feeb 100644 --- a/src/Nazara/Utility/Win32/WindowImpl.cpp +++ b/src/Nazara/Utility/Win32/WindowImpl.cpp @@ -12,6 +12,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include #include @@ -274,9 +279,6 @@ bool NzWindowImpl::IsVisible() const void NzWindowImpl::SetCursor(nzWindowCursor cursor) { - // 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 - switch (cursor) { case nzWindowCursor_Crosshair: @@ -337,9 +339,16 @@ void NzWindowImpl::SetCursor(nzWindowCursor cursor) break; } + // 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 NzWindowImpl::SetCursor(const NzCursor& cursor) +{ + m_cursor = cursor.m_impl->GetCursor(); +} + void NzWindowImpl::SetEventListener(bool listener) { if (m_ownsWindow) @@ -365,6 +374,14 @@ void NzWindowImpl::SetFocus() SetForegroundWindow(m_handle); } +void NzWindowImpl::SetIcon(const NzIcon& icon) +{ + HICON iconHandle = icon.m_impl->GetIcon(); + + SendMessage(m_handle, WM_SETICON, ICON_BIG, reinterpret_cast(iconHandle)); + SendMessage(m_handle, WM_SETICON, ICON_SMALL, reinterpret_cast(iconHandle)); +} + void NzWindowImpl::SetMaximumSize(int width, int height) { RECT rect = {0, 0, width, height}; diff --git a/src/Nazara/Utility/Win32/WindowImpl.hpp b/src/Nazara/Utility/Win32/WindowImpl.hpp index 1a55b0242..16c28b70a 100644 --- a/src/Nazara/Utility/Win32/WindowImpl.hpp +++ b/src/Nazara/Utility/Win32/WindowImpl.hpp @@ -57,8 +57,10 @@ class NzWindowImpl : NzNonCopyable bool IsVisible() const; void SetCursor(nzWindowCursor cursor); + void SetCursor(const NzCursor& cursor); void SetEventListener(bool listener); void SetFocus(); + void SetIcon(const NzIcon& icon); void SetMaximumSize(int width, int height); void SetMinimumSize(int width, int height); void SetPosition(int x, int y); diff --git a/src/Nazara/Utility/Window.cpp b/src/Nazara/Utility/Window.cpp index d9250049e..2c02557db 100644 --- a/src/Nazara/Utility/Window.cpp +++ b/src/Nazara/Utility/Window.cpp @@ -5,11 +5,18 @@ #include #include #include +#include +#include +#include #include #if defined(NAZARA_PLATFORM_WINDOWS) + #include + #include #include #elif defined(NAZARA_PLATFORM_LINUX) + #include + #include #include #else #error Lack of implementation: Window @@ -305,6 +312,20 @@ void NzWindow::SetCursor(nzWindowCursor cursor) m_impl->SetCursor(cursor); } +void NzWindow::SetCursor(const NzCursor& cursor) +{ + #if NAZARA_UTILITY_SAFE + if (!cursor.IsValid()) + { + NazaraError("Cursor is not valid"); + return; + } + #endif + + if (m_impl) + m_impl->SetCursor(cursor); +} + void NzWindow::SetEventListener(bool listener) { if (!m_impl) @@ -337,6 +358,20 @@ void NzWindow::SetFocus() m_impl->SetFocus(); } +void NzWindow::SetIcon(const NzIcon& icon) +{ + #if NAZARA_UTILITY_SAFE + if (!icon.IsValid()) + { + NazaraError("Icon is not valid"); + return; + } + #endif + + if (m_impl) + m_impl->SetIcon(icon); +} + void NzWindow::SetMaximumSize(const NzVector2i& maxSize) { if (m_impl)