tags:

views:

262

answers:

3

I am working on implementing tabs for my application. Everything is working well except I can't figure out how to draw the tabs in a lighter shade of gray when the window resigns main status. I am successfully receiving a NSWindowDidBecomeMainNotification and redrawing the tab bar but I am not sure how to calculate the new gray color for the tabs. I am currently using images for all drawing. I tried drawing a semi-transparent layer above to the entire tab bar to make it lighter but it didn't seem to work. I could probably set an opacity value for each image that I use but that seems less than ideal. I also couldn't find any information in the Apple docs about this. What is the best practice in this case?

A: 

The way I do inactive controls is to render an inactive state version of the same graphic in my graphics program (Photoshop or Illustrator) and draw the inactive version when needed. If you draw a 50% transparent version of the active image, you need to erase with the background color first.

lucius
Regarding using Photoshop: Raster images don't scale very well when the UI scale factor changes. This *currently* doesn't happen, but Apple's been hinting for a few OS versions that that will change someday. I predict that using a vector editor, or drawing in code, or both (Opacity can export an image as Quartz drawing code) will pay off.
Peter Hosey
True, a bitmap or raster image isn't going to be resolution independent, but there still isn't a shipping product which uses that feature. What I do is have original vector drawings which I can save in PDF or in a higher resolution raster format, when that time comes. For one of my shipping apps, the PNGs are in 4x resolution.
lucius
+2  A: 

What you could do is make the tabs draw in code, and then simply not draw a background. Let the window's background, active or inactive, show through.

You might also consider switching to PSMTabBarControl, a reusable tab bar class that's already written and in use in several apps. (And I assume that you've dismissed NSTabView as not the look you're going for.)

Peter Hosey
I don't understand exactly what you mean. Does the inner area of a window even have a color that changes? Your answer did give me an idea though. I'm wondering if it would be possible to subclass a toolbar because it would change color appropriately. I already have a toolbar though. Can a window have multiple toolbars?I was initially using PSMTabBarControl except it wasn't exactly what I neeeded so I was making modifications to his source code not knowing exactly what I was doing. I figured it was turning into a recipe for creating bugs so I abandoned ship.
stealthdragon
What I mean is write drawing code, instead of drawing the tabs in a separate app and loading PDF files (or, worse, raster images) in your app, and in this drawing code, don't draw a background.
Peter Hosey
Yes, a window has a background color, but you probably won't need to access it, and it won't help you at all as long as your tabs are graphic resources. No, a window cannot have multiple toolbars; moreover, a tab bar isn't a toolbar anyway. Separate jobs, separate views.
Peter Hosey
As for PSMTabBarControl, I would recommend writing your changes as patches for the main PSMTabBarControl source code and posting them on the MacCode issue tracker as review requests. That way, others can look at your code and see where you've gone wrong, and if you haven't, the maintainers can integrate your patches so all PSMTabBarControl users can benefit.
Peter Hosey
A: 

You can try drawing the images using a semi-transparent mask. The code I generally use simply draws an image and then uses Quartz's Transparency Layer feature to fill a rect over the image's actual bounds. I do this as a category on NSImage:

@implementation NSImage (ShadedImageAddition)
- (void)drawAtPoint:(NSPoint)point shadeWithColor:(NSColor *)color intensity:(CGFloat)alpha
{
    NSRect imageRect;
    CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];

    imageRect.origin = point;
    imageRect.size = [self size];

    CGContextBeginTransparencyLayerWithRect(context, NSRectToCGRect(imageRect), NULL);

    [self drawInRect:imageRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
    [[color colorWithAlphaComponent:alpha] setFill];
    NSRectFillUsingOperation(imageRect, NSCompositeSourceAtop);

    CGContextEndTransparencyLayer(context);
}
@end

Then when the image is to be drawn in a non-key window, I generally draw a white mask over it at 50%. Of course you'll have to choose a color and alpha value that looks good with your bitmaps.

[myImage drawAtPoint:NSZeroPoint shadeWithColor:[NSColor whiteColor] intensity:0.50];
caleb