Re: Cocoa et al as HCI usability problem
Re: Cocoa et al as HCI usability problem
- Subject: Re: Cocoa et al as HCI usability problem
- From: Graham Cox <email@hidden>
- Date: Mon, 19 May 2008 16:20:07 +1000
For clipping tasks like this, NSBezierPath is a very poor cousin to
Apple's old technology for this - Regions. With regions one could
trivially obtain union, intersection, difference and xor of complex
shapes using the built-in APIs. Neither NSBezierPath nor the
underlying Quartz routines it calls upon have the equivalent
operations. OK, Regions were intrinsically pixel-oriented (scanline)
entities and maybe it's just too hard to offer this sort of thing
generically with bezier paths, but I for one feel this is a glaring
hole in the functionality of Quartz (and, since the rasterizing code
*already* has to search for self-intersections and so on, in fact the
private code must be very close to having an implementation of this
right there - they just need to clean it up, flesh it out and make a
public API for it).
For the case of excluding an area from the clip region you can
eventually force it to do the job by combinations of winding rules,
path reversals and appends, but for other graphics work these are a
very blunt instrument. The "append" terminology is the only one
NSBezierPath has because that's all it can do - append more paths. It
cannot subtract ("remove") one path from another. If the paths
intersect you can get an xor or a union effect depending on the
winding rule, but never a subtraction. It's a royal PITA.
Here's one method I have in a category on NSBezierPath that *might*
address the clipping situation that you have. However, since there's
no public method to GET the current context's clip path, this works
using the bounding box of that path instead, which may not be
applicable in every case. Once again, I know there's a private API for
this but for some inexplicable reason, Apple do not expose it in the
public headers, even though without it this sort of thing is downright
awkward, yet commonly required.
- (void) addInverseClip
{
// this is similar to -addClip, except that it excludes the area
bounded by the path instead of includes it. It works by combining this
path
// with the existing clip area using the E/O winding rule, then
setting the result as the clip area. This should be called between
// calls to save and restore the gstate, as for addClip.
CGContextRef context = [[NSGraphicsContext currentContext]
graphicsPort];
CGRect cbbox = CGContextGetClipBoundingBox( context );
NSBezierPath* cp = [NSBezierPath bezierPathWithRect:*(NSRect*)&cbbox];
[cp appendBezierPath:self];
[cp setWindingRule:NSEvenOddWindingRule];
[cp setClip];
}
G.
On 19 May 2008, at 3:03 pm, Peter Duniho wrote:
As an example, I found myself wanting to exclude an area from my
clipping region. Nothing complicated: I had a rectangular area, and
I wanted to draw everywhere _except_ a specific sub-rectangle. The
docs were quite prideful as to how, since Cocoa clipping uses the
NSBezierPath, you have practically infinite control over clipped.
No doubt this boasting was reasonably accurate (*). And yet, even
as it hints tantalizingly at the idea that there's a way to do this
(see "Modifying the Current Graphics State"), it doesn't quite get
you there.
I was finally able to, after reading documentation in three
different places that discuss NSBezierPath, connect the dots so to
speak and figure out how the heck to get NSBezierPath to do what the
docs hinted it could do.
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden