Drawing a rounded cornered NSTextFieldCell - objective-c

My code for my NSTextFieldCell is:
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
// Drawing code here.
NSGradient *gradient = [[NSGradient alloc] initWithStartingColor:[NSColor lightGrayColor] endingColor:[NSColor grayColor]];
[gradient drawInRect:cellFrame angle:90];
[[self title] drawInRect:cellFrame withAttributes:nil];
}
I would like to have the NSTextFieldCell to have rounded corners.... how could I do this?

Use the layer property of NSView, then you can set a corner radius for this.

Related

NSMenuitem tempelate image tint color not changing

I have customview which has image view image i'm setting NSImageNameMenuOnStateTemplate to imageview with tint color but tint color is not applying
NSImage *tintImage = [self tintedImage:[NSImage imageNamed:NSImageNameMenuOnStateTemplate] withTintColor:NSColor.whiteColor];
myimageView.image = tintImage
-(NSImage*)tintedImage:(NSImage*)image withTintColor:(NSColor*)color{
NSImage *tinted = [image copy];
[tinted lockFocus];
[color set];
NSRect imageRect = {NSZeroPoint, [image size]};
NSRectFillUsingOperation(imageRect, NSCompositingOperationSourceAtop);
[image unlockFocus];
return tinted;
}
Any help most appreciated ..
You really should avoid using lockFocus/unlockFocus. They're deprecated and you've misused them by locking one image and unlocking another. Use `+[NSImage imageWithSize:flipped:drawingHandler:]
As a category addition to NSImage:
- (NSImage *)imageWithSolidFillColor:(NSColor *)color
{
return [NSImage imageWithSize:self.size flipped:false drawingHandler:^BOOL(NSRect dstRect) {
[self drawInRect:dstRect fromRect:NSZeroRect operation:NSCompositingOperationSourceOver fraction:1.0];
[color set];
NSRectFillUsingOperation(dstRect, NSCompositeSourceAtop);
return YES;
}];
}
Change [image unlockFocus]; with [tinted unlockFocus];
for macOS you need to set setTemplate to NO
[tinted setTemplate:NO];
HTH

NSView draw permanently to background

I'm trying to draw some things on the background of my windows. Therefore I subclassed the NSView of the window and added some drawing code like this:
- (void)drawRect:(NSRect)dirtyRect {
float color = 0.95;
[[NSColor colorWithDeviceRed:color green:color blue:color alpha:1.0] set];
NSRectFill(NSMakeRect(320, 0, 220, NSHeight(dirtyRect)-60));
}
This works great, but as soon as I open a NSComboBox or if I activate a checkbox, the background of these elements erases my just drawn rect.
I don't understand this, because checking for example the checkbox causes, that drawRect is called (I added a NSLog). Only resizing the window draws my rect again.
EDIT:
here is a screenshot of the problem:
I sometimes face the same problem. I think the following is what I use.
/// .h
#interface BackgroundView1 : NSView {
NSImage *myImage;
}
// .m
- (void)awakeFromNib {
[self setupBackgroundImage];
}
- (void)setupBackgroundImage {
NSColor *c = [NSColor colorWithDeviceRed:0.0f/255.0f green:55.0f/255.0f blue:150.0f/255.0f alpha:1.0f];
if (myImage == nil)
myImage = [self createColorImage:NSMakeSize(1,1):c];
}
- (void)drawRect:(NSRect)rect {
[myImage drawInRect:NSMakeRect([self bounds].origin.x,[self bounds].origin.y,[self frame].size.width,[self frame].size.height)
fromRect:NSMakeRect(0,0,[myImage size].width, [myImage size].height)
operation:NSCompositeCopy
fraction:1.0];
}
// Start Functions //
- (NSImage *)createColorImage:(NSSize)size :(NSColor *)color {
NSImage *image = [[NSImage alloc] initWithSize:size];
NSBitmapImageRep *rep = [[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:NULL
pixelsWide:size.width
pixelsHigh:size.height
bitsPerSample:8
samplesPerPixel:4
hasAlpha:YES
isPlanar:NO
colorSpaceName:NSCalibratedRGBColorSpace
bytesPerRow:0
bitsPerPixel:0];
[image addRepresentation:rep];
[image lockFocus]; // Lock focus of image, making it a destination for drawing
[color set];
NSRectFill(NSMakeRect(0,0,size.width,size.height));
[image unlockFocus];
return image;
}
// End Functions //

NSTextField with rounded corners?

I'm trying to draw rounded corners around an NSTextField.
I've subclassed NSTextField, tried the code below, but without any result...
Any ideas?
- (void)drawRect:(NSRect)dirtyRect
{
// black outline
NSRect blackOutlineFrame = NSMakeRect(0.0, 0.0, [self bounds].size.width, [self bounds].size.height-1.0);
NSGradient *gradient = nil;
if ([NSApp isActive]) {
gradient = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithCalibratedWhite:0.24 alpha:1.0] endingColor:[NSColor colorWithCalibratedWhite:0.374 alpha:1.0]];
}
else {
gradient = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithCalibratedWhite:0.55 alpha:1.0] endingColor:[NSColor colorWithCalibratedWhite:0.558 alpha:1.0]];
}
[gradient drawInBezierPath:[NSBezierPath bezierPathWithRoundedRect:blackOutlineFrame xRadius:5 yRadius:5] angle:90];
}
It is better to subclass NSTextFieldCell to draw rounded corners to preserve NSTextField functionality, e.g:
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView {
NSBezierPath *betterBounds = [NSBezierPath bezierPathWithRoundedRect:cellFrame xRadius:CORNER_RADIUS yRadius:CORNER_RADIUS];
[betterBounds addClip];
[super drawWithFrame:cellFrame inView:controlView];
if (self.isBezeled) {
[betterBounds setLineWidth:2];
[[NSColor colorWithCalibratedRed:0.510 green:0.643 blue:0.804 alpha:1] setStroke];
[betterBounds stroke];
}
}
Yields a nice rounded text field that works perfectly (if you had set it to draw a rectangle bezel in the first place, at least):
You are doing almost everything correct. You just need to change the textField's cell and radius which match. Take a look at this:
-(void)awakeFromNib {
[[self cell] setBezelStyle: NSTextFieldRoundedBezel];
}
- (void)drawRect:(NSRect)dirtyRect
{
NSRect blackOutlineFrame = NSMakeRect(0.0, 0.0, [self bounds].size.width, [self bounds].size.height-1.0);
NSGradient *gradient = nil;
if ([NSApp isActive]) {
gradient = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithCalibratedWhite:0.24 alpha:1.0] endingColor:[NSColor colorWithCalibratedWhite:0.374 alpha:1.0]];
}
else {
gradient = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithCalibratedWhite:0.55 alpha:1.0] endingColor:[NSColor colorWithCalibratedWhite:0.558 alpha:1.0]];
}
[gradient drawInBezierPath:[NSBezierPath bezierPathWithRoundedRect:blackOutlineFrame xRadius:10 yRadius:10] angle:90];
}
This is working for me nicely.
Swift 3 version of #Verious codes, with properties editable in Interface Builder:
class RoundedTextFieldCell: NSTextFieldCell {
#IBInspectable var borderColor: NSColor = .clear
#IBInspectable var cornerRadius: CGFloat = 3
override func draw(withFrame cellFrame: NSRect, in controlView: NSView) {
let bounds = NSBezierPath(roundedRect: cellFrame, xRadius: cornerRadius, yRadius: cornerRadius)
bounds.addClip()
super.draw(withFrame: cellFrame, in: controlView)
if borderColor != .clear {
bounds.lineWidth = 2
borderColor.setStroke()
bounds.stroke()
}
}
}
I did like this and it is working like charm.
yourLableName.wantsLayer = YES;
yourLableName.layer.cornerRadius = yourLableName.frame.size.width/2;
The easiest one is to do with interface builder, unless you want the corners rounded by some units:
Simply select the border as rounded one :

How Can I Change NSButton Color?

I have been using the setBackgroundColor method to change the NSButton colour, but my question is, are there any other methods I could use to change the colour of an NSButton other than that?
To change the color or the NSButton you need to access the button, mostly you do it with IBOutlet unless the buttons are in TableView / CollectionView etc.
Say the button outlet is myButton, then you need
[[myButton cell] setBackgroundColor:[NSColor redColor]]; //Change the color according to your need
Edit:
You can also do this by subclassing NSButtonCell with these methods
- (void)drawBezelWithFrame:(NSRect)frame inView:(NSView *)controlView
{
NSGraphicsContext* ctx = [NSGraphicsContext currentContext];
// corner radius
CGFloat roundedRadius = 17.0f;
NSColor *color = [NSColor redColor];
// Draw darker overlay if button is pressed
if([self isHighlighted]) {
[ctx saveGraphicsState];
[[NSBezierPath bezierPathWithRoundedRect:frame
xRadius:roundedRadius
yRadius:roundedRadius] setClip];
[[color darkenColorByValue:0.12f] setFill];
NSRectFillUsingOperation(frame, NSCompositeSourceOver);
[ctx restoreGraphicsState];
return;
}
// create background color
[ctx saveGraphicsState];
[[NSBezierPath bezierPathWithRoundedRect:frame
xRadius:roundedRadius
yRadius:roundedRadius] setClip];
[[color darkenColorByValue:0.12f] setFill];
NSRectFillUsingOperation(frame, NSCompositeSourceOver);
[ctx restoreGraphicsState];
//draw inner button area
[ctx saveGraphicsState];
NSBezierPath* bgPath = [NSBezierPath bezierPathWithRoundedRect:NSInsetRect(frame, 1.0f, 1.0f) xRadius:roundedRadius yRadius:roundedRadius];
[bgPath setClip];
NSColor* topColor = [color lightenColorByValue:0.12f];
// gradient for inner portion of button
NSGradient* bgGradient = [[NSGradient alloc] initWithColorsAndLocations:
topColor, 0.0f,
color, 1.0f,
nil];
[bgGradient drawInRect:[bgPath bounds] angle:90.0f];
[ctx restoreGraphicsState];
}
- (NSRect) drawTitle:(NSAttributedString *)title withFrame:(NSRect)frame inView:(NSView *)controlView {
NSGraphicsContext* ctx = [NSGraphicsContext currentContext];
[ctx saveGraphicsState];
NSMutableAttributedString *attrString = [title mutableCopy];
[attrString beginEditing];
NSColor *titleColor;
if ([[self getColorForButtonType] isLightColor]) {
titleColor = [NSColor blackColor];
} else {
titleColor = [NSColor whiteColor];
}
[attrString addAttribute:NSForegroundColorAttributeName value:titleColor range:NSMakeRange(0, [[self title] length])];
[attrString endEditing];
NSRect r = [super drawTitle:attrString withFrame:frame inView:controlView];
[ctx restoreGraphicsState];
return r;
}
I don't know what is going on here, but the following works for me:
[[myButton cell] setBackgroundColor:[NSColor redColor]];
But ONLY if I overwrite the following method in my NSButtonCell subclass:
- (void)drawBezelWithFrame:(NSRect)frame inView:(NSView *)controlView
{
[super drawBezelWithFrame:frame inView:controlView];
}
Fun fact here: it is not even called (tested with debugger).

Modifying Table Headers on Mac

I've been able to find tutorials on modifying the table headers on iOS using UITableView - but havent been able to find any info for mac development. Does anyone know of any good resources / steps to modify the appearance of tables?
Zach
To change how the table headers appear you need to subclass NSTableHeaderCell, perform your own custom drawing in one of its drawing methods, then replace the header cells of each column with an instance of your subclass.
You may also find that you need to subclass NSTableHeaderView to draw the any space where no header cells are visible, and to replace the cornerView of the table view.
This should get you started:
for (NSTableColumn *column in [tableView tableColumns]) {
[column setHeaderCell:
[[[MyHeaderCell alloc]
initTextCell:[[column headerCell] stringValue]]
autorelease]];
}
And here’s a starting point for a subclass of NSTableHeaderCell:
#interface MyHeaderCell : NSTableHeaderCell
{
}
- (void)drawWithFrame:(CGRect)cellFrame
highlighted:(BOOL)isHighlighted
inView:(NSView *)view;
#end
#implementation MyHeaderCell
- (void)drawWithFrame:(CGRect)cellFrame
highlighted:(BOOL)isHighlighted
inView:(NSView *)view
{
CGRect fillRect, borderRect;
CGRectDivide(cellFrame, &borderRect, &fillRect, 1.0, CGRectMaxYEdge);
NSGradient *gradient = [[NSGradient alloc]
initWithStartingColor:[NSColor whiteColor]
endingColor:[NSColor colorWithDeviceWhite:0.9 alpha:1.0]];
[gradient drawInRect:fillRect angle:90.0];
[gradient release];
if (isHighlighted) {
[[NSColor colorWithDeviceWhite:0.0 alpha:0.1] set];
NSRectFillUsingOperation(fillRect, NSCompositeSourceOver);
}
[[NSColor colorWithDeviceWhite:0.8 alpha:1.0] set];
NSRectFill(borderRect);
[self drawInteriorWithFrame:CGRectInset(fillRect, 0.0, 1.0) inView:view];
}
- (void)drawWithFrame:(CGRect)cellFrame inView:(NSView *)view
{
[self drawWithFrame:cellFrame highlighted:NO inView:view];
}
- (void)highlight:(BOOL)isHighlighted
withFrame:(NSRect)cellFrame
inView:(NSView *)view
{
[self drawWithFrame:cellFrame highlighted:isHighlighted inView:view];
}
#end
Code to change column header in tableView:
NSString *title = #"Your Title";
NSTableColumn *yourColumn = self.tableView.tableColumns.lastObject;
[yourColumn.headerCell setStringValue:title];