jbrennan
jbrennan

Reputation: 12003

Custom NSWindow with rounded corners which clip subviews

I'm trying to create a custom NSWindow, so I've created one with the proper borderless window mask and that works. I provide my own content view which is fine. But what I'm trying to do is draw with rounded corners that also clip subviews to those corners. Is this possible?

In my content view, I can override drawRect: and draw a path with round corners, but when I add subviews to this, they aren't clipped.

I can instead make my content view layer-backed and give it a corner radius (with masksToBounds set to YES) but when I add subviews, they're still not clipped by my round corners.

Is there a way to do this? Or some way to draw an NSWindow without a title bar and which I'd have full control over the drawing, and yet maintain the rounded, clipping corners?

Upvotes: 8

Views: 7635

Answers (3)

Klajd Deda
Klajd Deda

Reputation: 375

Subclassing is the most flexible way. If you don't want to subclass use this code.

// unfortunately the window can't be moved
// but this is just an alert type window, so i don't care
//
[window setOpaque:NO];
[window setBackgroundColor:[NSColor clearColor]];

NSView*  contentView = window.contentView;

contentView.wantsLayer = YES;
contentView.layer.backgroundColor = [NSColor windowBackgroundColor].CGColor;
contentView.layer.masksToBounds = YES;
contentView.layer.cornerRadius = 16.0;

[window makeKeyAndOrderFront:self];
[window center];

Upvotes: 1

ThE uSeFuL
ThE uSeFuL

Reputation: 1534

What @ericgorr is suggesting is correct. In addition if you want the window to be movable and resizable change the init of the NSWindow as follows,

- (id)initWithContentRect:(NSRect)contentRect
                 styleMask:(NSUInteger)aStyle
                   backing:(NSBackingStoreType)bufferingType
                     defer:(BOOL)flag
{
    self = [super initWithContentRect:contentRect
                            styleMask:aStyle
                              backing:bufferingType
                                defer:flag];
    if (self) {            
        [self setOpaque:NO];
        [self setBackgroundColor:[NSColor clearColor]];
        [self setMovableByWindowBackground:YES];
        [self setStyleMask:NSResizableWindowMask];
    }
    return self;
}

For further customisation refer Apple sample code http://developer.apple.com/library/mac/#samplecode/RoundTransparentWindow/Introduction/Intro.html

Upvotes: 5

ericg
ericg

Reputation: 8722

What I was able to do is provide a custom subclass of my NSWindow:

@implementation ELGRoundWindow

- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag
{
    self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:bufferingType defer:flag];

    if ( self )
    {
        [self setStyleMask:NSBorderlessWindowMask];
        [self setOpaque:NO];
        [self setBackgroundColor:[NSColor clearColor]];
    }

    return self;
}


- (void) setContentView:(NSView *)aView
{
    aView.wantsLayer            = YES;
    aView.layer.frame           = aView.frame;
    aView.layer.cornerRadius    = 20.0;
    aView.layer.masksToBounds   = YES;


    [super setContentView:aView];

}

@end

and then in IB, I changed the class of my content view to ELGRoundView:

@implementation ELGRoundView

- (void)drawRect:(NSRect)dirtyRect
{
    [[NSColor colorWithCalibratedRed:0.0 green:0.5 blue:1 alpha:1] set];
    NSRectFill(dirtyRect);
}

@end

I placed another square subview in my content view with the following:

@implementation ELGSquareView

- (void)drawRect:(NSRect)dirtyRect
{
    [[NSColor colorWithCalibratedRed:0.0 green:0 blue:1 alpha:1] set];
    NSRectFill(dirtyRect);
}

@end

I ended up with:

Rounded window with clipped subview

Upvotes: 13

Related Questions