Cocoa focus ring color animation - cocoa

I want to use a focus ring animation as an indicator of incorrect data in field. So I'm sending becomeFirstResponder: to field and want focus ring to fade from red to default color.
I'm wrestling with Core Animation but still have not found any way to do it. Is it possible?

I'm not sure if this strategy follows the HIG, its often more common to do something like display a persistent icon indicating a field doesn't validate next to the field, but it shouldn't be too hard to get the effect you're seeking.
It might be easier to use a simple NSAnimation here instead of using Core Animation.
The standard code for drawing a focus ring generally goes something like the following:
[NSGraphicsContext saveGraphicsState];
NSSetFocusRingStyle(NSFocusRingOnly);
[[NSColor clearColor] set];
[[NSBezierPath bezierPathWithRect:focusRect] fill];
[NSGraphicsContext restoreGraphicsState];
This code would be implemented in the drawRect: method in custom subclass of your control.
In order to draw a custom colored focus ring, you'll need to draw the rectangle yourself, and won't be able to benefit from the NSSetFocusRingStyle function. The color would be driven off of the NSAnimation, which would also set the control to repaint itself. Because you're not using Cocoa's facilities to draw the focus ring, you'll also probably need to inset the content of your view so you'll have space to draw the ring.
More information regarding NSAnimations is available in the Animation Programming Guide for Cocoa

Related

Creating pattern on-the-fly?

Is there a way to create a colored fill pattern dynamically in Cocoa?
In particular instead of using a fixed pattern from an image file via
NSColor *fillPattern = [NSColor colorWithPatternImage:patternImage];
I'd like to create a pattern by dynamically choosing the appropriate colors at runtime.
Background is highlighting a colored object by rendering stripes or squares in the ''opposite'' color on top of it - whatever opposite might mean in this context, but that's a different story..
Being applied to potentially hundreds of objects in a drawing app it needs to be a rather fast method so I suppose just swapping colors in patternImage won't be good enough.
(It did work just fine back in QuickDraw..!)
Why not just draw to an in-memory image and use that for your pattern?
NSImage* patternImage = [[NSImage alloc] initWithSize:someSize];
[patternImage lockFocus];
//draw your pattern
[patternImage unlockFocus];
NSColor* patternColor = [NSColor colorWithPatternImage:patternImage];
//do something with the pattern color
//remember to release patternImage if you're not using ARC
Performance-wise, you generally should be looking at optimising drawing by paying attention to the rect passed in to drawRect: and making sure you only draw what is necessary. If you do that then I can't see the pattern drawing performance being a major problem.
Background is highlighting a colored object by rendering stripes or squares in the ''opposite'' color on top of it - whatever opposite might mean in this context, but that's a different story..
You'll want to use one of Quartz's blend modes (most of them are present in Photoshop, Pixelmator, and Opacity, so you can experiment in one of those apps to determine which one you need).
You should then be able to fill with a static image—or a dynamic pattern, if it's really necessary—and Quartz will blend it in appropriately.
There's no way to do this in AppKit alone; you'll need to get a CGContext from the current NSGraphicsContext and do it in Quartz.

What do lockFocus and unlockFocus actually do?

Warning: I'm a Cocoa newbie.
I'm reading "Cocoa Programming For Mac OS X" by Hillegass.
On p.301 it's written:
To make the drawing appear on the image instead of on the screen, you must first lock focus on the image. When the drawing is complete, you must unlock focus.
The code I have, inside -(void)mouseDragged:(NSEvent *)theEvent of an NSView is as follows:
[resizedImage lockFocus];
[sourceImage drawInRect: NSMakeRect(0, 0, resizeWidth, resizeHeight) fromRect: NSMakeRect(0, 0, originalSize.width, originalSize.height) operation: NSCompositeSourceOver fraction: 1.0];
[resizedImage unlockFocus];
Without the lock/unlock, this does not work, but I still don't understand exactly what is going on.
I see that the 2nd line of code has no mention of resizedImage so does that mean when I use lockFocus it makes sure any 'drawing' that happens takes place there? Could someone explain this better?
Drawing requires a 'graphics context'. You'll notice that, unlike Core Graphics, none of the AppKit drawing methods take a parameter that specifies where the drawing ends up. Instead, the destination is stored globally as [NSGraphicsContext currentContext]. All AppKit drawing methods affect this current context.
The main purpose of -lockFocus (on images and views alike) is to set up the graphics context so your drawing ends up going where you want it to.
From the docs for -[NSImage lockFocus]:
This method sets the current drawing context to the area of the offscreen window used to cache the receiver's contents.
So there exists an offscreen window which you draw on when you draw to the image. This image has a graphics context and lockFocus makes this context the current drawing context so that drawInRect:... uses it for its drawing. It's similar to +[NSGraphicsContext setCurrentContext].

NSBezierPath to NSImage in order to avoid CoreAnimation

I have an app that currently has this line:
[myView setWantsLayer:YES];
In order to draw a GUI element via NSBezierPath. This line is required, otherwise when the user types in an adjacent (and overlapping) NSTextField, the contents of myView shudders.
I discovered that calling CoreAnimation loads the OpenGL framework, but does not unload it. See this question.
I think I can get around this by drawing the NSBezierPath to NSImage and then to display the NSImage in lieu of the NSBezierPath, but I haven't found a single source that shows me how to go about this.
Edit:
I should note that I want to save this BEFORE The NSBezierPath is displayed - so solutions that draw an existing view to an NSImage are not useful.
Question:
Can someone point me in the right direction for converting NSBezierPath to an NSImage?
You can draw anything directly into an NSImage, and you can create a blank NSImage. So, create an image whose size is the size of the bounds of the path, translate the path so that it's at the origin of the image, and then lock focus on the image, draw the path, and unlock focus.

Glow around Button

How can I draw a slight white 'glow' around a button or label in 10.5 and later? I have seen some apps do it, but I am still confused how I should do this.
See NSShadow. You'd create and set a shadow (saving your graphics context beforehand), then draw the basic shape of your button, unset it (by restoring your graphics context), then continue drawing as usual.
In the case of a ready-made control like NSButton, you will need to subclass and override its cell drawing (and possibly make the host NSButton control itself a bit larger to accommodate the larger area needed to encompass the "glow" of the cell).
You might be able to avoid this with a label by setting its font shadow, but I don't think IB lets you do this, so you'd programmatically give the label an attributed string (via its -setAttributedString: method). The attributes would include the NSShadow (configured as desired) as the NSShadowAttributeName.

what is layer in core animation

In core animation or in App kit When we say layer-backed view or simply add a layer in the view,then actually what we mean by the layer.
A simple Google search:
The CALayer is the canvas upon which everything in Core Animation is painted. When you define movement, color changes, image effects, and so on, those are applied to CALayer objects. From a code perspective, CALayers are a lightweight representation similar to an NSView. In fact, NSView objects can be manipulated via their CALayer. This is referred to as being layer-backed.
A CALayer is an object which manages and draws upon a GL surface, and can manipulate that surface's location in three dimensions, without needing to redraw its contents.

Resources