NSTextField with rounded corners? - objective-c

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 :

Related

How to programmatically allocate a subclass of NSButton with a custom NSButtonCell?

I' m trying to create a subclass of NSButton thats use also a subclass of NSButtonCell but I can' t do that in code!
This is my NSButonCell subclass that's works well if I create the button in IB and set his cell class directly in IB:
#import "MyCustomCell.h"
#implementation MyCustomCell
- (void)drawImage:(NSImage*)image withFrame:(NSRect)frame inView:(NSView*)controlView
{
NSGraphicsContext *ctx = [NSGraphicsContext currentContext];
CGContextRef contextRef = [ctx graphicsPort];
NSData *data = [image TIFFRepresentation];
CGImageSourceRef source = CGImageSourceCreateWithData((CFDataRef)data, NULL);
if(source) {
CGImageRef imageRef = CGImageSourceCreateImageAtIndex(source, 0, NULL);
CFRelease(source);
CGContextSaveGState(contextRef);
{
NSRect rect = NSOffsetRect(frame, 0.0f, 1.0f);
CGFloat white = [self isHighlighted] ? 0.2f : 0.35f;
CGContextClipToMask(contextRef, NSRectToCGRect(rect), imageRef);
[[NSColor colorWithDeviceWhite:white alpha:1.0f] setFill];
NSRectFill(rect);
}
CGContextRestoreGState(contextRef);
CGContextSaveGState(contextRef);
{
NSRect rect = frame;
CGContextClipToMask(contextRef, NSRectToCGRect(rect), imageRef);
[[NSColor colorWithDeviceWhite:0.1f alpha:1.0f] setFill];
NSRectFill(rect);
}
CGContextRestoreGState(contextRef);
CFRelease(imageRef);
}
}
- (void)drawBezelWithFrame:(NSRect)frame inView:(NSView *)controlView
{
NSGraphicsContext *ctx = [NSGraphicsContext currentContext];
CGFloat roundedRadius = 3.0f;
BOOL outer = YES;
BOOL background = YES;
BOOL stroke = YES;
BOOL innerStroke = YES;
if(outer) {
[ctx saveGraphicsState];
NSBezierPath *outerClip = [NSBezierPath bezierPathWithRoundedRect:frame xRadius:roundedRadius yRadius:roundedRadius];
[outerClip setClip];
NSGradient *outerGradient = [[NSGradient alloc] initWithColorsAndLocations:
[NSColor colorWithDeviceWhite:0.20f alpha:1.0f], 0.0f,
[NSColor colorWithDeviceWhite:0.21f alpha:1.0f], 1.0f,
nil];
[outerGradient drawInRect:[outerClip bounds] angle:90.0f];
[outerGradient release];
[ctx restoreGraphicsState];
}
if(background) {
[ctx saveGraphicsState];
NSBezierPath *backgroundPath = [NSBezierPath bezierPathWithRoundedRect:NSInsetRect(frame, 2.0f, 2.0f) xRadius:roundedRadius yRadius:roundedRadius];
[backgroundPath setClip];
NSGradient *backgroundGradient = [[NSGradient alloc] initWithColorsAndLocations:
[NSColor colorWithDeviceWhite:0.17f alpha:1.0f], 0.0f,
[NSColor colorWithDeviceWhite:0.20f alpha:1.0f], 0.12f,
[NSColor colorWithDeviceWhite:0.27f alpha:1.0f], 0.5f,
[NSColor colorWithDeviceWhite:0.30f alpha:1.0f], 0.5f,
[NSColor colorWithDeviceWhite:0.42f alpha:1.0f], 0.98f,
[NSColor colorWithDeviceWhite:0.50f alpha:1.0f], 1.0f,
nil];
[backgroundGradient drawInRect:[backgroundPath bounds] angle:270.0f];
[backgroundGradient release];
[ctx restoreGraphicsState];
}
if(stroke) {
[ctx saveGraphicsState];
[[NSColor colorWithDeviceWhite:0.12f alpha:1.0f] setStroke];
[[NSBezierPath bezierPathWithRoundedRect:NSInsetRect(frame, 1.5f, 1.5f) xRadius:roundedRadius yRadius:roundedRadius] stroke];
[ctx restoreGraphicsState];
}
if(innerStroke) {
[ctx saveGraphicsState];
[[NSColor colorWithDeviceWhite:1.0f alpha:0.05f] setStroke];
[[NSBezierPath bezierPathWithRoundedRect:NSInsetRect(frame, 2.5f, 2.5f) xRadius:roundedRadius yRadius:roundedRadius] stroke];
[ctx restoreGraphicsState];
}
if([self isHighlighted]) {
[ctx saveGraphicsState];
[[NSBezierPath bezierPathWithRoundedRect:NSInsetRect(frame, 2.0f, 2.0f) xRadius:roundedRadius yRadius:roundedRadius] setClip];
[[NSColor colorWithCalibratedWhite:0.0f alpha:0.35] setFill];
NSRectFillUsingOperation(frame, NSCompositeSourceOver);
[ctx restoreGraphicsState];
}
}
#end
I also create a custom NSButton sublclass that use this NSButtonCell
#import "myButton.h"
#import "MyCustomCell.h"
#implementation myButton
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
[self setCell:[[MyCustomCell alloc] init]];
self.image = [NSImage imageNamed:#"add"];
}
return self;
}
#end
But when I create this button in my view the look of the button is the default one and not the customized style of the NSButtonCell subclass. If I set the cell in IB all work great but not in code. Anyone have an idea to solve that problem? Thanks!
I understand how to fix the problem.
It' s needed to set the bezel style on the button calling setBezelStyle. With this line of code all works great except for the fact that the image is upside-down.
Have you tried to use the cellClass class method?
+ (Class)cellClass {
return MyCustomCell.class;
}

