This is MiscTabCell.m in view mode; [Download] [Up]
// Suppress compiler warning about rcsid being unused, yet prevent assembler
// code for this function from being produced.
inline extern const char *suppressCompilerWarning(void)
{
static const char *rcsid = "$Id$ cc: "__FILE__" "__DATE__" "__TIME__;
return rcsid;
}
//
// ------------------- MiscTabCell Class Implementation -----------------------
//
// NSMatrix cell designed to draw itself as a horizontal file folder tab across
// the top of a MiscSwitchView with a "file folder" border.
//
// Written by Art Isbell (derived from UITabActionCell by Bill Edney,
// Sean Hill, Mark Onyschuk).
// Copyright 1996 by Art Isbell.
// Version 1.0. All rights reserved.
//
// This notice may not be removed from this source code.
//
// This object is included in the MiscKit by permission from the author
// and its use is governed by the MiscKit license, found in the file
// "License.rtf" in the MiscKit distribution. Please refer to that file
// for a list of all applicable permissions and restrictions.
//
// ----------------------------------------------------------------------------
//
// ----------------------------- Header Files ---------------------------------
#import <AppKit/AppKit.h>
#ifndef NOMISC
#import <misckit/MiscTabCell.h>
#import <misckit/drawTab.h>
#else NOMISC
#import "MiscTabCell.h"
#import "drawTab.h" // pswrap that draws tab ends.
#endif NOMISC
// ---------------- Typedef, Struct, and Union Declarations -------------------
// --------------------- Constant and Enum Definitions ------------------------
// Minimum constant tab end width that results in a nicely-curved tab end.
static const int MiscTabEndWidth = 12;
// Left border gray on color systems (empirically determined)
static const float MiscLeftBorderGray = 21.0 / 25.0;
static NSString *MiscDefaultTabLabel = @"Label";
// ------------------------- Function Declarations ----------------------------
@interface MiscTabCell(Private)
// ---------------------- Private Method Declarations -------------------------
- (void)_finishInitializing;
@end
@implementation MiscTabCell
// ---------------------- Factory Method Definitions --------------------------
// ---------------- Overridden Instance Method Definitions --------------------
- (id)init
{
return [self initTextCell:MiscDefaultTabLabel];
}
- (id)initTextCell:(NSString *)aString
{
self = [super initTextCell:aString];
if (self != nil)
{
// Finish the initialization process.
[self _finishInitializing];
}
return self;
}
// Initializes a new instance after being unarchived.
- (id)awakeAfterUsingCoder:(NSCoder *)aDecoder
{
// Finish the initialization process.
[self _finishInitializing];
return self;
}
- (BOOL)isOpaque
{
return YES;
}
// Draws the receiver inside cellFrame in aControlView. The tab is composed of
// ends drawn by a pswrap and shaped like right triangles with a Bezier curve
// hypotenuse plus a rectangular text cell between the ends. The tab ends of
// interior tabs extend beyond the ends of the cellFrame to create overlapping
// tabs if the intercell distance is small. Because the leftmost and rightmost
// tabs cannot draw their left and right ends, respectively, in adjacent cells,
// they are narrower by half the width of an end than interior tabs.
- (void)drawWithFrame:(NSRect)aCellFrame inView:(NSView *)aControlView
{
BOOL isResizingL = (BOOL)(aControlView == nil ||
![aControlView isKindOfClass:[NSMatrix class]]);
BOOL isSelectedL = (BOOL)(!isResizingL &&
([(NSMatrix *)aControlView selectedCell] ==
self));
// If self is selected, draw all other cells starting with rightmost, then
// draw self.
if (isSelectedL)
{
[self redrawCellsInView:(NSMatrix *)aControlView];
}
// If self _canDraw or self is resizing in IB, draw self.
if (_canDraw || isResizingL)
{
[self eraseWithFrame:aCellFrame inView:aControlView
isSelected:isSelectedL];
[self drawTabEndsWithFrame:aCellFrame inView:aControlView
isSelected:isSelectedL];
[self drawInteriorWithFrame:aCellFrame inView:aControlView
isSelected:(isResizingL || isSelectedL)];
[self drawUpperBezelWithFrame:aCellFrame inView:aControlView
isSelected:isSelectedL];
// If aControlView is resizing or self isn't selected, draw lower
// bezel.
if (!isSelectedL)
{
[self drawLowerBezelWithFrame:aCellFrame inView:aControlView
isResizing:isResizingL];
}
// Prevent redraws.
_canDraw = NO;
[aControlView setNeedsDisplay:YES];
}
}
- (void)drawInteriorWithFrame:(NSRect)aCellFrame inView:(NSView *)aControlView
{
// isSelected will be true if aControlView is being resized in IB or if
// self is selected.
[self drawInteriorWithFrame:aCellFrame inView:aControlView
isSelected:(BOOL)(aControlView == nil ||
![aControlView isKindOfClass:[NSMatrix
class]] ||
[(NSMatrix *)aControlView selectedCell]
== self)];
}
- (void)highlight:(BOOL)aFlag withFrame:(NSRect)aCellFrame
inView:(NSView *)aView
{
// Always passing a NO flag to super redraws the key view indication over
// the cell's top border upon mouse up, so invoke _cmd with super only if
// aFlag is YES which happens upon mouse down. Sending
// highlight:withFrame:inView: with a YES flag from
// trackMouse:inRect:ofView:untilMouseUp: seems necessary to prevent
// highlighting.
if (aFlag)
{
[super highlight:NO withFrame:[self drawingRectForBounds:aCellFrame
inView:aView]
inView:aView];
}
}
- (NSSize)cellSizeForBounds:(NSRect)aRect
{
NSSize superSizeL = [super cellSizeForBounds:aRect];
// Add 1.5 tabEndWidths to width that super returns so that first and last
// cells will be wide enough to display the text.
return NSMakeSize((float)((((3 * MiscTabEndWidth) + 1) / 2) +
(unsigned)superSizeL.width), superSizeL.height);
}
// Limit the drawing rectangle to the text rectangle.
- (NSRect)drawingRectForBounds:(NSRect)aRect
{
return [self drawingRectForBounds:(NSRect)aRect inView:[self controlView]];
}
- (NSRect)titleRectForBounds:(NSRect)aRect
{
return [self drawingRectForBounds:aRect];
}
- (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)aCellFrame
ofView:(NSView *)aControlView untilMouseUp:(BOOL)aFlag
{
[self highlight:YES withFrame:aCellFrame inView:aControlView];
return [super trackMouse:theEvent inRect:aCellFrame
ofView:aControlView untilMouseUp:aFlag];
}
// -------------------- New Instance Method Definitions -----------------------
// Sets the _canDraw ivar that's used to minimize cell drawing.
- (void)setCanDraw:(BOOL)aFlag
{
_canDraw = aFlag;
}
- (NSColor *)cellGrayWithIsSelected:(BOOL)aFlag
{
if (aFlag)
{
return [NSColor lightGrayColor];
}
else
{
// If the window default depth limit is 2-bit grayscale or less, return
// dark gray.
if ([NSWindow defaultDepthLimit] <=
NSBestDepth(NSCalibratedWhiteColorSpace, 2, 2, YES, NULL))
{
return [NSColor darkGrayColor];
}
// The window default depth limit is deeper than 2-bit grayscale, so
// return gray.
else
{
return [NSColor grayColor];
}
}
}
- (NSColor *)textGrayWithIsSelected:(BOOL)aFlag
{
// If self is enabled, use black text.
if ([self isEnabled])
{
return [NSColor blackColor];
}
// Self is disabled, so use grayscale text appropriate to color depth.
else
{
// If this is a 2-bit grayscale system, set appropriate grays.
if ([NSWindow defaultDepthLimit] <=
NSBestDepth(NSCalibratedWhiteColorSpace, 2, 2, YES, NULL))
{
return [NSColor lightGrayColor];
}
// This is not a 2-bit grayscale system, so set appropriate grays.
else
{
return [NSColor darkGrayColor];
}
}
}
- (NSColor *)leftBorderGrayWithIsSelected:(BOOL)aFlag
{
if (aFlag)
{
return [NSColor whiteColor];
}
else
{
return [NSColor colorWithCalibratedWhite:MiscLeftBorderGray alpha:1.0];
}
}
- (NSColor *)rightBorderGrayWithIsSelected:(BOOL)aFlag
{
return [NSColor blackColor];
}
- (NSColor *)upperBezelGrayWithIsSelected:(BOOL)aFlag
{
return [self leftBorderGrayWithIsSelected:aFlag];
}
- (NSColor *)lowerBezelGrayWithIsSelected:(BOOL)aFlag
{
return [NSColor whiteColor];
}
- (void)redrawCellsInView:(NSMatrix *)aMatrix
{
NSEnumerator *cellsL = [[aMatrix cells] reverseObjectEnumerator];
// Draw each cell starting with the rightmost.
while (YES)
{
MiscTabCell *cellL = [cellsL nextObject];
// Loop termination test
if (cellL == nil) break;
// If cell isn't self, set its _canDraw flag and draw it.
if (cellL != self)
{
[cellL setCanDraw:YES];
[aMatrix drawCell:cellL];
}
}
// Set self's _canDraw flag so it will draw last.
_canDraw = YES;
}
// Limit the drawing rectangle to the text rectangle whose size is determined
// by the cell's position in aControlView, if it exists.
- (NSRect)drawingRectForBounds:(NSRect)aRect inView:(NSView *)aControlView
{
NSRect drawingRectL;
float halfTabEndWidthL = (float)((MiscTabEndWidth + 1) / 2);
NSSize textCellSizeL = [self cellSizeForBounds:aRect];
drawingRectL.origin.y = NSMinY(aRect) +
(float)((unsigned)(NSHeight(aRect) - textCellSizeL.height) / 2);
drawingRectL.size.height = textCellSizeL.height;
// If aControlView isn't being resized in IB, return the correct drawing
// rectangle.
if ((aControlView != nil) && [aControlView isKindOfClass:[NSMatrix class]])
{
NSArray *controlCellsL = [(NSMatrix *)aControlView cells];
BOOL isFirstCellL = (BOOL)([controlCellsL objectAtIndex:0] == self);
// If self is first cell, set drawingRect origin tabEndWidth to the
// right of the cell frame origin.
if (isFirstCellL)
{
drawingRectL.origin.x = NSMinX(aRect) + (float)MiscTabEndWidth;
}
// self isn't first cell, so set drawingRect origin halfTabEndWidth to
// the right of the cell frame origin.
else
{
drawingRectL.origin.x = NSMinX(aRect) + halfTabEndWidthL;
}
// If self is first or last cell, set drawingRect width to 1.5
// tabEndWidth less than that of cell to accommodate tab ends.
if (isFirstCellL || ([controlCellsL lastObject] == self))
{
drawingRectL.size.width = NSWidth(aRect) - (float)MiscTabEndWidth -
halfTabEndWidthL;
}
// self is interior cell, so set drawingRect width to tabEndWidth less
// than that of cell to accommodate tab ends.
else
{
drawingRectL.size.width = NSWidth(aRect) - (float)MiscTabEndWidth;
}
}
// aControlView is being resized in IB, so return the drawing rectangle of
// an interior cell.
else
{
drawingRectL.origin.x = NSMinX(aRect) + halfTabEndWidthL;
drawingRectL.size.width = NSWidth(aRect) - (float)MiscTabEndWidth;
}
return drawingRectL;
}
- (void)eraseWithFrame:(NSRect)aCellFrame inView:(NSView *)aControlView
isSelected:(BOOL)aFlag
{
NSRect textFrameL = [self drawingRectForBounds:aCellFrame
inView:aControlView];
// Erase self.
[[self cellGrayWithIsSelected:aFlag] set];
NSRectFill(NSMakeRect(NSMinX(textFrameL), NSMinY(aCellFrame),
NSWidth(textFrameL), NSHeight(aCellFrame)));
}
- (void)drawTabEndsWithFrame:(NSRect)aCellFrame inView:(NSView *)aControlView
isSelected:(BOOL)aFlag
{
float cellGrayL = [[self cellGrayWithIsSelected:aFlag] whiteComponent];
NSRect textFrameL = [self drawingRectForBounds:aCellFrame
inView:aControlView];
// Draw tab ends.
drawLeftTabEndX_y_w_h_borderGray_cellGray((int)NSMinX(textFrameL),
(int)NSMaxY(aCellFrame),
MiscTabEndWidth,
(int)NSHeight(aCellFrame),
[[self
leftBorderGrayWithIsSelected:
aFlag] whiteComponent],
cellGrayL);
drawRightTabEndX_y_w_h_borderGray_cellGray((int)NSMinX(textFrameL) +
(int)NSWidth(textFrameL),
(int)NSMaxY(aCellFrame),
MiscTabEndWidth,
(int)NSHeight(aCellFrame),
[[self
rightBorderGrayWithIsSelected:
aFlag] whiteComponent],
cellGrayL);
}
- (void)drawInteriorWithFrame:(NSRect)aCellFrame inView:(NSView *)aControlView
isSelected:(BOOL)aFlag
{
NSRect textFrameL = [self drawingRectForBounds:aCellFrame
inView:aControlView];
// If aControlView is being resized in IB or self is selected, let super
// draw cell interior.
if (aFlag)
{
[super drawInteriorWithFrame:textFrameL inView:aControlView];
}
// aControlView is being resized in IB or self isn't selected, so draw cell
// interior because NSCell doesn't support setting text or cell background
// colors.
else
{
float ascenderL;
float descenderL;
float lineHeightL;
NSFont *cellFontL;
NSFont *screenFontL;
NSString *stringValueL;
// Draw the text by first filling the cell with cellGray.
[[self cellGrayWithIsSelected:NO] set];
NSRectFill(textFrameL);
[[self textGrayWithIsSelected:NO] set];
// Set the font.
cellFontL = [self font];
screenFontL = [cellFontL screenFont];
if ([[NSDPSContext currentContext] isDrawingToScreen] &&
(screenFontL != nil))
{
[screenFontL set];
}
else
{
[cellFontL set];
}
stringValueL = [self stringValue];
// Display text centered horizontally in the text cell and vertically,
// with the bottom of the font descender at the text cell edge.
NSTextFontInfo(cellFontL, &ascenderL, &descenderL, &lineHeightL);
PSmoveto(NSMinX(textFrameL) + (float)(((unsigned)NSWidth(textFrameL) -
(unsigned)[cellFontL
widthOfString:stringValueL] -
1) / 2),
NSMaxY(textFrameL) - descenderL);
PSshow([stringValueL cString]);
}
}
- (void)drawUpperBezelWithFrame:(NSRect)aCellFrame
inView:(NSView *)aControlView
isSelected:(BOOL)aFlag
{
NSRect textFrameL = [self drawingRectForBounds:aCellFrame
inView:aControlView];
// Draw the upper bezel by using the drawing color that reflects the
// selected state.
[[self upperBezelGrayWithIsSelected:aFlag] set];
NSRectFill(NSMakeRect(NSMinX(textFrameL), NSMinY(aCellFrame),
NSWidth(textFrameL), 1.0));
}
- (void)drawLowerBezelWithFrame:(NSRect)aCellFrame
inView:(NSView *)aControlView
isResizing:(BOOL)aFlag
{
NSRect lowerBezelFrameL;
// Set up the lowerBezelFrame that will be used for drawing the bottom
// bezel.
lowerBezelFrameL.origin.y = NSMaxY(aCellFrame) - 1.0;
lowerBezelFrameL.size.height = 1.0;
if (!aFlag)
{
float halfTabEndWidthL = (float)((MiscTabEndWidth + 1) / 2);
NSSize intercellL = [(NSMatrix *)aControlView intercellSpacing];
NSArray *controlCellsL = [(NSMatrix *)aControlView cells];
// If self is the first cell, start the lower bezel at self's right
// edge and set lowerBezelFrame's width to that of the self plus
// halfTabEndWidth.
if ([controlCellsL objectAtIndex:0] == self)
{
lowerBezelFrameL.origin.x = NSMinX(aCellFrame);
lowerBezelFrameL.size.width = NSWidth(aCellFrame) +
halfTabEndWidthL;
}
// self is the last cell so start the lower bezel at the right
// edge of the cell to the left plus halfTabEndWidth and set
// lowerBezelFrame's width to that of self plus the intercell less
// halfTabEndWidth.
else if ([controlCellsL lastObject] == self)
{
lowerBezelFrameL.origin.x = NSMinX(aCellFrame) -
(intercellL.width - halfTabEndWidthL);
lowerBezelFrameL.size.width = NSWidth(aCellFrame) +
(intercellL.width - halfTabEndWidthL);
}
// self is an interior cell so start the lower bezel at the
// right edge of the cell to the left plus halfTabEndWidth and set
// lowerBezelFrame's width to that of self plus the intercell.
else
{
lowerBezelFrameL.origin.x = NSMinX(aCellFrame) -
(intercellL.width - halfTabEndWidthL);
lowerBezelFrameL.size.width = NSWidth(aCellFrame) +
intercellL.width;
}
}
else
{
lowerBezelFrameL.origin.x = NSMinX(aCellFrame);
lowerBezelFrameL.size.width = NSWidth(aCellFrame);
}
// Fill in lowerBezelFrame.
[[self lowerBezelGrayWithIsSelected:NO] set];
NSRectFill(lowerBezelFrameL);
}
// ----------------- Delegate Instance Method Definitions ---------------------
@end
@implementation MiscTabCell(Private)
// ---------------------- Private Method Definitions --------------------------
- (void)_finishInitializing
{
_canDraw = NO;
[self setShowsFirstResponder:YES];
[self setAlignment:NSCenterTextAlignment];
}
@end
// ------------------------- Function Definitions -----------------------------
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.