How to click through a window's transparent part in Cocoa and SFML - cocoa

I use window.getSystemHandle() in SFML and convert it to NSWindow *, the following code is used to make the window transparent:
NSWindow *cocoa_window = (NSWindow*)window.getSystemHandle() ;
GLint opaque = 0;
[cocoa_window setStyleMask:NSWindowStyleMaskBorderless];
[cocoa_window setLevel: NSFloatingWindowLevel];
[[[cocoa_window contentView] openGLContext] setValues:&opaque forParameter:NSOpenGLContextParameterSurfaceOpacity];
[cocoa_window setBackgroundColor:[NSColor clearColor]];
[cocoa_window setOpaque:NO];
And I clean the window by:
window.clear(sf::Color::Transparent);
However, I can't click through the transparent part ( I want to receive mouse events when the user click on the opaque part) of the window. What can I do?
Should I replace the line [[[cocoa_window contentView] openGLContext] ...; with something else? Or do something on SFML part instead?

Related

Change MacOS X mouse cursor Image

Is there any way to change Mac OSX mouse cursor image as I am recording a video in which I want to use a different image for Mac mouse cursor and I tried many software that only change size of the mouse cursor, but not the image. So how can I replace default MacOSX mouse cursor image on the screen.
You can override -(void) resetCursorRects for a NSView subclass. Something like this:
-(void) resetCursorRects {
[super resetCursorRects];
// define cursor image and cursorRects
NSRect move = NSMakeRect((reg1UserStart + REGION_RESIZE_SIZE),REGION_Y_LOCATION, (self.reg1UserLength - (REGION_RESIZE_SIZE*2)), REGION_HEIGHT);
NSRect resizeStart = NSMakeRect(self.reg1UserStart, REGION_Y_LOCATION, REGION_RESIZE_SIZE, REGION_HEIGHT);
NSRect resizeEnd = NSMakeRect(((self.reg1UserStart + self.reg1UserLength) - REGION_RESIZE_SIZE), REGION_Y_LOCATION, REGION_RESIZE_SIZE, REGION_HEIGHT);
[self addCursorRect:move cursor:[NSCursor openHandCursor]];
[self addCursorRect:resizeStart cursor: [NSCursor resizeRightCursor]];
[self addCursorRect:resizeEnd cursor:[NSCursor resizeLeftCursor]];
}
You have to define a NSRect that represents the area that changes the mouse cursor, and then you give it an NSCursor type. This can be used to make custom cursors as well.
GW

Redrawed inset NSShadow on a Custom View using -setClip method

I have and odd problem, related with the answer of this question:
Draw an Inset NSShadow and Inset Stroke
I use this code into the drawRect method of a custom view. I have exactly this:
- (void)drawRect:(NSRect)rect
{
// Create and fill the shown path
NSBezierPath *path = [NSBezierPath
bezierPathWithRoundedRect:[self bounds]
xRadius:4.0f
yRadius:4.0f];
[[NSColor colorWithCalibratedWhite:0.8f alpha:0.2f] set];
[path fill];
// Save the graphics state for shadow
[NSGraphicsContext saveGraphicsState];
// Set the shown path as the clip
[path setClip];
// Create and stroke the shadow
NSShadow * shadow = [[[NSShadow alloc] init] autorelease];
[shadow setShadowColor:[NSColor colorWithCalibratedWhite:0.0f alpha:0.8f]];
[shadow setShadowBlurRadius:2.0];
[shadow set];
[path stroke];
// Restore the graphics state
[NSGraphicsContext restoreGraphicsState];
if ( highlight && [[self window] firstResponder] == self ) {
NSSetFocusRingStyle(NSFocusRingOnly);
[[NSBezierPath bezierPathWithRect:[self bounds]] fill];
}
}
The problem comes when I add a Multiline Label (either sibling or child of my custom view).
When my program window loses the focus and I come back to it, my inner shadow / stroke go darker. It seems that the shadows superimpose. It's strange because as said, if my window only have this custom view, it goes well.
If I comment the line
[path setClip];
the shadow isn't superimposed anymore, but I don't get the desired effect of rounded corners (similar than NSBox).
I tried what happens with a Push Button instead of a Multiline Label, and by losing / getting the window focus it has no problems, but when I click the button the shadow gets superimposed.
I find the problem is similar than here, but in Cocoa instead of Java:
Java setClip seems to redraw
Thanks for your help!
You should never use -setClip unless you know what you're doing. You should use -addClip instead, which respects the existing clipping paths.

NSPopover below caret in NSTextView

I know that in order to show a popover I need an NSView, but I don't think that there is one associated with the caret (inside the NSTextView). Is there a way to show a NSPopover below the caret?
I tried to alloc a NSView and position it using (NSRect)boundingRectForGlyphRange:(NSRange)glyphRange inTextContainer:(NSTextContainer *)container, but the popover will not appear (and there's a reason, that method returns NSRect: {{0, 0}, {0, 0}}).
I'm not sure if you are still looking for answer. I recently was working on a project which happens to need a very similar feature like you described.
You can do the following inside a subclass of NSTextView:
the function you are going to call is : showRelativeToRect:ofView:preferredEdge:
the rect will be a rect inside the NSTextView, using the NSTextView coordinate system, the ofView is the NSTextView, and the preferredEdge is the edge you want this popover thing to hook with.
now, you are saying that you want the PopOver thing to show under the caret, well you have to give him a Rect, a Point is not enough. The NSTextView has a selector called selectedRange, which gives you the range of the selected text, you can use that to locate your caret.
the next thing is to call firstRectForCharacterRange (the class must delegate NSTextInputClient), this method will return a screen coordinate of the selected text inside the NSTextView, then you convert them into the NSTextView coordinate system, you will be able to show the NSPopover thing at a correct position. Here's my code of doing this.
NSRect rect = [self firstRectForCharacterRange:[self selectedRange]]; //screen coordinates
// Convert the NSAdvancedTextView bounds rect to screen coordinates
NSRect textViewBounds = [self convertRectToBase:[self bounds]];
textViewBounds.origin = [[self window] convertBaseToScreen:textViewBounds.origin];
rect.origin.x -= textViewBounds.origin.x;
rect.origin.y -= textViewBounds.origin.y;
rect.origin.y = textViewBounds.size.height - rect.origin.y - 10; //this 10 is tricky, if without, my control shows a little below the text, which makes it ugly.
NSLog(#"rect %#", NSStringFromRect(rect));
NSLog(#"bounds %#", NSStringFromRect([self bounds]));
if([popover isShown] == false)
[popover showRelativeToRect:rect
ofView:self preferredEdge:NSMaxYEdge];
and this is the result.
All the thing I am wondering is that if there is a way to convert using System functions, although I tried the convertRect:toView, but since this method is written in a delegate, the NSTextView always has the coordinate system of (0,0), which makes this method useless.

How to avoid double window opening at launch?

I've been porting my cocos2D iOS game to Mac and it works without problems but I don't understand why I get two windows open every time I launch the app.
One of them is the cocos2d window with the main menu scene and the properties and name I give but there is another blank white window with the app name (I mean the Xcode project name). I suppose this is a trivial issue but I really can't avoid that window from appearing.
What am I doing wrong?
This is my AppDelegate window initialization:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification{
CCDirectorMac *director = (CCDirectorMac*) [CCDirector sharedDirector];
//Posiciona ventana y define escalado
NSRect aFrame=[[NSScreen mainScreen] frame];
CGSize winSize = CGSizeMake(1024,768);
CC_DIRECTOR_INIT(winSize);
[self.window showsResizeIndicator];
[director setResizeMode:kCCDirectorResize_AutoScale];
[director setProjection:kCCDirectorProjection2D];
[window_ setContentAspectRatio:NSMakeSize(winSize.width,winSize.height)];
[window_ setStyleMask:[window_ styleMask] | NSResizableWindowMask | NSMiniaturizableWindowMask];
[window_ setTitle:#"Barman Hero"];
aFrame=[[NSScreen mainScreen] frame];
if (aFrame.size.width<=winSize.width || aFrame.size.height<=winSize.height) [window_ zoom:self];
[window_ center];
[glView_ setFrameSize:NSMakeSize(window_.frame.size.width,window_.frame.size.height-22)];
// Enable "moving" mouse event. Default no.
[window_ setAcceptsMouseMovedEvents:NO];
.....
.....
.....
//Carga escena principal
[[CCDirectorMac sharedDirector] runWithScene:[MainMenu scene]];
}
Thanks in advance.
It is likely that you have a Window defined in MainMenu.xib that is being opened semi-automatically. Remove the window from MainMenu.xib and any code that might reference it and it should no longer open the second window.

NSTrackingArea with fullscreen window/view

I'm trying to install a NSTrackingArea into a fullscreen view in order to get mouse moved events.
However, whenever I do, I get an assertion error. I've searched the web, but have not been able to find any leads.
*** Assertion failure in -[_NSFullScreenWindow _setTrackingRect:inside:owner:userData:useTrackingNum:install:], /SourceCache/AppKit/AppKit-1038.25/AppKit.subproj/NSWindow.m:3944
Here's the code that sets up the tracking area (x=1024, y=768):
cocoaWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(0.0, 0.0, x,y)
styleMask: NSTitledWindowMask
backing: NSBackingStoreBuffered
defer:NO];
glView = [[WLMacGLView alloc] initWithFrame:NSMakeRect(0.0, 0.0, x,y) pixelFormat:[WLMacGLView defaultPixelFormat]];
[glView setCocoaController:self];
//add the glView as a subview of the window's content view
[[cocoaWindow contentView] addSubview:glView];
NSRect r = [glView frame];
NSTrackingArea *track = [[NSTrackingArea alloc] initWithRect:r options: NSTrackingMouseMoved | NSTrackingActiveWhenFirstResponder | NSTrackingActiveInKeyWindow
owner:self userInfo:nil];
[glView addTrackingArea:track];
[glView enterFullScreenMode:[NSScreen mainScreen] withOptions:nil];
[glView createContext];
The assertion happens right after the call to enterFullScreenMode: withOptions:
Anyone got any ideas? Is this not the approach I should be taking to get mouse moved events in a fullscreen window?
If you want to track mouse in the whole view, I think is will be easier to implement the mouseDown:, mouseMoved: and mouseUp: methods in order to get the mouse events.
So the answer to this question turned out to be a bug in my own code.
When initializing the NSTrackingArea, I was passing in the wrong object for owner. The proper thing to pass was the NSView. With that corrected, all works as expected.

Resources