Resizeable Custom NSPanel

OK, here's my situation :
I'm trying a HUD-like custom-controls collection, SNRHUDKit.
I'm specifically using SNRHUDWindow as my main window class
No matter what, although it actually works, I can't get the NSWindow (or NSPanel - doesn't make much difference) to resize, when the user drags its lower-right corner.
The code for SNRHUDWindow is :
//
// SNRHUDWindow.m
// SNRHUDKit
//
// Created by Indragie Karunaratne on 12-01-22.
// Copyright (c) 2012 indragie.com. All rights reserved.
//
#import "SNRHUDWindow.h"
#import "NSBezierPath+MCAdditions.h"
#define SNRWindowTitlebarHeight 22.f
#define SNRWindowBorderColor [NSColor blackColor]
#define SNRWindowTopColor [NSColor colorWithDeviceWhite:0.240 alpha:0.960]
#define SNRWindowBottomColor [NSColor colorWithDeviceWhite:0.150 alpha:0.960]
#define SNRWindowHighlightColor [NSColor colorWithDeviceWhite:1.000 alpha:0.200]
#define SNRWindowCornerRadius 5.f
#define SNRWindowTitleFont [NSFont systemFontOfSize:11.f]
#define SNRWindowTitleColor [NSColor colorWithDeviceWhite:0.700 alpha:1.000]
#define SNRWindowTitleShadowOffset NSMakeSize(0.f, 1.f)
#define SNRWindowTitleShadowBlurRadius 1.f
#define SNRWindowTitleShadowColor [NSColor blackColor]
#define SNRWindowButtonSize NSMakeSize(18.f, 18.f)
#define SNRWindowButtonEdgeMargin 5.f
#define SNRWindowButtonBorderColor [NSColor colorWithDeviceWhite:0.040 alpha:1.000]
#define SNRWindowButtonGradientBottomColor [NSColor colorWithDeviceWhite:0.070 alpha:1.000]
#define SNRWindowButtonGradientTopColor [NSColor colorWithDeviceWhite:0.220 alpha:1.000]
#define SNRWindowButtonDropShadowColor [NSColor colorWithDeviceWhite:1.000 alpha:0.100]
#define SNRWindowButtonCrossColor [NSColor colorWithDeviceWhite:0.450 alpha:1.000]
#define SNRWindowButtonCrossInset 1.f
#define SNRWindowButtonHighlightOverlayColor [NSColor colorWithDeviceWhite:0.000 alpha:0.300]
#define SNRWindowButtonInnerShadowColor [NSColor colorWithDeviceWhite:1.000 alpha:0.100]
#define SNRWindowButtonInnerShadowOffset NSMakeSize(0.f, 0.f)
#define SNRWindowButtonInnerShadowBlurRadius 1.f
#interface SNRHUDWindowButtonCell : NSButtonCell
#end
#interface SNRHUDWindowFrameView : NSView
- (void)snr_drawTitleInRect:(NSRect)rect;
#end
#implementation SNRHUDWindow {
NSView *__customContentView;
}
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)windowStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation
{
if ((self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:bufferingType defer:deferCreation])) {
[self setOpaque:NO];
[self setBackgroundColor:[NSColor clearColor]];
[self setMovableByWindowBackground:YES];
[self setLevel:NSFloatingWindowLevel];
}
return self;
}
- (NSRect)contentRectForFrameRect:(NSRect)windowFrame
{
windowFrame.origin = NSZeroPoint;
windowFrame.size.height -= SNRWindowTitlebarHeight;
return windowFrame;
}
+ (NSRect)frameRectForContentRect:(NSRect)windowContentRect
styleMask:(NSUInteger)windowStyle
{
windowContentRect.size.height += SNRWindowTitlebarHeight;
return windowContentRect;
}
- (NSRect)frameRectForContentRect:(NSRect)windowContent
{
windowContent.size.height += SNRWindowTitlebarHeight;
return windowContent;
}
- (void)setContentView:(NSView *)aView
{
if ([__customContentView isEqualTo:aView]) {
return;
}
NSRect bounds = [self frame];
bounds.origin = NSZeroPoint;
SNRHUDWindowFrameView *frameView = [super contentView];
if (!frameView) {
frameView = [[SNRHUDWindowFrameView alloc] initWithFrame:bounds];
NSSize buttonSize = SNRWindowButtonSize;
NSRect buttonRect = NSMakeRect(SNRWindowButtonEdgeMargin, NSMaxY(frameView.bounds) -(SNRWindowButtonEdgeMargin + buttonSize.height), buttonSize.width, buttonSize.height);
NSButton *closeButton = [[NSButton alloc] initWithFrame:buttonRect];
[closeButton setCell:[[SNRHUDWindowButtonCell alloc] init]];
[closeButton setButtonType:NSMomentaryChangeButton];
[closeButton setTarget:self];
[closeButton setAction:#selector(close)];
[closeButton setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
[frameView addSubview:closeButton];
[super setContentView:frameView];
}
if (__customContentView) {
[__customContentView removeFromSuperview];
}
__customContentView = aView;
[__customContentView setFrame:[self contentRectForFrameRect:bounds]];
[__customContentView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
[frameView addSubview:__customContentView];
}
- (NSView *)contentView
{
return __customContentView;
}
- (void)setTitle:(NSString *)aString
{
[super setTitle:aString];
[[super contentView] setNeedsDisplay:YES];
}
- (BOOL)canBecomeKeyWindow
{
return YES;
}
#end
#implementation SNRHUDWindowFrameView
- (void)drawRect:(NSRect)dirtyRect
{
NSRect drawingRect = NSInsetRect(self.bounds, 0.5f, 0.5f);
NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:drawingRect xRadius:SNRWindowCornerRadius yRadius:SNRWindowCornerRadius];
[NSGraphicsContext saveGraphicsState];
[path addClip];
// Fill in the title bar with a gradient background
NSRect titleBarRect = NSMakeRect(0.f, NSMaxY(self.bounds) - SNRWindowTitlebarHeight, self.bounds.size.width, SNRWindowTitlebarHeight);
NSGradient *titlebarGradient = [[NSGradient alloc] initWithStartingColor:SNRWindowBottomColor endingColor:SNRWindowTopColor];
[titlebarGradient drawInRect:titleBarRect angle:90.f];
// Draw the window title
[self snr_drawTitleInRect:titleBarRect];
// Rest of the window has a solid fill
NSRect bottomRect = NSMakeRect(0.f, 0.f, self.bounds.size.width, self.bounds.size.height - SNRWindowTitlebarHeight);
[SNRWindowBottomColor set];
[NSBezierPath fillRect:bottomRect];
// Draw the highlight line around the top edge of the window
// Outset the width of the rectangle by 0.5px so that the highlight "bleeds" around the rounded corners
// Outset the height by 1px so that the line is drawn right below the border
NSRect highlightRect = NSInsetRect(drawingRect, 0.f, 0.5f);
// Make the height of the highlight rect something bigger than the bounds so that it won't show up on the bottom
highlightRect.size.height += 50.f;
highlightRect.origin.y -= 50.f;
NSBezierPath *highlightPath = [NSBezierPath bezierPathWithRoundedRect:highlightRect xRadius:SNRWindowCornerRadius yRadius:SNRWindowCornerRadius];
[SNRWindowHighlightColor set];
[highlightPath stroke];
[NSGraphicsContext restoreGraphicsState];
[SNRWindowBorderColor set];
[path stroke];
}
- (void)snr_drawTitleInRect:(NSRect)titleBarRect
{
NSString *title = [[self window] title];
if (!title) { return; }
NSShadow *shadow = [NSShadow new];
[shadow setShadowColor:SNRWindowTitleShadowColor];
[shadow setShadowOffset:SNRWindowTitleShadowOffset];
[shadow setShadowBlurRadius:SNRWindowTitleShadowBlurRadius];
NSMutableParagraphStyle *style = [NSMutableParagraphStyle new];
[style setAlignment:NSCenterTextAlignment];
NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:SNRWindowTitleColor, NSForegroundColorAttributeName, SNRWindowTitleFont, NSFontAttributeName, shadow, NSShadowAttributeName, style, NSParagraphStyleAttributeName, nil];
NSAttributedString *attrTitle = [[NSAttributedString alloc] initWithString:title attributes:attributes];
NSSize titleSize = attrTitle.size;
NSRect titleRect = NSMakeRect(0.f, NSMidY(titleBarRect) - (titleSize.height / 2.f), titleBarRect.size.width, titleSize.height);
[attrTitle drawInRect:NSIntegralRect(titleRect)];
}
#end
#implementation SNRHUDWindowButtonCell
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
NSRect drawingRect = NSInsetRect(cellFrame, 1.5f, 1.5f);
drawingRect.origin.y = 0.5f;
NSRect dropShadowRect = drawingRect;
dropShadowRect.origin.y += 1.f;
// Draw the drop shadow so that the bottom edge peeks through
NSBezierPath *dropShadow = [NSBezierPath bezierPathWithOvalInRect:dropShadowRect];
[SNRWindowButtonDropShadowColor set];
[dropShadow stroke];
// Draw the main circle w/ gradient & border on top of it
NSBezierPath *circle = [NSBezierPath bezierPathWithOvalInRect:drawingRect];
NSGradient *gradient = [[NSGradient alloc] initWithStartingColor:SNRWindowButtonGradientBottomColor endingColor:SNRWindowButtonGradientTopColor];
[gradient drawInBezierPath:circle angle:270.f];
[SNRWindowButtonBorderColor set];
[circle stroke];
// Draw the cross
NSBezierPath *cross = [NSBezierPath bezierPath];
CGFloat boxDimension = floor(drawingRect.size.width * cos(45.f)) - SNRWindowButtonCrossInset;
CGFloat origin = round((drawingRect.size.width - boxDimension) / 2.f);
NSRect boxRect = NSMakeRect(1.f + origin, origin, boxDimension, boxDimension);
NSPoint bottomLeft = NSMakePoint(boxRect.origin.x, NSMaxY(boxRect));
NSPoint topRight = NSMakePoint(NSMaxX(boxRect), boxRect.origin.y);
NSPoint bottomRight = NSMakePoint(topRight.x, bottomLeft.y);
NSPoint topLeft = NSMakePoint(bottomLeft.x, topRight.y);
[cross moveToPoint:bottomLeft];
[cross lineToPoint:topRight];
[cross moveToPoint:bottomRight];
[cross lineToPoint:topLeft];
[SNRWindowButtonCrossColor set];
[cross setLineWidth:2.f];
[cross stroke];
// Draw the inner shadow
NSShadow *shadow = [[NSShadow alloc] init];
[shadow setShadowColor:SNRWindowButtonInnerShadowColor];
[shadow setShadowBlurRadius:SNRWindowButtonInnerShadowBlurRadius];
[shadow setShadowOffset:SNRWindowButtonInnerShadowOffset];
NSRect shadowRect = drawingRect;
shadowRect.size.height = origin;
[NSGraphicsContext saveGraphicsState];
[NSBezierPath clipRect:shadowRect];
[circle fillWithInnerShadow:shadow];
[NSGraphicsContext restoreGraphicsState];
if ([self isHighlighted]) {
[SNRWindowButtonHighlightOverlayColor set];
[circle fill];
}
}
#end
Any ideas what could be responsible for the NSPanel losing its resizing ability?
I'm using this framework as well, and the reason that resizing doesn't work by default is this line in the initWithContentRect method:
if ((self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:bufferingType defer:deferCreation])) {
As you can see, instead of passing the windowStyle bitmask provided to super's init method, it passes through just NSBorderlessWindowMask. A bit of sniffing around shows that for resizing to be possible at all, the styleMask must have NSResizableWindowMask included in the bitmask.
So, changing the line to
if ((self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask|NSResizableWindowMask backing:bufferingType defer:deferCreation])) {
should solve your problem.

Change highlighting color in NSTableView in Cocoa?

I am developing a Cocoa application and encountered a problem with highlighting. Standard highlighting color in MAC OS X applications is blue, but it doesn't suit my app, since because of design concepts, I need a green color for highlighting.
I tried to subclass NSTableview and override method
- (void)highlightSelectionInClipRect:(NSRect)clipRect
but it didn't help.
How to fix this problem?
I am using this, and so far works perfectly:
- (void)highlightSelectionInClipRect:(NSRect)theClipRect
{
// this method is asking us to draw the hightlights for
// all of the selected rows that are visible inside theClipRect
// 1. get the range of row indexes that are currently visible
// 2. get a list of selected rows
// 3. iterate over the visible rows and if their index is selected
// 4. draw our custom highlight in the rect of that row.
NSRange aVisibleRowIndexes = [self rowsInRect:theClipRect];
NSIndexSet * aSelectedRowIndexes = [self selectedRowIndexes];
int aRow = aVisibleRowIndexes.location;
int anEndRow = aRow + aVisibleRowIndexes.length;
NSGradient * gradient;
NSColor * pathColor;
// if the view is focused, use highlight color, otherwise use the out-of-focus highlight color
if (self == [[self window] firstResponder] && [[self window] isMainWindow] && [[self window] isKeyWindow])
{
gradient = [[[NSGradient alloc] initWithColorsAndLocations:
[NSColor colorWithDeviceRed:(float)62/255 green:(float)133/255 blue:(float)197/255 alpha:1.0], 0.0,
[NSColor colorWithDeviceRed:(float)48/255 green:(float)95/255 blue:(float)152/255 alpha:1.0], 1.0, nil] retain]; //160 80
pathColor = [[NSColor colorWithDeviceRed:(float)48/255 green:(float)95/255 blue:(float)152/255 alpha:1.0] retain];
}
else
{
gradient = [[[NSGradient alloc] initWithColorsAndLocations:
[NSColor colorWithDeviceRed:(float)190/255 green:(float)190/255 blue:(float)190/255 alpha:1.0], 0.0,
[NSColor colorWithDeviceRed:(float)150/255 green:(float)150/255 blue:(float)150/255 alpha:1.0], 1.0, nil] retain];
pathColor = [[NSColor colorWithDeviceRed:(float)150/255 green:(float)150/255 blue:(float)150/255 alpha:1.0] retain];
}
// draw highlight for the visible, selected rows
for (aRow; aRow < anEndRow; aRow++)
{
if([aSelectedRowIndexes containsIndex:aRow])
{
NSRect aRowRect = NSInsetRect([self rectOfRow:aRow], 1, 4); //first is horizontal, second is vertical
NSBezierPath * path = [NSBezierPath bezierPathWithRoundedRect:aRowRect xRadius:4.0 yRadius:4.0]; //6.0
[path setLineWidth: 2];
[pathColor set];
[path stroke];
[gradient drawInBezierPath:path angle:90];
}
}
}
I searched for hours for an answer on this as well, and although I found many fragments, none of them were complete. So here I submit another approach, which I am using with success.
1) Set your NSTableView selectionHighLightStyle to None
This is necessary to ensure that OSX does not simply apply it's own highlights over the top of yours, leaving you with a blue highlight.
You can do this either through IB or via code.
2) Subclass NSTableView, and override drawRow.
This will set the background color for your selected rows to primary (active window) and secondary (inactive).
- (void)drawRow:(NSInteger)row clipRect:(NSRect)clipRect
{
NSColor* bgColor = Nil;
if (self == [[self window] firstResponder] && [[self window] isMainWindow] && [[self window] isKeyWindow])
{
bgColor = [NSColor colorWithCalibratedWhite:0.300 alpha:1.000];
}
else
{
bgColor = [NSColor colorWithCalibratedWhite:0.800 alpha:1.000];
}
NSIndexSet* selectedRowIndexes = [self selectedRowIndexes];
if ([selectedRowIndexes containsIndex:row])
{
[bgColor setFill];
NSRectFill([self rectOfRow:row]);
}
[super drawRow:row clipRect:clipRect];
}
3) Implement an NSTableViewDelegate, attach it to your NSTableView, and implement willDisplayCell.
This will allow you to change the textColor of the rows on selection/deselection, in case your selection colors make the text hard to read.
- (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
{
// check if it is a textfield cell
if ([aCell isKindOfClass:[NSTextFieldCell class]])
{
NSTextFieldCell* tCell = (NSTextFieldCell*)aCell;
// check if it is selected
if ([[aTableView selectedRowIndexes] containsIndex:rowIndex])
{
tCell.textColor = [NSColor whiteColor];
}
else
{
tCell.textColor = [NSColor blackColor];
}
}
}
And you are done.
- (void)drawInteriorWithFrame:(NSRect)frame inView:(NSView *)controlView
{
if ([self isHighlighted])
{
NSRect bgFrame = frame;
[[NSColor redColor] set];
NSRectFill(bgFrame);
}
}
I use this code to deal with the height, the code is in my custom cell file

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).

Drawing a rounded cornered NSTextFieldCell

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.