Implement reusable cursors on macOS
parent
6c4c406211
commit
3d501ef57e
|
@ -291,6 +291,75 @@ static int is_cursor_locked(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int cursor_metatable;
|
||||
|
||||
static void *load_custom_cursor(lua_State *L, int index)
|
||||
{
|
||||
#ifdef DM_PLATFORM_WINDOWS
|
||||
const char *cursor_path_lua = luaL_checkstring(L, index);
|
||||
return defos_load_cursor_win(cursor_path_lua);
|
||||
#endif
|
||||
|
||||
#ifdef DM_PLATFORM_LINUX
|
||||
const char *cursor_path_lua = luaL_checkstring(L, index);
|
||||
return defos_load_cursor_linux(cursor_path_lua);
|
||||
return 0;
|
||||
|
||||
// TODO: X11 support animated cursor by XRender
|
||||
#endif
|
||||
|
||||
#ifdef DM_PLATFORM_OSX
|
||||
luaL_checktype(L, index, LUA_TTABLE);
|
||||
|
||||
lua_getfield(L, index, "hot_spot_x");
|
||||
float hotSpotX = 0.0f;
|
||||
if (!lua_isnil(L, -1))
|
||||
{
|
||||
hotSpotX = luaL_checknumber(L, -1);
|
||||
}
|
||||
|
||||
lua_getfield(L, index, "hot_spot_y");
|
||||
float hotSpotY = 0.0f;
|
||||
if (!lua_isnil(L, -1))
|
||||
{
|
||||
hotSpotY = luaL_checknumber(L, -1);
|
||||
}
|
||||
|
||||
lua_getfield(L, index, "image");
|
||||
dmBuffer::HBuffer image = dmScript::CheckBuffer(L, -1)->m_Buffer;
|
||||
|
||||
void *cursor = defos_load_cursor_mac(image, hotSpotX, hotSpotY);
|
||||
lua_pop(L, 3);
|
||||
return cursor;
|
||||
#endif
|
||||
|
||||
#ifdef DM_PLATFORM_HTML5
|
||||
const char * cursor_url = luaL_checkstring(L, 1);
|
||||
return defos_load_cursor_html5(cursor_url);
|
||||
#endif
|
||||
|
||||
lua_pushstring(L, "Invalid argument");
|
||||
lua_error(L);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int load_cursor(lua_State *L)
|
||||
{
|
||||
void ** userdata = (void**)lua_newuserdata(L, sizeof(void*));
|
||||
*userdata = load_custom_cursor(L, 1);
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, cursor_metatable);
|
||||
lua_setmetatable(L, -2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int gc_cursor(lua_State *L)
|
||||
{
|
||||
luaL_checktype(L, 1, LUA_TUSERDATA);
|
||||
void **cursor = (void**)lua_touserdata(L, 1);
|
||||
defos_gc_custom_cursor(*cursor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_cursor(lua_State *L)
|
||||
{
|
||||
if (lua_isnil(L, 1))
|
||||
|
@ -306,53 +375,16 @@ static int set_cursor(lua_State *L)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DM_PLATFORM_WINDOWS
|
||||
const char *cursor_path_lua = luaL_checkstring(L, 1);
|
||||
defos_set_custom_cursor_win(cursor_path_lua);
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
#ifdef DM_PLATFORM_LINUX
|
||||
const char *cursor_path_lua = luaL_checkstring(L,1);
|
||||
defos_set_custom_cursor_linux(cursor_path_lua);
|
||||
return 0;
|
||||
|
||||
// TODO: X11 support animated cursor by XRender
|
||||
#endif
|
||||
|
||||
#ifdef DM_PLATFORM_OSX
|
||||
luaL_checktype(L, 1, LUA_TTABLE);
|
||||
|
||||
lua_getfield(L, 1, "hot_spot_x");
|
||||
float hotSpotX = 0.0f;
|
||||
if (!lua_isnil(L, -1))
|
||||
if (lua_isuserdata(L, 1))
|
||||
{
|
||||
hotSpotX = luaL_checknumber(L, -1);
|
||||
void **cursor = (void**)lua_touserdata(L, 1);
|
||||
defos_set_custom_cursor(*cursor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lua_getfield(L, 1, "hot_spot_y");
|
||||
float hotSpotY = 0.0f;
|
||||
if (!lua_isnil(L, -1))
|
||||
{
|
||||
hotSpotY = luaL_checknumber(L, -1);
|
||||
}
|
||||
|
||||
lua_getfield(L, 1, "image");
|
||||
dmBuffer::HBuffer image = dmScript::CheckBuffer(L, -1)->m_Buffer;
|
||||
|
||||
defos_set_custom_cursor_mac(image, hotSpotX, hotSpotY);
|
||||
lua_pop(L, 3);
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
#ifdef DM_PLATFORM_HTML5
|
||||
const char * cursor_url = luaL_checkstring(L, 1);
|
||||
defos_set_custom_cursor_html5(cursor_url);
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
lua_pushstring(L, "Invalid argument");
|
||||
lua_error(L);
|
||||
void *custom_cursor = load_custom_cursor(L, 1);
|
||||
defos_set_custom_cursor(custom_cursor);
|
||||
defos_gc_custom_cursor(custom_cursor);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -604,6 +636,7 @@ static const luaL_reg Module_methods[] =
|
|||
{"get_view_size", get_view_size},
|
||||
{"set_cursor", set_cursor},
|
||||
{"reset_cursor", reset_cursor},
|
||||
{"load_cursor", load_cursor},
|
||||
{"get_displays", get_displays},
|
||||
{"get_display_modes", get_display_modes},
|
||||
{"get_current_display_id", get_current_display_id},
|
||||
|
@ -635,6 +668,11 @@ static void LuaInit(lua_State *L)
|
|||
lua_setfield(L, -2, "PATH_SEP");
|
||||
#endif
|
||||
|
||||
lua_newtable(L);
|
||||
lua_pushcfunction(L, gc_cursor);
|
||||
lua_setfield(L, -2, "__gc");
|
||||
cursor_metatable = dmScript::Ref(L, LUA_REGISTRYINDEX);
|
||||
|
||||
lua_pop(L, 1);
|
||||
assert(top == lua_gettop(L));
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ void defos_init() {
|
|||
// [window disableCursorRects];
|
||||
// [window resetCursorRects];
|
||||
default_cursor = NSCursor.arrowCursor;
|
||||
[default_cursor retain];
|
||||
current_cursor = default_cursor;
|
||||
[current_cursor retain];
|
||||
enable_mouse_tracking();
|
||||
|
@ -60,8 +61,10 @@ void defos_init() {
|
|||
|
||||
void defos_final() {
|
||||
disable_mouse_tracking();
|
||||
[default_cursor release];
|
||||
[current_cursor release];
|
||||
current_cursor = nil;
|
||||
default_cursor = nil;
|
||||
}
|
||||
|
||||
void defos_update() {
|
||||
|
@ -338,24 +341,37 @@ bool defos_is_cursor_locked() {
|
|||
return is_cursor_locked;
|
||||
}
|
||||
|
||||
void defos_set_custom_cursor_mac(dmBuffer::HBuffer buffer, float hotSpotX, float hotSpotY) {
|
||||
uint8_t* bytes = NULL;
|
||||
uint32_t size = 0;
|
||||
if (dmBuffer::GetBytes(buffer, (void**)&bytes, &size) != dmBuffer::RESULT_OK) {
|
||||
dmLogError("defos_set_custom_cursor_mac: dmBuffer::GetBytes failed");
|
||||
return;
|
||||
void *defos_load_cursor_mac(dmBuffer::HBuffer buffer, float hotSpotX, float hotSpotY) {
|
||||
@autoreleasepool {
|
||||
uint8_t* bytes = NULL;
|
||||
uint32_t size = 0;
|
||||
if (dmBuffer::GetBytes(buffer, (void**)&bytes, &size) != dmBuffer::RESULT_OK) {
|
||||
dmLogError("defos_set_custom_cursor_mac: dmBuffer::GetBytes failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t* copy = (uint8_t*)malloc(size);
|
||||
memcpy(copy, bytes, size);
|
||||
NSData * data = [[NSData alloc] initWithBytesNoCopy:copy length:size freeWhenDone:YES];
|
||||
NSImage * image = [[NSImage alloc] initWithData:data];
|
||||
NSCursor * cursor = [[NSCursor alloc] initWithImage:image hotSpot:NSMakePoint(hotSpotX, hotSpotY)];
|
||||
|
||||
[image release];
|
||||
[data release];
|
||||
return cursor;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* copy = (uint8_t*)malloc(size);
|
||||
memcpy(copy, bytes, size);
|
||||
NSData * data = [[NSData alloc] initWithBytesNoCopy:copy length:size freeWhenDone:YES];
|
||||
void defos_gc_custom_cursor(void * _cursor) {
|
||||
NSCursor * cursor = (NSCursor*)_cursor;
|
||||
[cursor release];
|
||||
}
|
||||
|
||||
NSImage * image = [[NSImage alloc] initWithData:data];
|
||||
NSCursor * cursor = [[NSCursor alloc] initWithImage:image hotSpot:NSMakePoint(hotSpotX, hotSpotY)];
|
||||
void defos_set_custom_cursor(void * _cursor) {
|
||||
NSCursor * cursor = (NSCursor*)_cursor;
|
||||
[cursor retain];
|
||||
[current_cursor release];
|
||||
current_cursor = cursor;
|
||||
[image release];
|
||||
[data release];
|
||||
[current_cursor set];
|
||||
}
|
||||
|
||||
|
@ -376,10 +392,10 @@ static NSCursor * get_cursor(DefosCursor cursor) {
|
|||
|
||||
void defos_set_cursor(DefosCursor cur) {
|
||||
NSCursor * cursor = get_cursor(cur);
|
||||
[cursor set];
|
||||
[cursor retain];
|
||||
[current_cursor release];
|
||||
current_cursor = cursor;
|
||||
[current_cursor set];
|
||||
}
|
||||
|
||||
void defos_reset_cursor() {
|
||||
|
|
|
@ -107,10 +107,12 @@ extern bool defos_is_cursor_clipped();
|
|||
extern void defos_set_cursor_locked(bool locked);
|
||||
extern bool defos_is_cursor_locked();
|
||||
|
||||
extern void defos_set_custom_cursor_html5(const char *url);
|
||||
extern void defos_set_custom_cursor_win(const char *filename);
|
||||
extern void defos_set_custom_cursor_mac(dmBuffer::HBuffer buffer, float hotSpotX, float hotSpotY);
|
||||
extern void defos_set_custom_cursor_linux(const char *filename);
|
||||
extern void *defos_load_cursor_html5(const char *url);
|
||||
extern void *defos_load_cursor_win(const char *filename);
|
||||
extern void *defos_load_cursor_mac(dmBuffer::HBuffer buffer, float hotSpotX, float hotSpotY);
|
||||
extern void *defos_load_cursor_linux(const char *filename);
|
||||
extern void defos_gc_custom_cursor(void *cursor);
|
||||
extern void defos_set_custom_cursor(void *cursor);
|
||||
extern void defos_set_cursor(DefosCursor cursor);
|
||||
extern void defos_reset_cursor();
|
||||
|
||||
|
|
|
@ -47,26 +47,26 @@ function init(self)
|
|||
if system_name == "Linux" then
|
||||
-- NOTE: since Defold cannot load resource without extension, we added .xcur here.
|
||||
-- NOTE: cursor should be normal x11 cursor file that type is: image/x-xcursor
|
||||
table.insert(self.cursors, extract_to_savefolder("cursor.xcur"))
|
||||
table.insert(self.cursors, defos.load_cursor(extract_to_savefolder("cursor.xcur")))
|
||||
end
|
||||
|
||||
if system_name == "Windows" then
|
||||
for i, v in ipairs({"cursor_01.ani", "cursor_02.ani" }) do
|
||||
-- load source file and write them to save folder, so that we can access them with fullpath, or you can use bundle_resource
|
||||
table.insert(self.cursors, extract_to_savefolder(v))
|
||||
table.insert(self.cursors, defos.load_cursor(extract_to_savefolder(v)))
|
||||
end
|
||||
end
|
||||
|
||||
if system_name == "Darwin" then
|
||||
table.insert(self.cursors, {
|
||||
table.insert(self.cursors, defos.load_cursor({
|
||||
image = resource.load("/resources/cursor_mac.tiff"),
|
||||
hot_spot_x = 18,
|
||||
hot_spot_y = 2,
|
||||
})
|
||||
}))
|
||||
end
|
||||
|
||||
if system_name == "HTML5" then
|
||||
table.insert(self.cursors, cursor_url)
|
||||
table.insert(self.cursors, defos.load_cursor(cursor_url))
|
||||
end
|
||||
|
||||
defos.on_mouse_enter(function ()
|
||||
|
|
Loading…
Reference in New Issue