Question

I've been experimenting with JUEmptyView (a custom Cocoa control / NSView subclass, which displays a custom center-aligned placeholder in the middle of the view when all subviews have been removed).

So, I tried implementing the same thing for an NSTabView - simply by making it an NSTabView subclass (and re-setting my initial NSTabView item class).

Generally, it does work - it does show the placeholder (when the last tab is closed). However, some issues still exist :

  • The background remains as that of a tabitem (thought they've all been closed)
  • When resizing the window (given that the NSTabView stretches all the way from left to right and from top to bottom), the view seems like it fails to redraw itself properly.

Example :

enter image description here

Full Code :

Interface

#import <Cocoa/Cocoa.h>

@interface JUTabEmptyView : NSTabView
{
@private
    BOOL forceShow;

    NSString *title;
    NSColor  *titleColor;
    NSFont   *titleFont;

    NSColor *backgroundColor;
}

@property (nonatomic, copy) NSString  *title;
@property (nonatomic, retain) NSFont  *titleFont;
@property (nonatomic, retain) NSColor *titleColor;
@property (nonatomic, retain) NSColor *backgroundColor;

@property (nonatomic, assign) BOOL forceShow;

- (id)initWithTitle:(NSString *)title;
- (id)initWithTitle:(NSString *)title andFont:(NSFont *)font;
- (id)initWithTitle:(NSString *)title font:(NSFont *)font color:(NSColor *)color andBackgroundColor:(NSColor *)backgroundColor;

@end

Implementation

#import "JUTabEmptyView.h"

@implementation JUTabEmptyView
@synthesize title, titleFont, titleColor, backgroundColor;
@synthesize forceShow;

#pragma mark -
#pragma mark Setter

- (void)setTitle:(NSString *)ttitle
{
    [title autorelease];
    title = [ttitle copy];

    [self setNeedsDisplay:YES];
}

- (void)setTitleFont:(NSFont *)ttitleFont
{
    [titleFont autorelease];
    titleFont = [ttitleFont retain];

    [self setNeedsDisplay:YES];
}

- (void)setTitleColor:(NSColor *)ttitleColor
{
    [titleColor autorelease];
    titleColor = [ttitleColor retain];

    [self setNeedsDisplay:YES];
}

- (void)setBackgroundColor:(NSColor *)tbackgroundColor
{
    [backgroundColor autorelease];
    backgroundColor = [tbackgroundColor retain];

    [self setNeedsDisplay:YES];
}

- (void)setForceShow:(BOOL)tforceShow
{
    forceShow = tforceShow;

    [self setNeedsDisplay:YES];
}

#pragma mark -
#pragma Drawing

- (void)drawRect:(NSRect)dirtyRect
{
    if(forceShow || [[self subviews] count] == 0)
    {
        NSRect rect = [self bounds];
        NSSize size = [title sizeWithAttributes:[NSDictionary dictionaryWithObject:titleFont forKey:NSFontAttributeName]];
        NSSize bezierSize = NSMakeSize(size.width + 40.0, size.height + 20.0);
        NSRect drawRect;


        // Background
        drawRect = NSMakeRect(0.0, 0.0, bezierSize.width, bezierSize.height);
        drawRect.origin.x = round((rect.size.width * 0.5) - (bezierSize.width * 0.5));
        drawRect.origin.y = round((rect.size.height * 0.5) - (bezierSize.height * 0.5));

        [backgroundColor setFill];
        [[NSBezierPath bezierPathWithRoundedRect:drawRect xRadius:8.0 yRadius:8.0] fill];


        // String
        drawRect = NSMakeRect(0.0, 0.0, size.width, size.height);
        drawRect.origin.x = round((rect.size.width * 0.5) - (size.width * 0.5));
        drawRect.origin.y = round((rect.size.height * 0.5) - (size.height * 0.5));

        [title drawInRect:drawRect withAttributes:[NSDictionary dictionaryWithObjectsAndKeys:titleColor, NSForegroundColorAttributeName,
                                                   titleFont, NSFontAttributeName, nil]];
    }
}


- (void)willRemoveSubview:(NSView *)subview
{
    [super willRemoveSubview:subview];
    [self setNeedsDisplay:YES];
}

- (void)didAddSubview:(NSView *)subview
{
    [super didAddSubview:subview];
    [self setNeedsDisplay:YES];
}

#pragma mark -
#pragma mark Constructor / Destructor

- (void)constructWithTitle:(NSString *)ttitle font:(NSFont *)font color:(NSColor *)color andBackgroundColor:(NSColor *)tbackgroundColor
{
    title = ttitle ? [ttitle copy] : [[NSString alloc] initWithString:@"No active document"];
    titleFont = font ? [font retain] : [[NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize]] retain];
    titleColor = color ? [color retain] : [[NSColor colorWithCalibratedRed:0.890 green:0.890 blue:0.890 alpha:1.0] retain];
    backgroundColor = tbackgroundColor ? [tbackgroundColor retain] : [[NSColor colorWithCalibratedRed:0.588 green:0.588 blue:0.588 alpha:1.000] retain];
}

- (id)initWithCoder:(NSCoder *)decoder
{
    if(self = [super initWithCoder:decoder])
    {
        [self constructWithTitle:nil font:nil color:nil andBackgroundColor:nil];
    }

    return self;
}

- (id)initWithFrame:(NSRect)frameRect
{
    if(self = [super initWithFrame:frameRect])
    {
        [self constructWithTitle:nil font:nil color:nil andBackgroundColor:nil];
    }

    return self;
}

- (id)initWithTitle:(NSString *)ttitle
{
    if((self = [super init]))
    {
        [self constructWithTitle:ttitle font:nil color:nil andBackgroundColor:nil];
    }

    return self;
}

- (id)initWithTitle:(NSString *)ttitle andFont:(NSFont *)font
{
    if((self = [super init]))
    {
        [self constructWithTitle:ttitle font:font color:nil andBackgroundColor:nil];
    }

    return self;
}

- (id)initWithTitle:(NSString *)ttitle font:(NSFont *)font color:(NSColor *)color andBackgroundColor:(NSColor *)tbackgroundColor
{
    if((self = [super init]))
    {
        [self constructWithTitle:ttitle font:font color:color andBackgroundColor:tbackgroundColor];
    }

    return self;
}

- (void)dealloc
{
    [title release];
    [titleFont release];
    [titleColor release];
    [backgroundColor release];

    [super dealloc];
}

@end
Was it helpful?

Solution

OK, so that's how I've managed to fix it.

It turns out this "Empty View" implementation, apart from print a rounded box with a label in it, in the very middle of the parent view, failed to re-draw the main background. So, all it takes is to repaint it...

In drawRect: just add :

[[NSColor grayColor] set]; // or any other color you prefer
NSRectFill([self bounds]);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top