Skip to content

Commit eb248c1

Browse files
committed
Allow cursors to be loaded at full size + Add destroyCursor() method
1 parent 0c4fbd7 commit eb248c1

File tree

5 files changed

+133
-9
lines changed

5 files changed

+133
-9
lines changed

Corona/cursor3.ani

528 KB
Binary file not shown.

Corona/main.lua

Lines changed: 78 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ local cursor = require('plugin.hwcursor')
44
local hidden = false
55
cursor.initPlugin()
66

7-
-- New in this branch
7+
-- New in this version
88

99
-- Call cursor.loadCursor the first time with the path to the cursor
1010
-- and store the return value, which is a pointer to the cursor resource (preload step)
@@ -14,8 +14,9 @@ cursor.initPlugin()
1414

1515
-- Cursors must be preloaded before being used
1616
local cursors = {
17-
cursor1 = cursor.loadCursor(system.pathForFile('cursor1.cur')),
18-
cursor2 = cursor.loadCursor(system.pathForFile('cursor2.ani'))
17+
cursor1 = cursor.loadCursor(system.pathForFile('cursor1.cur')), -- Bigger than normal
18+
cursor2 = cursor.loadCursor(system.pathForFile('cursor2.ani')), -- Regular size
19+
cursor3 = cursor.loadCursor(system.pathForFile('cursor3.ani')) -- Huge (256x256)
1920
}
2021

