mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-29 00:06:44 -04:00
cocoadisplay: Use hotspot read from .cur files
Previously, the cursor's hotspot defaulted to (0,0). Fixes #845. Closes #849
This commit is contained in:
parent
17dddeedc4
commit
4f4b14dd2b
@ -79,8 +79,11 @@ protected:
|
|||||||
virtual void mouse_mode_relative();
|
virtual void mouse_mode_relative();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
NSData *load_image_data(const Filename &filename);
|
||||||
NSImage *load_image(const Filename &filename);
|
NSImage *load_image(const Filename &filename);
|
||||||
|
|
||||||
|
NSCursor *load_cursor(const Filename &filename);
|
||||||
|
|
||||||
void handle_modifier(NSUInteger modifierFlags, NSUInteger mask, ButtonHandle button);
|
void handle_modifier(NSUInteger modifierFlags, NSUInteger mask, ButtonHandle button);
|
||||||
ButtonHandle map_key(unsigned short c) const;
|
ButtonHandle map_key(unsigned short c) const;
|
||||||
ButtonHandle map_raw_key(unsigned short keycode) const;
|
ButtonHandle map_raw_key(unsigned short keycode) const;
|
||||||
@ -104,7 +107,7 @@ private:
|
|||||||
CFDictionaryRef _windowed_mode;
|
CFDictionaryRef _windowed_mode;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef pmap<Filename, NSImage*> IconImages;
|
typedef pmap<Filename, NSData*> IconImages;
|
||||||
IconImages _images;
|
IconImages _images;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -571,17 +571,17 @@ open_window() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (_properties.has_cursor_filename()) {
|
if (_properties.has_cursor_filename()) {
|
||||||
NSImage *image = load_image(_properties.get_cursor_filename());
|
NSCursor *cursor = load_cursor(_properties.get_cursor_filename());
|
||||||
NSCursor *cursor = nil;
|
|
||||||
// TODO: allow setting the hotspot, read it from file when loading .cur.
|
|
||||||
if (image != nil) {
|
|
||||||
cursor = [[NSCursor alloc] initWithImage:image hotSpot:NSMakePoint(0, 0)];
|
|
||||||
}
|
|
||||||
if (cursor != nil) {
|
if (cursor != nil) {
|
||||||
|
if (_cursor != nil) {
|
||||||
|
[_cursor release];
|
||||||
|
}
|
||||||
_cursor = cursor;
|
_cursor = cursor;
|
||||||
} else {
|
} else {
|
||||||
_properties.clear_cursor_filename();
|
_properties.clear_cursor_filename();
|
||||||
}
|
}
|
||||||
|
|
||||||
// This will ensure that NSView's resetCursorRects gets called, which sets
|
// This will ensure that NSView's resetCursorRects gets called, which sets
|
||||||
// the appropriate cursor rects.
|
// the appropriate cursor rects.
|
||||||
[[_view window] invalidateCursorRectsForView:_view];
|
[[_view window] invalidateCursorRectsForView:_view];
|
||||||
@ -1045,19 +1045,15 @@ set_properties_now(WindowProperties &properties) {
|
|||||||
properties.set_cursor_filename(cursor_filename);
|
properties.set_cursor_filename(cursor_filename);
|
||||||
properties.clear_cursor_filename();
|
properties.clear_cursor_filename();
|
||||||
} else {
|
} else {
|
||||||
NSImage *image = load_image(cursor_filename);
|
NSCursor *cursor = load_cursor(cursor_filename);
|
||||||
if (image != nil) {
|
if (cursor != nil) {
|
||||||
NSCursor *cursor;
|
// Replace the existing cursor.
|
||||||
cursor = [[NSCursor alloc] initWithImage:image hotSpot:NSMakePoint(0, 0)];
|
if (_cursor != nil) {
|
||||||
if (cursor != nil) {
|
[_cursor release];
|
||||||
// Replace the existing cursor.
|
|
||||||
if (_cursor != nil) {
|
|
||||||
[_cursor release];
|
|
||||||
}
|
|
||||||
_cursor = cursor;
|
|
||||||
_properties.set_cursor_filename(cursor_filename);
|
|
||||||
properties.clear_cursor_filename();
|
|
||||||
}
|
}
|
||||||
|
_cursor = cursor;
|
||||||
|
_properties.set_cursor_filename(cursor_filename);
|
||||||
|
properties.clear_cursor_filename();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// This will ensure that NSView's resetCursorRects gets called, which sets
|
// This will ensure that NSView's resetCursorRects gets called, which sets
|
||||||
@ -1321,11 +1317,12 @@ do_switch_fullscreen(CFDictionaryRef mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the indicated filename and returns an NSImage pointer, or NULL on
|
* Loads the indicated filename and returns an NSData pointer (which can then
|
||||||
* failure. Must be called from the window thread.
|
* be used to create a CGImageSource or NSImage), or NULL on failure. Must be
|
||||||
|
* called from the window thread. May return nil.
|
||||||
*/
|
*/
|
||||||
NSImage *CocoaGraphicsWindow::
|
NSData *CocoaGraphicsWindow::
|
||||||
load_image(const Filename &filename) {
|
load_image_data(const Filename &filename) {
|
||||||
if (filename.empty()) {
|
if (filename.empty()) {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
@ -1345,7 +1342,6 @@ load_image(const Filename &filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Look in our index.
|
// Look in our index.
|
||||||
NSImage *image = nil;
|
|
||||||
IconImages::const_iterator it = _images.find(resolved);
|
IconImages::const_iterator it = _images.find(resolved);
|
||||||
if (it != _images.end()) {
|
if (it != _images.end()) {
|
||||||
// Found it.
|
// Found it.
|
||||||
@ -1373,21 +1369,81 @@ load_image(const Filename &filename) {
|
|||||||
|
|
||||||
NSData *data = [NSData dataWithBytesNoCopy:buffer length:size];
|
NSData *data = [NSData dataWithBytesNoCopy:buffer length:size];
|
||||||
if (data == nil) {
|
if (data == nil) {
|
||||||
|
cocoadisplay_cat.error()
|
||||||
|
<< "Could not load image data from file " << filename << "\n";
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
image = [[NSImage alloc] initWithData:data];
|
_images[resolved] = data;
|
||||||
[data release];
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps image data loaded by load_image_data with an NSImage. The returned
|
||||||
|
* pointer is autoreleased. May return nil.
|
||||||
|
*/
|
||||||
|
NSImage *CocoaGraphicsWindow::
|
||||||
|
load_image(const Filename &filename) {
|
||||||
|
NSData *image_data = load_image_data(filename);
|
||||||
|
NSImage *image = [[[NSImage alloc] initWithData:image_data] autorelease];
|
||||||
if (image == nil) {
|
if (image == nil) {
|
||||||
cocoadisplay_cat.error()
|
cocoadisplay_cat.error()
|
||||||
<< "Could not load image from file " << filename << "\n";
|
<< "Could not load image from file " << filename << "\n";
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
_images[resolved] = image;
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a cursor with the proper hotspot if a .cur filename is passed in.
|
||||||
|
* You must release the returned pointer. May return nil.
|
||||||
|
*/
|
||||||
|
NSCursor *CocoaGraphicsWindow::
|
||||||
|
load_cursor(const Filename &filename) {
|
||||||
|
NSData *image_data = load_image_data(cursor_filename);
|
||||||
|
if (image_data == nil) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the metadata from the image, which should contain hotspotX and
|
||||||
|
// hotspotY properties.
|
||||||
|
CGImageSourceRef cg_image = CGImageSourceCreateWithData((CFDataRef)image_data, nullptr);
|
||||||
|
if (cg_image == NULL) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSDictionary *image_props = (NSDictionary *)CGImageSourceCopyPropertiesAtIndex(cg_image, 0, nil);
|
||||||
|
CFRelease(cg_image);
|
||||||
|
|
||||||
|
if (image_props == nil) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGFloat hotspot_x = 0.0f;
|
||||||
|
CGFloat hotspot_y = 0.0f;
|
||||||
|
if (image_props[@"hotspotX"] != nil) {
|
||||||
|
hotspot_x = [(NSNumber *)image_props[@"hotspotX"] floatValue];
|
||||||
|
}
|
||||||
|
if (image_props[@"hotspotY"] != nil) {
|
||||||
|
hotspot_y = [(NSNumber *)image_props[@"hotspotY"] floatValue];
|
||||||
|
}
|
||||||
|
[image_props release];
|
||||||
|
|
||||||
|
NSImage *image = [[NSImage alloc] initWithData:image_data];
|
||||||
|
|
||||||
|
NSCursor *cursor;
|
||||||
|
if (image != nil) {
|
||||||
|
// Apple recognizes that hotspots are usually specified from a .cur
|
||||||
|
// file, whose origin is in the top-left, so there's no need to flip
|
||||||
|
// it like most other Cocoa coordinates.
|
||||||
|
cursor = [[NSCursor alloc] initWithImage:image
|
||||||
|
hotSpot:NSMakePoint(hotspot_x, hotspot_y)];
|
||||||
|
[image release];
|
||||||
|
}
|
||||||
|
|
||||||
|
return cursor;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by CocoaPandaView or the window delegate when the frame rect
|
* Called by CocoaPandaView or the window delegate when the frame rect
|
||||||
* changes.
|
* changes.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user