This is RZBrowserCell.m in view mode; [Download] [Up]
/*
* RZBrowserCell
*
* A subclass of BrowserCell supporting fixed and variable position tabs,
* multi-font text and inline graphics.
*
* Here is an example of setting up a Browser to use a RZBrowserCell:
*
* // create a prototype cell for the browser
* id cellPrototype = [[RZBrowserCell alloc] init];
*
* // initialize the tab stops
* // fixed tab at 10 pixels
* [cellPrototype addFixedTab:10.0];
*
* // proportional tab at 20% with min at 30 and max at 600 pixels
* [cellPrototype addProportionalTab:0.2 min:30 max:600];
*
* // fixed tab 60 pixels from right side
* [cellPrototype addFixedTab:-60.0];
*
* // make sure to set the prototype before we've loaded any columns
* [browser setCellPrototype:cellPrototype];
* [browser loadColumnZero];
* [[browser window] makeKeyAndOrderFront:self];
*
*
* You may freely copy, distribute and reuse the code in this example.
* This code is provided AS IS without warranty of any kind, expressed
* or implied, as to its fitness for any particular use.
*
* Copyright 1995 Ralph Zazula (rzazula@next.com). All Rights Reserved.
*
*/
#import "RZBrowserCell.h"
#import "RZSortedList.h"
#import "RZTextToken.h"
#import "RZTabStop.h"
#import "RZSimpleString.h"
#import "RZRefCountedList.h"
#import <appkit/appkit.h>
#define BORDER 1
@interface RZBrowserCell(Private)
- _addTab:(RZTabStop *)aTab;
- _addText:(RZTextToken *)aText;
- _drawToken:(RZTextToken *)token inside:(const NXRect *)cellFrame inView:controlView;
@end
@implementation RZBrowserCell
- copyFromZone:(NXZone *)zone
{
if(self = [super copyFromZone:zone]) {
if(tabStops) {
[tabStops addReference];
}
if(textTokens) {
[textTokens addReference];
}
}
return self;
}
- free
{
if(tabStops) {
tabStops = [[tabStops freeObjects] free];
}
if(textTokens) {
textTokens = [[textTokens freeObjects] free];
}
return [super free];
}
- setFont:fontObj
{
[super setFont:fontObj];
/*
* save this info so we don't have to look it up every time we draw
* Note: support for a TextCell is a font object
*/
NXTextFontInfo(support, &ascender, &descender, &lineHeight);
return self;
}
- calcCellSize:(NXSize *)theSize inRect:(const NXRect *)aRect
{
NXRect b;
[super calcCellSize:theSize inRect:aRect];
[[self controlView] getBounds:&b];
theSize->width = b.size.width;
return self;
}
- drawInside:(const NXRect *)cellFrame inView:controlView
{
int i, count;
if([[self font] screenFont]) {
[[[self font] screenFont] set];
} else {
[[self font] set];
}
/* erase the cell */
PSsetgray((cFlags1.state || cFlags1.highlighted) ? NX_WHITE : NX_LTGRAY);
NXRectFill(cellFrame);
/* draw the individual tokens */
count = [textTokens count];
for(i=0; i<count; i++) {
[self _drawToken:(RZTextToken *)[textTokens objectAt:i]
inside:cellFrame inView:controlView];
}
#if BORDER
/* all drawing from now on will be in dark gray */
PSsetgray(NX_DKGRAY);
/* draw the two dark gray lines above and below the cell */
if (cFlags1.state || cFlags1.highlighted) {
NXRect rectArray[2];
/*
* draw 1-pixel tall rectangles instead of lines (this is faster than
* PSmoveto(); PSlineto()).
*/
NXSetRect(&(rectArray[0]), NX_X(cellFrame), NX_Y(cellFrame),
NX_WIDTH(cellFrame), 1.0);
NXSetRect(&(rectArray[1]), NX_X(cellFrame), NX_MAXY(cellFrame) - 1.0,
NX_WIDTH(cellFrame), 1.0);
/* using NXRectFillList is faster than separate calls to NXRectFill */
NXRectFillList(rectArray, 2);
}
#endif
return self;
}
- highlight:(const NXRect *)cellFrame inView:controlView lit:(BOOL)flag
{
if (cFlags1.highlighted != flag) {
cFlags1.highlighted = flag;
[self drawInside:cellFrame inView:controlView];
}
return self;
}
/*** manipulating tabs ***/
- addProportionalTab:(float)position
{
return [self addProportionalTab:position min:0.0 max:0.0];
}
- addProportionalTab:(float)position min:(float)minPos max:(float)maxPos
{
id aTab = [[RZTabStop alloc] initProportional:position min:minPos max:maxPos];
[self _addTab:aTab];
return self;
}
- addFixedTab:(float)position
{
id aTab = [[RZTabStop alloc] initFixed:position];
[self _addTab:aTab];
return self;
}
- clearTabs
{
if(tabStops) {
[tabStops freeObjects];
}
return self;
}
/*** manipulating text tokens ***/
- setText:(const char *)format at:(unsigned)index font:(char)font color:(char)color, ...
{
va_list args;
static char buf[1024];
va_start(args, format);
vsprintf(buf, format, args);
[self _addText:[[RZTextToken alloc] initText:buf at:index font:font color:color]];
return self;
}
- setText:(const char *)format at:(unsigned)index, ...
{
va_list args;
static char buf[1024];
va_start(args, format);
vsprintf(buf, format, args);
[self _addText:[[RZTextToken alloc] initText:buf at:index]];
return self;
}
- setText:(const char *)format at:(unsigned)index font:(char)font, ...
{
va_list args;
static char buf[1024];
va_start(args, format);
vsprintf(buf, format, args);
[self _addText:[[RZTextToken alloc] initText:buf at:index font:font color:0]];
return self;
}
- setText:(const char *)format at:(unsigned)index color:(char)color, ...
{
va_list args;
static char buf[1024];
va_start(args, format);
vsprintf(buf, format, args);
[self _addText:[[RZTextToken alloc] initText:buf at:index font:0 color:color]];
return self;
}
- clearText
{
if(textTokens) {
[textTokens freeObjects];
}
return self;
}
/*** manipulating icons ***/
- setImageNamed:(const char *)name at:(unsigned)index
{
[self _addText:[[RZTextToken alloc] initImage:name at:index]];
return self;
}
/*** archiving ***/
- write:(NXTypedStream *)ts
{
[super write:ts];
NXWriteTypes(ts, "fff@@", &ascender, &descender, &lineHeight, &tabStops, &textTokens);
return self;
}
- read:(NXTypedStream *)ts
{
[super read:ts];
NXReadTypes(ts, "fff@@", &ascender, &descender, &lineHeight, &tabStops, &textTokens);
return self;
}
@end
@implementation RZBrowserCell(Private)
- _addTab:(RZTabStop *)aTab
{
if(!tabStops) {
tabStops = [[RZRefCountedList alloc] init];
}
[tabStops addObject:aTab];
return self;
}
- _addText:(RZTextToken *)aText
{
int i;
if(!textTokens) {
textTokens = [[RZSortedList alloc] init];
}
/* remove any tokens at the same index */
for(i=0; i<[textTokens count]; i++) {
if([(RZTextToken *)[textTokens objectAt:i] position] == [aText position]) {
[[textTokens removeObjectAt:i] free];
}
}
[textTokens addObject:aText];
return self;
}
- _drawToken:(RZTextToken *)token inside:(const NXRect *)cellFrame inView:controlView
{
static id textCell = nil;
switch([token isText]) {
case YES : { // text
NXRect rect = *cellFrame;
RZTabStop *thisStop, *nextStop;
float thisStopPos, nextStopPos;
if(!textCell) {
textCell = [[TextFieldCell alloc] init];
[textCell setWrap:NO];
}
[textCell setFont:[self font]];
thisStop = [tabStops objectAt:[token position]];
nextStop = [tabStops objectAt:([token position] + 1)];
if([thisStop fixed]) {
thisStopPos = [thisStop position];
if(thisStopPos < 0.0) {
thisStopPos += NX_WIDTH(cellFrame);
}
} else {
thisStopPos = [thisStop position] * NX_WIDTH(cellFrame);
if(([thisStop max] > 0.0) && (thisStopPos > [thisStop max])) {
thisStopPos = [thisStop max];
}
if(thisStopPos < [thisStop min]) {
thisStopPos = [thisStop min];
}
}
if(nextStop) {
if([nextStop fixed] ) {
nextStopPos = [nextStop position];
if(nextStopPos < 0.0) {
nextStopPos += NX_WIDTH(cellFrame);
}
} else {
nextStopPos = [nextStop position] * NX_WIDTH(cellFrame);
if(([nextStop max] > 0.0) && (nextStopPos > [nextStop max])) {
nextStopPos = [nextStop max];
}
if(nextStopPos < [nextStop min]) {
nextStopPos = [nextStop min];
}
}
} else {
nextStopPos = 0.0;
}
/* move to the correct tab position */
if(nextStopPos > 0.0) {
NX_WIDTH(&rect) = nextStopPos - thisStopPos;
} else {
NX_WIDTH(&rect) -= thisStopPos;
}
NX_X(&rect) = thisStopPos;
// NX_Y(&rect) += descender - 1;
/* set the gray level */
switch([token color]) {
default :
case 0 :
[textCell setTextGray:NX_BLACK];
break;
case 1 :
[textCell setTextGray:NX_DKGRAY];
break;
case 2 :
case 3 :
if(cFlags1.state || cFlags1.highlighted) {
[textCell setTextGray:NX_LTGRAY];
} else {
[textCell setTextGray:NX_WHITE];
}
break;
}
/* set the font */
{
id newFont;
char buf[128];
switch([token font]) {
default :
case 0 :
sprintf(buf, "%s", [[self font] familyName]);
newFont = [[Font newFont:buf size:[[self font] pointSize]] screenFont];
break;
case 1 :
sprintf(buf, "%s-Bold", [[self font] familyName]);
newFont = [[Font newFont:buf size:[[self font] pointSize]] screenFont];
break;
case 2 :
sprintf(buf, "%s-Oblique", [[self font] familyName]);
newFont = [[Font newFont:buf size:[[self font] pointSize]] screenFont];
break;
case 3 :
sprintf(buf, "%s-BoldOblique", [[self font] familyName]);
newFont = [[Font newFont:buf size:[[self font] pointSize]] screenFont];
break;
}
[textCell setFont:newFont];
}
[textCell setStringValue:(char *)[[token data] string]];
[textCell drawInside:&rect inView:controlView];
break;
}
case NO : { // icon
float thisStopPos;
RZTabStop *thisStop = [tabStops objectAt:[token position]];
NXPoint p = cellFrame->origin;
NXSize imageSize;
if([thisStop fixed]) {
thisStopPos = [thisStop position];
if(thisStopPos < 0.0) {
thisStopPos += NX_WIDTH(cellFrame);
}
} else {
thisStopPos = [thisStop position] * NX_WIDTH(cellFrame);
if(([thisStop max] > 0.0) && (thisStopPos > [thisStop max])) {
thisStopPos = [thisStop max];
}
if(thisStopPos < [thisStop min]) {
thisStopPos = [thisStop min];
}
}
[[token data] getSize:&imageSize];
p.x += thisStopPos;
p.y += NX_HEIGHT(cellFrame) - (NX_HEIGHT(cellFrame) - imageSize.height) / 2.0;
[[token data] composite:NX_SOVER toPoint:&p];
break;
}
}
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.