How to change the focus ring color? - objective-c

In the draw function of the NSImageView,I want to set my custom focus ring color,not the default blue color.I tried as follows code
NSSetFocusRingStyle(NSFocusRingOnly);
[[NSColor redColor] setStroke];
NSRectFill([self bounds]);
But the color is still default blue color.How can I solve this problem?
update:
The NSShadow class help me to accomplish adding focus ring.It's easy to change the shadow color.
NSShadow *shadow = [[[NSShadow alloc] init] autorelease];
[shadow setShadowBlurRadius:5];
[shadow setShadowOffset:NSMakeSize(0.0, 0.0)];
[shadow setShadowColor:[NSColor redColor]];
[shadow set];
I code this in the NSImageView's draw function.

The only way to solve this "problem" is to draw the focus ring yourself. The NSFocusRingStyle code is designed to make it easy for you to draw a focus ring in the user's selected focus style, which includes them being able to set the focus ring color.
It is by design that you cannot easily change the focus ring color, as it is part of the OS theme and thus should be under the user's control (according to the HIG). If you have a special case, such as needing to adaptively color the focus ring based on the contents of the image, you will have to create your own focus ring from scratch.

Related

Problems with borderless window content disappearing

If I remove this method from my view everything works fine (no content disappears if I click on a button), so this is definitely the cause.
I'm trying to make a window that is rounded and has a gradient via the code below. Is there anything wrong with this at all that could cause content on the view to disappear?
- (void)drawRect:(NSRect)dirtyRect
{
[NSGraphicsContext saveGraphicsState];
NSBezierPath *outerClip = [NSBezierPath bezierPathWithRoundedRect:[self bounds]
xRadius:3.0
yRadius:3.0];
[outerClip setClip];
NSGradient* aGradient = [[NSGradient alloc]
initWithStartingColor:[NSColor colorWithCalibratedWhite:1.0 alpha:1.0]
endingColor:[NSColor colorWithCalibratedWhite:0.65 alpha:1.0]];
[aGradient drawInRect:[outerClip bounds] angle:270];
[NSGraphicsContext restoreGraphicsState];
}
Switching to NSGradient drawInbezierPath fixes the issue.
I know you answered your own question but I thought I would share why your content was vanishing with the above code.
When you use setClip you are removing the previous clipping path and replacing it with your new path. This means you will wind up drawing outside of the dirty area, thus overwriting previously drawn content.
I had the same issue with drawing rounded corners on my own splash screen, and eventually found a different way to do what I wanted.
Also, you can use the clipRect: class method of NSBezierPath to change the clipping path to the intersection of the existing path and the area you want to restrict drawing into. Of course, save and restore the graphics state around your call to clipRect:.

Draw NSShadow inside a NSView

I'm trying to draw a NSShadow on the background of a NSView. I want to use it as a replacement for NSGradient, as I need to support Mac OS X Tiger. How may I do that? I know this must be pretty easy and I must be making some mistake.
Thanks!
The easiest approach may be to just set the shadow properties for the view's layer. If you have a NSView* named view, it'd be something like:
[[view layer] setShadowOpacity:0.5];
Setting the shadow opacity to something greater than 0 will make the shadow visible. The shadow drawn will be similar to the view's alpha channel, so whatever you draw in the view will have a shadow. There are several other shadow attributes that you can set, such as the blur radius. Take a look at the CALayer reference page for more.
If you must use NSShadow, then just set up a shadow before you do your drawing:
- (void)drawRect:(NSRect)rect
{
NSShadow *shadow = [[[NSShadow alloc] init] autorelease];
[shadow setShadowBlurRadius:3.0];
[shadow setShadowOffset:NSMakeSize(0.0, 5.0)];
[shadow setShadowColor:[NSColor colorWithCalibratedWhite:0.0 alpha:0.6]];
[shadow set];
// continue with your drawing...
}

Custom background drawing in an grouped UITableViewCell