2122
display.newText(
@@ -80,6 +81,21 @@ widget.newButton(
8081
shape = 'roundedRect',
8182
x = display.contentCenterX,
8283
y = display.contentCenterY + 50,
84+
label = 'Custom cursor 3',
85+
-- Set cursor using stored pointer
86+
onRelease = function() cursor.loadCursor(cursors.cursor3) end,
87+
labelColor = { default = { 1, 1, 1 }, over = { 0, 0, 0, 0.5 } },
88+
fillColor = { default = { 1, 0.2, 0.5, 0.7 }, over = { 1, 0.2, 0.5, 1 } }
89+
}
90+
)
91+
92+
widget.newButton(
93+
{
94+
width = 200,
95+
height = 30,
96+
shape = 'roundedRect',
97+
x = display.contentCenterX,
98+
y = display.contentCenterY + 100,
8399
label = 'Show/Hide cursor',
84100
onRelease = function()
85101
if hidden then
@@ -100,10 +116,14 @@ widget.newButton(
100116
height = 30,
101117
shape = 'roundedRect',
102118
x = display.contentCenterX,
103-
y = display.contentCenterY + 100,
119+
y = display.contentCenterY + 150,
104120
label = 'Exit application',
105121
onRelease = function()
106-
cursor.resetCursor()
122+
-- Destroy all cursors before exiting
123+
for k, v in pairs(cursors) do
124+
cursor.destroyCursor(v)
125+
cursors[k] = nil
126+
end
107127
cursor.freePlugin()
108128
native.requestExit()
109129
end,
@@ -112,6 +132,59 @@ widget.newButton(
112132
}
113133
)
114134

135+
--[[
136+
widget.newButton(
137+
{
138+
width = 200,
139+
height = 30,
140+
shape = 'roundedRect',
141+
x = display.contentCenterX,
142+
y = display.contentCenterY + 200,
143+
label = 'Destroy cursor 1',
144+
onRelease = function()
145+
cursor.destroyCursor(cursors.cursor1)
146+
cursors.cursor1 = nil
147+
end,
148+
labelColor = { default = { 1, 1, 1 }, over = { 0, 0, 0, 0.5 } },
149+
fillColor = { default = { 1, 0.2, 0.5, 0.7 }, over = { 1, 0.2, 0.5, 1 } }
150+
}
151+
)
152+
153+
widget.newButton(
154+
{
155+
width = 200,
156+
height = 30,
157+
shape = 'roundedRect',
158+
x = display.contentCenterX,
159+
y = display.contentCenterY + 250,
160+
label = 'Destroy cursor 2',
161+
onRelease = function()
162+
cursor.destroyCursor(cursors.cursor2)
163+
cursors.cursor2 = nil
164+
end,
165+
labelColor = { default = { 1, 1, 1 }, over = { 0, 0, 0, 0.5 } },
166+
fillColor = { default = { 1, 0.2, 0.5, 0.7 }, over = { 1, 0.2, 0.5, 1 } }
167+
}
168+
)
169+
170+
widget.newButton(
171+
{
172+
width = 200,
173+
height = 30,
174+
shape = 'roundedRect',
175+
x = display.contentCenterX,
176+
y = display.contentCenterY + 300,
177+
label = 'Destroy cursor 3',
178+
onRelease = function()
179+
cursor.destroyCursor(cursors.cursor3)
180+
cursors.cursor3 = nil
181+
end,
182+
labelColor = { default = { 1, 1, 1 }, over = { 0, 0, 0, 0.5 } },
183+
fillColor = { default = { 1, 0.2, 0.5, 0.7 }, over = { 1, 0.2, 0.5, 1 } }
184+
}
185+
)
186+
]]--
187+
115188
Runtime:addEventListener('key',
116189
function(event)
117190
if event.phase == 'up' then

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Refer to example project in ```Corona/``` directory
1212
- ```showCursor``` - shows the cursor if it was hidden
1313
- ```hideCursor``` - hides the cursor if it was visible
1414
- ```resetCursor``` - resets the cursor to the default arrow cursor
15+
- ```destroyCursor``` - destroys the cursor handle and frees its memory
1516
- ```loadWinCursor``` - loads the specified windows-provided cursor
1617

1718
# Valid arguments to loadWinCursor()
@@ -37,4 +38,5 @@ Refer to example project in ```Corona/``` directory
3738

3839
# Caveats
3940
- Only supports windows for now
41+
- Destroy preloaded cursors before exiting the application programmatically. Call ```plugin.destroyCursor(cursor)```.
4042
- You must call ```plugin.freePlugin()``` while exiting the application programmatically. An example of how this should be done is provided.

shared/PluginHwCursor.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ int luaopen_plugin_hwcursor(lua_State *L) {
2929
{"showCursor", showCursor},
3030
{"hideCursor", hideCursor},
3131
{"resetCursor", resetCursor},
32+
{"destroyCursor", destroyCursor},
3233
{"loadWinCursor", loadWinCursor},
3334
{"regExitCallback", regExitCallback},
3435
{NULL, NULL}
@@ -63,12 +64,12 @@ LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
6364
if(exitCallback != 0) {
6465
lua_rawgeti(state, LUA_REGISTRYINDEX, exitCallback);
6566
if(lua_pcall(state, 0, 0, 0) != 0) {
66-
CoronaLuaLog(state, "[hwcursor] the error below occurred while calling the callback function");
67-
CoronaLuaLog(state, lua_tostring(state, -1));
67+
CoronaLuaError(state, "[hwcursor] The error below occurred while calling the callback function");
68+
CoronaLuaError(state, lua_tostring(state, -1));
6869
}
6970
}
7071
else {
71-
CoronaLuaLog(state, "[hwcursor] no exit callback was found");
72+
CoronaLuaError(state, "[hwcursor] No exit callback was found");
7273
}
7374

7475
return false;
@@ -106,7 +107,9 @@ static int loadCursor(lua_State *L) {
106107
}
107108
else {
108109
std::string cursorLoc = lua_tostring(L, 1);
109-
HCURSOR cursor = LoadCursorFromFile(s2ws(cursorLoc).c_str());
110+
// Allows for actual cursor size to be used with no constraints, i.e: even 256x256 size cursors will display at this
111+
// size with no downsizing being performed as happens with LoadCursorFromFile
112+
HCURSOR cursor = (HCURSOR)LoadImage(NULL, s2ws(cursorLoc).c_str(), IMAGE_CURSOR, 0, 0, LR_LOADFROMFILE);
110113
lua_pushlightuserdata(L, cursor);
111114
return 1;
112115
}
@@ -136,6 +139,25 @@ static int hideCursor(lua_State *L) {
136139

137140
static int resetCursor(lua_State *L) {
138141
currentCursor = NULL;
142+
SetCursor(currentCursor);
143+
return 0;
144+
}
145+
146+
// ----------------------------------------------------------------------------
147+
148+
static int destroyCursor(lua_State *L) {
149+
HCURSOR cursor = (HCURSOR)lua_touserdata(L, 1);
150+
if(cursor == currentCursor) {
151+
currentCursor = NULL;
152+
SetCursor(currentCursor);
153+
}
154+
DestroyCursor(cursor);
155+
/*
156+
if(!DestroyCursor(cursor)) {
157+
CoronaLuaError(L, "[hwcursor] The error below occurred while destroying the cursor");
158+
CoronaLuaError(L, GetLastErrorAsString().c_str());
159+
}
160+
*/
139161
return 0;
140162
}
141163

shared/PluginHwCursor.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ static int loadCursor(lua_State *L);
3131
static int showCursor(lua_State *L);
3232
static int hideCursor(lua_State *L);
3333
static int resetCursor(lua_State *L);
34+
static int destroyCursor(lua_State *L);
3435
static int loadWinCursor(lua_State *L);
3536
static int regExitCallback(lua_State *L);
3637

@@ -45,3 +46,29 @@ std::wstring s2ws(const std::string &s) {
4546
MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, const_cast<wchar_t*>(buf.c_str()), len);
4647
return buf;
4748
}
49+
50+
// ----------------------------------------------------------------------------
51+
// https://stackoverflow.com/a/17387176
52+
/*
53+
std::string GetLastErrorAsString() {
54+
//Get the error message ID, if any.
55+
DWORD errorMessageID = GetLastError();
56+
if(errorMessageID == 0) {
57+
return std::string(); //No error message has been recorded
58+
}
59+
60+
LPSTR messageBuffer = nullptr;
61+
62+
//Ask Win32 to give us the string version of that message ID.
63+
//The parameters we pass in, tell Win32 to create the buffer that holds the message for us (because we don't yet know how long the message string will be).
64+
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
65+
66+
//Copy the error message into a std::string.
67+
std::string message(messageBuffer, size);
68+
69+
//Free the Win32's string's buffer.
70+
LocalFree(messageBuffer);
71+
72+
return message;
73+
}
74+
*/

0 commit comments

Comments
 (0)