diff --git a/TODO b/TODO index d02f73dc..34ccb900 100644 --- a/TODO +++ b/TODO @@ -41,8 +41,6 @@ review usage of x,y/width,height in lua instead of point/size == Platform port to MacOs and iphone -change win32 mouse cursor icon -rework win32 key input system == UI [bart] multiline rich text widget diff --git a/modules/core_lib/cursor.lua b/modules/core_lib/cursor.lua index 63f7e88b..ed6e83c8 100644 --- a/modules/core_lib/cursor.lua +++ b/modules/core_lib/cursor.lua @@ -1,5 +1,5 @@ function setTargetCursor() - g_window.setMouseCursor('/core_styles/icons/targetcursor.png') + g_window.setMouseCursor('/core_styles/icons/targetcursor.png', {x=9,y=9}) end function restoreCursor() diff --git a/modules/core_styles/icons/targetcursor.png b/modules/core_styles/icons/targetcursor.png index 92c9d4f2..3ce607ba 100644 Binary files a/modules/core_styles/icons/targetcursor.png and b/modules/core_styles/icons/targetcursor.png differ diff --git a/modules/core_widgets/uiitem.lua b/modules/core_widgets/uiitem.lua index 292d7118..559876ed 100644 --- a/modules/core_widgets/uiitem.lua +++ b/modules/core_widgets/uiitem.lua @@ -1,7 +1,7 @@ function UIItem:onDragEnter(mousePos) local item = self:getItem() if not item then return false end - + self.currentDragThing = item setTargetCursor() return true @@ -15,10 +15,10 @@ end function UIItem:onDrop(widget, mousePos) if not widget or not widget.currentDragThing then return false end - + local pos = self.position local count = 1 -- todo make a window for it - + Game.move(widget.currentDragThing, pos, count) return true end diff --git a/src/framework/luafunctions.cpp b/src/framework/luafunctions.cpp index 9dd02eaf..b3d240d7 100644 --- a/src/framework/luafunctions.cpp +++ b/src/framework/luafunctions.cpp @@ -391,7 +391,7 @@ void Application::registerLuaFunctions() g_lua.bindClassStaticFunction("g_window", "showMouse", std::bind(&PlatformWindow::showMouse, &g_window)); g_lua.bindClassStaticFunction("g_window", "hideMouse", std::bind(&PlatformWindow::hideMouse, &g_window)); g_lua.bindClassStaticFunction("g_window", "setTitle", std::bind(&PlatformWindow::setTitle, &g_window, _1)); - g_lua.bindClassStaticFunction("g_window", "setMouseCursor", std::bind(&PlatformWindow::setMouseCursor, &g_window, _1)); + g_lua.bindClassStaticFunction("g_window", "setMouseCursor", std::bind(&PlatformWindow::setMouseCursor, &g_window, _1, _2)); g_lua.bindClassStaticFunction("g_window", "setMinimumSize", std::bind(&PlatformWindow::setMinimumSize, &g_window, _1)); g_lua.bindClassStaticFunction("g_window", "setFullscreen", std::bind(&PlatformWindow::setFullscreen, &g_window, _1)); g_lua.bindClassStaticFunction("g_window", "setVerticalSync", std::bind(&PlatformWindow::setVerticalSync, &g_window, _1)); diff --git a/src/framework/platform/platformwindow.h b/src/framework/platform/platformwindow.h index 66c75516..dd3d92f0 100644 --- a/src/framework/platform/platformwindow.h +++ b/src/framework/platform/platformwindow.h @@ -53,7 +53,7 @@ public: virtual void hideMouse() = 0; virtual void displayFatalError(const std::string& message) { } - virtual void setMouseCursor(const std::string& file) = 0; + virtual void setMouseCursor(const std::string& file, const Point& hotSpot) = 0; virtual void setTitle(const std::string& title) = 0; virtual void setMinimumSize(const Size& minimumSize) = 0; virtual void setFullscreen(bool fullscreen) = 0; diff --git a/src/framework/platform/win32window.cpp b/src/framework/platform/win32window.cpp index 82332085..eb9421b8 100644 --- a/src/framework/platform/win32window.cpp +++ b/src/framework/platform/win32window.cpp @@ -33,6 +33,7 @@ WIN32Window::WIN32Window() m_instance = 0; m_deviceContext = 0; m_glContext = 0; + m_cursor = 0; m_maximized = false; m_minimumSize = Size(16,16); m_size = m_minimumSize; @@ -226,6 +227,11 @@ void WIN32Window::terminate() m_deviceContext = NULL; } + if(m_cursor) { + DestroyCursor(m_cursor); + m_cursor = NULL; + } + if(m_window) { if(!DestroyWindow(m_window)) logError("ERROR: Destroy window failed."); @@ -248,6 +254,7 @@ struct WindowProcProxy { void WIN32Window::internalRegisterWindowClass() { + m_defaultCursor = LoadCursor(NULL, IDC_ARROW); WNDCLASSA wc; wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wc.lpfnWndProc = (WNDPROC)WindowProcProxy::call; @@ -255,7 +262,7 @@ void WIN32Window::internalRegisterWindowClass() wc.cbWndExtra = 0; wc.hInstance = m_instance; wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); - wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hCursor = m_defaultCursor; wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = g_app->getAppName().c_str(); @@ -352,12 +359,16 @@ void *WIN32Window::getExtensionProcAddress(const char *ext) void WIN32Window::move(const Point& pos) { - MoveWindow(m_window, pos.x, pos.y, m_size.width(), m_size.height(), TRUE); + RECT windowRect = {pos.x, pos.y, m_pos.x + m_size.width(), m_pos.y + m_size.height()}; + AdjustWindowRectEx(&windowRect, WS_OVERLAPPEDWINDOW, FALSE, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE); + MoveWindow(m_window, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, TRUE); } void WIN32Window::resize(const Size& size) { - MoveWindow(m_window, m_pos.x, m_pos.y, size.width(), size.height(), TRUE); + RECT windowRect = {m_pos.x, m_pos.y, m_pos.x + size.width(), m_pos.y + size.height()}; + AdjustWindowRectEx(&windowRect, WS_OVERLAPPEDWINDOW, FALSE, WS_EX_APPWINDOW | WS_EX_WINDOWEDGE); + MoveWindow(m_window, windowRect.left, windowRect.top, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, TRUE); } void WIN32Window::show() @@ -399,6 +410,13 @@ LRESULT WIN32Window::windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar { switch(uMsg) { + case WM_SETCURSOR: { + if(m_cursor) + SetCursor(m_cursor); + else + SetCursor(m_defaultCursor); + break; + } case WM_ACTIVATE: { m_focused = !(wParam == WA_INACTIVE); break; @@ -518,16 +536,24 @@ void WIN32Window::swapBuffers() void WIN32Window::restoreMouseCursor() { - //TODO + logTraceDebug(); + if(m_cursor) { + DestroyCursor(m_cursor); + m_cursor = NULL; + SetCursor(m_defaultCursor); + ShowCursor(true); + } } void WIN32Window::showMouse() { + logTraceDebug(); ShowCursor(true); } void WIN32Window::hideMouse() { + logTraceDebug(); ShowCursor(false); } @@ -536,9 +562,60 @@ void WIN32Window::displayFatalError(const std::string& message) MessageBoxA(m_window, message.c_str(), "FATAL ERROR", MB_OK | MB_ICONERROR); } -void WIN32Window::setMouseCursor(const std::string& file) +#define LSB_BIT_SET(p, n) (p[(n)/8] |= (1 <<((n)%8))) +#define HSB_BIT_SET(p, n) (p[(n)/8] |= (128 >>((n)%8))) + +void WIN32Window::setMouseCursor(const std::string& file, const Point& hotSpot) { + logTraceDebug(); + std::stringstream fin; + g_resources.loadFile(file, fin); + + apng_data apng; + if(load_apng(fin, &apng) != 0) { + logTraceError("unable to load png file ", file); + return; + } + + if(apng.bpp != 4) { + logError("the cursor png must have 4 channels"); + free_apng(&apng); + return; + } + + if(apng.width != 32|| apng.height != 32) { + logError("the cursor png must have 32x32 dimension"); + free_apng(&apng); + return; + } + + if(m_cursor != NULL) + DestroyCursor(m_cursor); + + int width = apng.width; + int height = apng.height; + int numbits = width * height; + int numbytes = (width * height)/8; + + std::vector andMask(numbytes, 0); + std::vector xorMask(numbytes, 0); + + for(int i=0;i