Why is my layer shadow clipped to my NSView's rect? - cocoa

I'm creating a window containing an NSButton (both window content view & button have wantsLayer = YES), and setting the NSButton's shadowColor, shadowRadius, shadowOpacity and shadowOffset. But my shadow gets clipped to the rect of the NSView. How do I fix this?
NSRect wdBox = NSMakeRect(0,0,100,100);
NSWindow * theWindow = [[[NSWindow alloc] initWithContentRect: wdBox styleMask: NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask backing: NSBackingStoreBuffered defer: NO] autorelease];
NSView* cv = [[[NSView alloc] initWithFrame: wdBox] autorelease];
cv.wantsLayer = YES;
[cv setLayerUsesCoreImageFilters: YES];
theWindow.contentView = cv;
[theWindow setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary];
[theWindow setTitle: #"foo"];
NSButton* mView = [[NSButton alloc] initWithFrame: NSMakeRect(10, 10, 100, 80)];
[mView setLayerUsesCoreImageFilters: YES];
[mView setWantsLayer: YES];
mView.layer.masksToBounds = NO;
[mView.layer setShadowColor: [NSColor.redColor CGColor]];
[mView.layer setShadowOffset: CGSizeMake(4, 4)];
[mView.layer setShadowRadius: 8];
[mView.layer setShadowOpacity: 1.0];
[mView setBezelStyle: NSRoundRectBezelStyle];
[mView setTitle: #"bar"];
[theWindow.contentView addSubview: mView];
Here's a picture:
I had similar code before and it used to work until 10.9, but the shadow suddenly got clipped to the view, so I rewrote it to this simple case, but it's still clipped.

There is a bug in Mavericks. If you create an NSButton in XIB and give it a layer and set its shadow it works fine, but if you create one programmatically it clips its shadow.
I suspect the AppKit team did some crazy hacks when they made buttons do fast layer compositing in Mavericks (they won't redraw their backgrounds unless necessary now, for instance), because they tried to make it all happen magically, which is always always a bad idea.
Note that if you make an NSTextField the shadow code works as you'd expect. It's just NSButtons (so far) that I've found have this issue.
Please file a radar.

Related

My NSScrollView is not scrolling my NSTextView (document)

So I've been burned by this a few times. I'm trying to create an NSTextView that can be scrolled.
The only way I've gotten it to work is by having a Xib—but right now that stopped working after I added a Stack View in an adjacent Split View for God-knows-what-reason.
So what have I done?
I have code for code copied down the Apple Docs like for Text in Scroll View like so:
// https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/TextUILayer/Tasks/TextInScrollView.html
BOOL deviateFromAppleScrollDoc = NO;
_scrollView = [[NSScrollView alloc]
initWithFrame:[[self view] frame]];
// Apple Has
// [[theWindow contentView] frame]];
// but we are in a sub-View-Controller
NSSize contentSize = [_scrollView contentSize];
[_scrollView setBorderType:NSNoBorder];
[_scrollView setHasVerticalScroller:YES];
[_scrollView setHasHorizontalScroller:NO];
[_scrollView setAutoresizingMask:NSViewWidthSizable |
NSViewHeightSizable];
_editorView = [[EditorView alloc]
initWithFrame:NSMakeRect(
0, 0,
contentSize.width, contentSize.height)];
[_editorView setMinSize:NSMakeSize(0.0, contentSize.height)];
[_editorView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
[_editorView setVerticallyResizable:YES];
[_editorView setHorizontallyResizable:NO];
if (deviateFromAppleScrollDoc)
{
[_editorView setAutoresizesSubviews:YES];
[_editorView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
}
else
{
[_editorView setAutoresizingMask:NSViewWidthSizable];
}
[[_editorView textContainer]
setContainerSize:NSMakeSize(contentSize.width, FLT_MAX)];
[[_editorView textContainer] setWidthTracksTextView:YES];
if (deviateFromAppleScrollDoc)
{
[[_editorView textContainer] setHeightTracksTextView:YES];
}
if (deviateFromAppleScrollDoc)
{
NSClipView *clipView = [[NSClipView alloc] init];
[clipView setDocumentView:_editorView];
[_scrollView setContentView:clipView];
}
else
{
[_scrollView setDocumentView:_editorView];
}
[[self view] addSubview:_scrollView];
What does that get me?
As you can tell, there is an NSTextView. It does not fill the Container as I would like it to.
There is also a Scroll View and I can tell it is active. You can pull down and get a rebound effect—but it does not scroll the document as I would like. This text is cut off mid-sentence and when I add to it, the View does not scroll with my typing—and even if I scroll I can't get to it.
The Scroll View is "stuck".
I can make it fill the entire window if I change the Autoresizing mask to inlcude NSViewHeightSizable like so:
[_editorView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];
See here:
Unfortunatley, it still does not scroll and the "Scroll View" is still "Stuck".
I don't know what to change.
I have tried to add a "NSClipView" and set the Content View instead like so:
NSClipView *clipView = [[NSClipView alloc] init];
[clipView setDocumentView:_editorView];
[_scrollView setContentView:clipView];
This does not work either.
Moreover it does something funky to the width and some of the letters get cut off. Not acceptable. No solution yet.
What am I missing?
What do I need to try / set / do?
Thank you!
UPDATE:
The Scroll View does scroll the document when I activate the find menu in the NSTextView.
Still mystified.
See here:

NSView wont use CALayer at all

I've tried everything and read a LOT about using a CALayer in a NSView, but can't get code that worked fine on iOS to work on a Mac.
I'm calling
[ nsView setLayer:[CALayer layer]];
[ nsView wantsLayer];
to create a layer as I've read everywhere I should.
then I've tried settings the layer's background color, and adding a sublayer and setting it's background color, but I just get a black window no matter what I do.
The entire programatically created app is, after removing all nibs etc, trying to make a gradient to be sure I get some Layer content:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSWindow *mainWindow;
NSView *nsView;
mainWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(20, 500, 200, 400)//screenRect
styleMask:NSTitledWindowMask
backing:NSBackingStoreBuffered
defer:NO];
[mainWindow setTitle:#"My Window"];
CAGradientLayer *layer;
nsView = [ [ NSView alloc] initWithFrame:NSMakeRect(20, 20, 200, 400)];
[mainWindow makeKeyAndOrderFront:nil];
[ nsView setLayer:[CALayer layer]];
[ nsView wantsLayer];
[ nsView setLayerContentsRedrawPolicy:NSViewLayerContentsRedrawOnSetNeedsDisplay];
layer = [CAGradientLayer layer];
layer.frame = CGRectMake(0, 0, 200, 400);
layer.colors = #[ (id)CGColorCreateGenericRGB(1, 0, 0, 1), (id)CGColorCreateGenericRGB(1, 1, 0, 1) ];
layer.startPoint = CGPointMake(0.5, 0);
layer.endPoint = CGPointMake(0.5, 1);
[nsView.layer addSublayer:layer];
[layer setNeedsDisplay];
[nsView setNeedsDisplay:YES];
[mainWindow setContentView:nsView];
}
no matter what I do, I never get any indication that the layer is being used. It and subviews exists when I debug, but are never shown. The view's drawRect method is called once as well.
I've read for days about using CALayers for NSViews, but nothing seems to get them working.
Any suggestions?
It was something amazingly simple but easy to be blind about:
I was calling:
[nsView wantsLayer]
(thinking it was a way of setting wantsLayer (probably infuenced by seeing it as a property)).
Which is just a getter that was being ignored.
[nsView setWantsLayer:YES]
or
nsView.wantsLayer = YES;
would of course be what I wanted.

NSPopover Not Appearing

I really wish I could be more specific, but unfortunately, I cannot. All appropriate objects are non-nil, and all appropriate method calls are going through (presumably) successfully, but my NSPopover just never shows up. None of the delegate methods get called, either.
// ivars
NSPopover *tagPopover;
NSViewController *tagPopoverViewController;
// in method to display popover
tagPopover = [[NSPopover alloc] init];
[tagPopover setBehavior: NSPopoverBehaviorApplicationDefined];
[tagPopover setDelegate: self];
tagPopoverViewController = [[MYViewController alloc] initWithNibName: #"MYViewController" bundle: nil];
[tagPopover setContentViewController: tagPopoverViewController];
[tagPopover setContentSize: tagPopoverViewController.view.frame.size];
[tagPopover showRelativeToRect: NSMakeRect(700, 400, 5, 5) // Screen coordinates
ofView: [[NSApp keyWindow] contentView]
preferredEdge: NSMinYEdge];
Turns out the coordinate system was wrong:
NSRect theRect = [[NSApp keyWindow] convertRectFromScreen: NSMakeRect(700, 400, 5, 5)];
[tagPopover showRelativeToRect: theRect // Window Coordinates
ofView: [[NSApp keyWindow] contentView]
preferredEdge: NSMinYEdge];
Needed to convert it to the window's coordinate system first.
I suspect that tagPopoverViewController.view.frame is NSZeroRect, since frames are set to that before they start to go onscreen (e.g. they are meaningless as they come out of xibs/storyboards). Are you sure you need that line? The documentation mentions that the contentSize is bound to the content-view's size anyway.

NSTextView background not resizing appropriately

I have an NSTextView inside an NSScrollView. The scroll view has the auto resize masks for height and width, so it changes size with the window it's in.
The text view is set up much in the way the apple documentation recommends here.
But no matter what settings I put on the text view, I cannot get the background color to resize along with the scroll view.
Here's a picture of what I'm dealing with:
The width works, but not the height.
Here's my setup code for the textview as it is for this picture:
NSTextView *view = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, scrollview.contentSize.width, scrollview.contentSize.height) textContainer:textContainer];
[view setMinSize:NSMakeSize(0.0, scrollview.contentSize.height)];
[view setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
[view setVerticallyResizable:YES];
[view setHorizontallyResizable:NO];
[view setAllowsDocumentBackgroundColorChange:YES];
[view setDrawsBackground:YES];
[view setAutomaticLinkDetectionEnabled:YES];
[view setAutoresizingMask:NSViewWidthSizable];
The white background colour isn’t that of the NSTextView, but rather that of its enclosing NSScrollView.
To change it, either select the NSScrollView in Interface Builder/Xcode 4. Or, to do it programmatically, use -[NSView encosingScrollView]:
NSScrollView *scrollView = [textView enclosingScrollView];
[scrollView setBackgroundColor:[NSColor blackColor]];

Custom NSView with NSTextField subview drawing issue

So I am drawing a custom window (transparent) with a custom NSView as the contentview, and wouldlike to add an NSTextField to the window as well, however, when I add the NSTextField, I get a weird resizing or redraw of the custom NSView, and I can't figure out what is causing the problem. Both the window and the contentview of the window are subclasses of NSWindow, and NSView, respectively. Also, I have tried to just layer the custom NSView (not set it as the contentview) with no change. Any ideas?
NSWindow *quickEntryWindow = [[TransparentWindow alloc] initWithContentRect:NSMakeRect([[NSScreen mainScreen] frame].size.width/2 - 250, [[NSScreen mainScreen] frame].size.height/2 + 50, 500, 100)
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO
special:YES];
BorderView *quickEntryBorderView = [[BorderView alloc] initWithFrame:NSMakeRect(0, 0, [[quickEntryWindow contentView] frame].size.width, [[quickEntryWindow contentView] frame].size.height)];
[quickEntryBorderView canDrawConcurrently];
[quickEntryWindow setContentView:quickEntryBorderView];
NSTextField *quickEntryTextField = [[NSTextField alloc] initWithFrame:NSMakeRect(10, 10, [quickEntryBorderView frame].size.width-20, [quickEntryBorderView frame].size.height-20)];
[quickEntryTextField setAutoresizingMask:NSViewNotSizable];
[quickEntryTextField setBordered:NO];
[quickEntryTextField setDrawsBackground:NO];
[quickEntryTextField setFocusRingType:NSFocusRingTypeNone];
[quickEntryTextField setFont:[NSFont fontWithName:#"Helvetica" size:42]];
[quickEntryTextField setTextColor:[NSColor grayColor]];
[quickEntryBorderView addSubview:quickEntryTextField];
What I get is something that looks like this (it is normal when no text is entered into the NSTextField):
Oh yeah, I know I'm not managing my memory...I'm just trying to get this working. Thanks!

Resources