mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-28 15:53:55 -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();
|
||||
|
||||
private:
|
||||
NSData *load_image_data(const Filename &filename);
|
||||
NSImage *load_image(const Filename &filename);
|
||||
|
||||
NSCursor *load_cursor(const Filename &filename);
|
||||
|
||||
void handle_modifier(NSUInteger modifierFlags, NSUInteger mask, ButtonHandle button);
|
||||
ButtonHandle map_key(unsigned short c) const;
|
||||
ButtonHandle map_raw_key(unsigned short keycode) const;
|
||||
@ -104,7 +107,7 @@ private:
|
||||
CFDictionaryRef _windowed_mode;
|
||||
#endif
|
||||
|
||||
typedef pmap<Filename, NSImage*> IconImages;
|
||||
typedef pmap<Filename, NSData*> IconImages;
|
||||
IconImages _images;
|
||||
|
||||
public:
|
||||
|
@ -571,17 +571,17 @@ open_window() {
|
||||
}
|
||||
|
||||
if (_properties.has_cursor_filename()) {
|
||||
NSImage *image = load_image(_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)];
|
||||
}
|
||||
NSCursor *cursor = load_cursor(_properties.get_cursor_filename());
|
||||
|
||||
if (cursor != nil) {
|
||||
if (_cursor != nil) {
|
||||
[_cursor release];
|
||||
}
|
||||
_cursor = cursor;
|
||||
} else {
|
||||
_properties.clear_cursor_filename();
|
||||
}
|
||||
|
||||
// This will ensure that NSView's resetCursorRects gets called, which sets
|
||||
// the appropriate cursor rects.
|
||||
[[_view window] invalidateCursorRectsForView:_view];
|
||||
@ -1045,19 +1045,15 @@ set_properties_now(WindowProperties &properties) {
|
||||
properties.set_cursor_filename(cursor_filename);
|
||||
properties.clear_cursor_filename();
|
||||
} else {
|
||||
NSImage *image = load_image(cursor_filename);
|
||||
if (image != nil) {
|
||||
NSCursor *cursor;
|
||||
cursor = [[NSCursor alloc] initWithImage:image hotSpot:NSMakePoint(0, 0)];
|
||||
if (cursor != nil) {
|
||||
// Replace the existing cursor.
|
||||
if (_cursor != nil) {
|
||||
[_cursor release];
|
||||
}
|
||||
_cursor = cursor;
|
||||
_properties.set_cursor_filename(cursor_filename);
|
||||
properties.clear_cursor_filename();
|
||||
NSCursor *cursor = load_cursor(cursor_filename);
|
||||
if (cursor != nil) {
|
||||
// Replace the existing cursor.
|
||||
if (_cursor != nil) {
|
||||
[_cursor release];
|
||||
}
|
||||
_cursor = cursor;
|
||||
_properties.set_cursor_filename(cursor_filename);
|
||||
properties.clear_cursor_filename();
|
||||
}
|
||||
}
|
||||
// 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
|
||||
* failure. Must be called from the window thread.
|
||||
* Loads the indicated filename and returns an NSData pointer (which can then
|
||||
* be used to create a CGImageSource or NSImage), or NULL on failure. Must be
|
||||
* called from the window thread. May return nil.
|
||||
*/
|
||||
NSImage *CocoaGraphicsWindow::
|
||||
load_image(const Filename &filename) {
|
||||
NSData *CocoaGraphicsWindow::
|
||||
load_image_data(const Filename &filename) {
|
||||
if (filename.empty()) {
|
||||
return nil;
|
||||
}
|
||||
@ -1345,7 +1342,6 @@ load_image(const Filename &filename) {
|
||||
}
|
||||
|
||||
// Look in our index.
|
||||
NSImage *image = nil;
|
||||
IconImages::const_iterator it = _images.find(resolved);
|
||||
if (it != _images.end()) {
|
||||
// Found it.
|
||||
@ -1373,21 +1369,81 @@ load_image(const Filename &filename) {
|
||||
|
||||
NSData *data = [NSData dataWithBytesNoCopy:buffer length:size];
|
||||
if (data == nil) {
|
||||
cocoadisplay_cat.error()
|
||||
<< "Could not load image data from file " << filename << "\n";
|
||||
return nil;
|
||||
}
|
||||
|
||||
image = [[NSImage alloc] initWithData:data];
|
||||
[data release];
|
||||
_images[resolved] = data;
|
||||
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) {
|
||||
cocoadisplay_cat.error()
|
||||
<< "Could not load image from file " << filename << "\n";
|
||||
return nil;
|
||||
}
|
||||
|
||||
_images[resolved] = 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
|
||||
* changes.
|
||||
|
Loading…
x
Reference in New Issue
Block a user