I'm having some trouble drawing a custom gradient background in a UITableViewCell when the style is set to 'grouped' and the cell is first or the last one of the section. My approach is to simply create a CAGradientLayer and add it to the view like this:
CAGradientLayer *gradient = [CAGradientLayer layer];
gradient.frame = rect;
gradient.colors = [NSArray arrayWithObjects:(id)[_backgroundColorLight CGColor], (id)[_backgroundColorDark CGColor], nil];
[self.backgroundView.layer insertSublayer:gradient atIndex:0];
self.backgroundView.layer.masksToBounds = YES;
Unfortunately this produces cells like this one:
Does anyone have a hint on how to make the background fit the boarders of the cell?
Thanks
–f
If you draw a custom background, you also have to draw the borders yourself. There's quite some open source stuff out there.
Basically, you need to know [in the cell] if it's top/middle/bottom/single, and cut the stuff in drawRect. You won't come far with insertSublayer.
Check out the PageCellBackground class you find here:
http://cocoawithlove.com/2010/12/uitableview-construction-drawing-and.html
I've not tried it but CAGradientLayer happens to be a subclass of CALayer, so perhaps setting its borderRadius may work. But it rounds all corners then, so you may compensate for that by making the layer bigger than the cell and have the cell view cut it off.
Look at Rounded UIView using CALayers - only some corners - How? for more examples

Drawing Transparent Images

I created a custom view to a button, as I need to implement some highlighting when the mouse is over. The class is very simple, and I already implemented mouseEntered: as well as mouseExited:. The view was registered for tracking in the init method (not sure if it's the best place).
The problem is drawing. I keep an ivar mouseOver, set to YES on mouse enter and NO on mouse exited. The other ivar is for the image, called image. The difference between mouse over or not when it comes to drawing, is the transparency. Here is my drawRect::
- (void)drawRect:(NSRect)dirtyRect
{
[image drawAtPoint:NSMakePoint(0.0,0.0)
fromRect:dirtyRect
operation:NSCompositeCopy
fraction:((mouseOver) ? 1.0 : 0.0)];
}
It works nicely, but only when the mouse first entered, apparently. I guess the problem is that the view is not cleared before drawing the other image. I tried adding:
[[NSColor clearColor] set];
NSRectFillUsingOperation(dirtyRect, NSCompositeClear);
But without success. How can I fix this?
[NSColor clearColor] is a purely transparent color. You probably want to fill using a color with some opacity, like, say, [NSColor whiteColor].

Odd problem with NSImage -lockFocusFlipped:

I'm using NSImage's -lockFocusFlipped: method to do some drawing into an image. My code looks like this:
NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize(256, 256)];
[image lockFocusFlipped:YES];
NSShadow *shadow = [[NSShadow alloc] init];
[shadow setShadowColor:[NSColor blackColor]];
[shadow setShadowBlurRadius:6.0];
[shadow setShadowOffset:NSMakeSize(0, 3)];
[shadow set];
NSRect shapeRect = NSMakeRect(0, 0, 256, 100);
[[NSColor redColor] set];
NSRectFill(shapeRect);
[image unlockFocus];
This code works to a certain point. I can confirm that the context is indeed flipped because [[NSGraphicsContext currentContext] isFlipped] returns YES, and also because shapeRect is drawn at the right position (using the top left corner as the origin). That said, the NSShadow does not seem to respect the flipped status of the context. Setting the shadow offset to (0, 3) should move the shadow down when the context is flipped, but it actually moves it up (which is what would happen in a standard non-flipped context).
This problem seems specific to -lockFocusFlipped, because when I'm drawing using this same code into a CALayer with a flipped coordinate system, the shadow is drawn just fine (respecting the flip). Documentation on -lockFocusFlipped also seems to be quite vague. This is all it says in the NSImage class documentation:
Prepares the image to receive drawing commands using the specified flipped state.
And I also found this note in the Snow Leopard AppKit Release Notes:
There are cases, for example drawing directly via NSLayoutManager, that require a flipped context. To cover this case, we add
- (void)lockFocusFlipped:(BOOL)flipped;
This doesn't alter the state of the image itself, only the context on which focus is locked. It means that (0,0) is at the top left and positive along the Y-axis is down in the locked context.
None of the docs seem to explain NSShadow's behaviour in this case. And through further testing, it seems NSGradient does not seem to respect the flipped state of the drawing context used by NSImage either.
Any insight is greatly appreciated :-)
From the NSShadow class reference:
Shadows are always drawn in the default user coordinate space, regardless of any transformations applied to that space. This means that rotations, translations and other transformations of the current transformation matrix (the CTM) do not affect the resulting shadow.
And that's what flipping ultimately is: Translate up, scale back the other way.
There's no such statement for NSGradient, so I'd suggest filing a bug about that one.