Objective c change autosizing of NSRect in custom view - objective-c

The title is fairly specific about what I want to do. I have a custom view and have drawn some elements inside that view. How do I change the autosizing properties programmtically? I have looked around and couldn't find anything that would help me in my case.
Objective C:
- (void)drawRect:(NSRect)HTMLContent {
NSGraphicsContext* gc = [NSGraphicsContext currentContext];
[gc saveGraphicsState];
int height = [[NSScreen mainScreen] frame].size.height;
int screenwidth = [[NSScreen mainScreen] frame].size.width;
int emailInnerContentWidth = screenwidth - 510;
// Horizontal Line
[[NSColor colorWithCalibratedRed:.8 green:.82 blue:.83 alpha:1] setFill];
NSBezierPath* drawingPath = [NSBezierPath bezierPathWithRect:NSMakeRect(337, 570, emailInnerContentWidth, 2)];
[drawingPath fill];
// Social Icon
NSRect outrect = NSMakeRect(355, 585, 58, 58);
[[NSColor lightGrayColor] setStroke];
[[NSColor colorWithPatternImage:[NSImage imageNamed:#"NoSocialIcon.png"]] setFill];
NSBezierPath* outcirclePath = [NSBezierPath bezierPath];
[outcirclePath appendBezierPathWithOvalInRect: outrect];
[[NSColor lightGrayColor] setStroke];[[NSImage imageNamed:#"NoSocialIcon.png"] drawInRect:outrect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1];
[outcirclePath stroke];
// Restore graphics state
[gc restoreGraphicsState];
}
I want to set these 2 shapes to not be affected by the bottom of the window changing. I want it to change when the top of the window changes height. I have looked on the Apple docs and nothing seemed to work. Thanks in advance

So, for each of the two shapes:
[shape setAutoresizingMask:NSViewNotSizable | NSViewMaxXMargin | NSViewMinYMargin];

Related

NSPopUpButtonCell Subclass Animates Closed With Standard Appearance

I've created an NSPopUpButtonCell subclass to customize its appearance.
When one of the menu items is selected from the popup it animates the selection with the standard popup appearance on OS X 10.10.
I'd like it to animate with my custom appearance.
Customized PopUp
Animating Selection
My Implementation
- (void)drawBezelWithFrame:(NSRect)frame inView:(NSView *)controlView {
[[NSGraphicsContext currentContext] saveGraphicsState];
NSBezierPath *rectanglePath = [NSBezierPath bezierPathWithRoundedRect:frame xRadius:5.0 yRadius:5.0];
[[NSColor colorWithWhite:0.7 alpha:1.0] setFill];
[rectanglePath fill];
float width = frame.size.width;
float height = frame.size.height;
NSBezierPath *path = [NSBezierPath bezierPath];
[path moveToPoint:CGPointMake(width - 5, height/2 - 2)];
[path lineToPoint:CGPointMake(width - 10, height/2 - 7)];
[path lineToPoint:CGPointMake(width - 15, height/2 - 2)];
[path moveToPoint:CGPointMake(width - 5, height/2 + 2)];
[path lineToPoint:CGPointMake(width - 10, height/2 + 7)];
[path lineToPoint:CGPointMake(width - 15, height/2 + 2)];
[path setLineWidth:2.0];
[[NSColor darkGrayColor] setStroke];
[path stroke];
[NSGraphicsContext restoreGraphicsState];
}
You have to turn off bordered property on Interface Builder.
If bordered is actualy off, you have to switch it on and next off.
Better way is use
- (void)drawBorderAndBackgroundWithFrame:(NSRect)cellFrame inView:(NSView *)controlView

NSTextFieldCell rounded corners stroke not rounded

I want to have an NSTextField with rounded corners, for that I subclassed my NSTextFieldCell, and used drawInteriorWithFrame:(NSRect) inView:(NSView *)
My code looks like that :
-(void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
//Color Declarations
NSColor* fillColor = [NSColor colorWithCalibratedRed: 1 green: 1 blue: 1 alpha: 1];
NSColor* strokeColor = [NSColor colorWithCalibratedRed: 0.679 green: 0.679 blue: 0.679 alpha: 1];
//Shadow Declarations
NSShadow* shadow = [[NSShadow alloc] init];
[shadow setShadowColor: strokeColor];
[shadow setShadowOffset: NSMakeSize(0.1, 0.1)];
[shadow setShadowBlurRadius: 4];
//Rounded Rectangle Drawing
NSBezierPath* roundedRectanglePath = [NSBezierPath bezierPathWithRoundedRect:cellFrame xRadius: 10 yRadius: 10];
[fillColor setFill];
[roundedRectanglePath fill];
//Rounded Rectangle Inner Shadow
NSRect roundedRectangleBorderRect = NSInsetRect([roundedRectanglePath bounds], -shadow.shadowBlurRadius, -shadow.shadowBlurRadius);
roundedRectangleBorderRect = NSOffsetRect(roundedRectangleBorderRect, -shadow.shadowOffset.width, -shadow.shadowOffset.height);
roundedRectangleBorderRect = NSInsetRect(NSUnionRect(roundedRectangleBorderRect, [roundedRectanglePath bounds]), -1, -1);
NSBezierPath* roundedRectangleNegativePath = [NSBezierPath bezierPathWithRect: roundedRectangleBorderRect];
[roundedRectangleNegativePath appendBezierPath: roundedRectanglePath];
[roundedRectangleNegativePath setWindingRule: NSEvenOddWindingRule];
[NSGraphicsContext saveGraphicsState];
{
NSShadow* shadowWithOffset = [shadow copy];
CGFloat xOffset = shadowWithOffset.shadowOffset.width + round(roundedRectangleBorderRect.size.width);
CGFloat yOffset = shadowWithOffset.shadowOffset.height;
shadowWithOffset.shadowOffset = NSMakeSize(xOffset + copysign(0.1, xOffset), yOffset + copysign(0.1, yOffset));
[shadowWithOffset set];
[[NSColor grayColor] setFill];
[roundedRectanglePath addClip];
NSAffineTransform* transform = [NSAffineTransform transform];
[transform translateXBy: -round(roundedRectangleBorderRect.size.width) yBy: 0];
[[transform transformBezierPath: roundedRectangleNegativePath] fill];
}
[NSGraphicsContext restoreGraphicsState];
[strokeColor setStroke];
[roundedRectanglePath setLineWidth: 2];
[roundedRectanglePath stroke];
[super drawInteriorWithFrame:cellFrame inView:controlView];
}
The result looks great apart from borders which are not rounded. Images are better than words : My NSTextField
All help is accepted ! :D Thank you in advance.
UPDATE
I did a copy paste with the code of the site you said, but I'm still having the same trouble...
NSTextField with on rounded corner
You may simply choose the Border of Text Field in its Attributes Inspector if you want a text field with its all corners rounded. Or to draw a text field with any one round corner, go through this
Also if you want draw a custom all round corner text field, just follow the steps in above link, but instead of drawing a bezier path with one round corner, simply draw a bezier path with all corners round using
[NSBezierPath bezierPathWithRoundedRect:textfieldrect xRadius:10 yRadius:10]

Adding Bezier path to CGPath: ObjectiveC

I have a rectangle drawn using drawRect method.
CGContextRef context = UIGraphicsGetCurrentContext();
CGRect outline = CGRectMake(4, 4, width - 8, height - 8);
CGColorRef white = [[UIColor whiteColor] CGColor];
CGColorRef black = [[UIColor blackColor] CGColor];
CGContextSetFillColorWithColor(context, white);
CGContextFillEllipseInRect(context, outline);
CGContextSetLineWidth(context, 2.0f);
CGContextSetStrokeColorWithColor(context, black);
CGContextStrokeEllipseInRect(context, outline);
I have a bezier path drawn in the samedrawn rect method.
[[UIColor blackColor] setStroke];
[[UIColor whiteColor] setFill];
UIBezierPath * path = [UIBezierPath bezierPath];
[path moveToPoint:point1];
[path addQuadCurveToPoint:point3 controlPoint:point2];
[path addQuadCurveToPoint:point5 controlPoint:point4];
[path setLineWidth:2.0f];
[path stroke];
[path fill];
I need to add a CALayer over these two shapes so that they appear as one.
aPath = CGPathCreateMutable();
CGPathAddEllipseInRect(aPath, nil, outline);
CGPathCloseSubpath(aPath);
pathCopy = CGPathCreateCopyByTransformingPath(aPath, nil);
myLayer = nil;
myLayer = [CAShapeLayer layer];
myLayer.path = pathCopy;
myLayer.fillColor = [[UIColor whiteColor] CGColor];
[self.layer addSublayer:myLayer];
The problem is that I cant add the bezier path to the CGPath. That's one.
Another one is that I cant add a border color or border width to the layer which I am creating. Can anyone help?
Try:
CGPathAddPath(aPath, nil, path.CGPath);
Where aPath is your mutable CGPath and path is your UIBezierPath.

Setting composite drawing mode causing black holes/patches on NSWindow

I wanted to draw a shape, over it I wanted to draw the smaller transparent shape.
-(void) drawRect:(NSRect)dirtyRect
{
//clear everything
{
[[NSColor whiteColor] set];
[[NSBezierPath bezierPathWithRect:dirtyRect] fill];
}
NSBezierPath *thePath = [NSBezierPath bezierPathWithOvalInRect: self.bounds];
[thePath setLineWidth: 30];
[[NSColor blueColor] set];
[thePath stroke];
[[NSGraphicsContext currentContext] setCompositingOperation: NSCompositeCopy];
[[NSColor clearColor] set];
[thePath setLineWidth: 4];
[thePath stroke];
}
I've also tried it with an NSImage forst and then on view, but still getting the same result.
-(void) drawRect:(NSRect)dirtyRect
{
//clear everything
{
[[NSColor whiteColor] set];
[[NSBezierPath bezierPathWithRect:dirtyRect] fill];
}
NSImage* image = [[NSImage alloc] initWithSize:self.frame.size];
[image lockFocus];
//clear everything
{
[[NSColor whiteColor] set];
[[NSBezierPath bezierPathWithRect:dirtyRect] fill];
}
NSBezierPath *thePath = [NSBezierPath bezierPathWithOvalInRect: self.bounds];
[thePath setLineWidth: 30];
[[NSColor blueColor] set];
[thePath stroke];
[[NSGraphicsContext currentContext] setCompositingOperation: NSCompositeCopy];
[[NSColor clearColor] set];
[thePath setLineWidth: 4];
[thePath stroke];
[image unlockFocus];
[image drawInRect:self.frame fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0];
}
The oval appears black because windows are opaque by default. You've successfully cut an oval track in your window, but because the window is opaque, without an industrial laser to cut the same oval in your monitor, your Mac has to show some color there instead. The color it shows is the color of clearColor: black.
The solution is to set the window's opaque to NO.
The default is YES, which is nice and efficient but (well, actually, because) it prevents other windows' contents from showing through. Setting it to NO will allow you to see what is behind the window through that thin oval track. (It'll work better if you fill the oval, giving yourself a larger window in the… er… window.)
(Why does it look like the track is filled with gray? That's the window's shadow you're seeing there. When you try it for real, you'll be able to see the other windows on your system through the track as you move the window around.)

Gap between clipping regions

I'm drawing a lot of trapezoids filled with a NSGradient. I expect them to join seamlessly, which is not the case. In this case, I would prefer to use clipping instead of explicitly filling a NSBezierPath with a gradient.
Here is the incriminated code:
-(void)drawRect:(NSRect)dirtyRect {
[[NSColor blackColor]set];
NSRectFill(self.bounds);
NSPoint v0 = NSMakePoint(100,100);
NSPoint v1 = NSMakePoint(200,100);
NSPoint v2 = NSMakePoint(100,200);
NSPoint v3 = NSMakePoint(200,200);
NSPoint v4 = NSMakePoint(150, 150);
NSBezierPath * triangle0 = [NSBezierPath bezierPath];
[triangle0 moveToPoint:v0];
[triangle0 lineToPoint:v1];
[triangle0 lineToPoint:v2];
[triangle0 closePath];
NSBezierPath * triangle1 = [NSBezierPath bezierPath];
[triangle1 moveToPoint:v1];
[triangle1 lineToPoint:v2];
[triangle1 lineToPoint:v3];
[triangle1 closePath];
NSGradient * gradient = [[NSGradient alloc] initWithColorsAndLocations:[NSColor whiteColor],0.0,[NSColor orangeColor],1.0,nil];
[NSGraphicsContext saveGraphicsState];
[triangle0 addClip];
[gradient drawFromPoint:v0 toPoint:v4 options:NSGradientDrawsAfterEndingLocation|NSGradientDrawsBeforeStartingLocation];
// [gradient drawFromPoint:v0 toPoint:v4 options:0];
[NSGraphicsContext restoreGraphicsState];
[NSGraphicsContext saveGraphicsState];
[triangle1 addClip];
[gradient drawFromPoint:v3 toPoint:v4 options:NSGradientDrawsAfterEndingLocation|NSGradientDrawsBeforeStartingLocation];
//[gradient drawFromPoint:v3 toPoint:v4 options:0];
[NSGraphicsContext restoreGraphicsState];
What should I do to avoid the gap between the two triangles ?
Edit:
Here is an attempt to go around this problem by explicitely filling NSBezierPath.
-(void)drawRect:(NSRect)dirtyRect {
[[NSColor blackColor]set];
NSRectFill([self bounds]);
CGContextRef c = [[NSGraphicsContext currentContext] graphicsPort];
CGContextTranslateCTM(c, 0.5, 0.5);
NSPoint v0 = NSMakePoint(100,100);
NSPoint v1 = NSMakePoint(200,100);
NSPoint v2 = NSMakePoint(100,200);
NSPoint v3 = NSMakePoint(200,200);
NSBezierPath * triangle0 = [NSBezierPath bezierPath];
[triangle0 moveToPoint:v0];
[triangle0 lineToPoint:v1];
[triangle0 lineToPoint:v2];
[triangle0 closePath];
NSBezierPath * triangle1 = [NSBezierPath bezierPath];
[triangle1 moveToPoint:v1];
[triangle1 lineToPoint:v2];
[triangle1 lineToPoint:v3];
[triangle1 closePath];
[[NSColor whiteColor]set];
NSGradient * gradient = [[NSGradient alloc] initWithColorsAndLocations:[NSColor whiteColor],0.0,[NSColor orangeColor],1.0,nil];
[gradient drawInBezierPath:triangle0 angle:45];
[gradient drawInBezierPath:triangle1 angle:45+180];
NSBezierPath * seam = [ NSBezierPath bezierPath]; [seam moveToPoint:v1]; [seam lineToPoint:v2];
[[NSColor orangeColor]set]; [seam stroke];
NSGradient * gradient2 = [[NSGradient alloc] initWithColorsAndLocations:[NSColor whiteColor],0.0,[NSColor orangeColor],0.5,[NSColor whiteColor],1.0,nil];
NSBezierPath * squarePath = [NSBezierPath bezierPath];
[squarePath moveToPoint:v0];
[squarePath lineToPoint:v1];
[squarePath lineToPoint:v3];
[squarePath lineToPoint:v2];
[squarePath closePath];
CGContextTranslateCTM(c, 200, 0);
[gradient2 drawInBezierPath:squarePath angle:45];
}
On the left, two triangles filled with the same NSGradient.
On the right, a square filled with an NSGradient, the goal I'm trying to reach.
The seam is an attempt to hide the black line between the two NSBezierPath, but it doesn't really work. In this case, it is barely visible, but it will be visible if I draw a large amount of such triangles.
Edit for Rengers answer:
Here is how it looks without antialiasing:
Technically, this is the good answer, but now the problem is that, unsurprisingly, the edge of the polygon are not longer antialiased. Any idea how I could remove the gap between the clipping regions, without losing the antialiasing on the edges ?
This is probably because of anti-aliasing which is enabled by default. You can disable it using:
[[NSGraphicsContext currentContext] setShouldAntialias:NO];