This is MiscValueCell.m in view mode; [Download] [Up]
// // MiscValueCell.m -- a TextFieldCell subclass that adds arrow buttons // Written by David Fedchenko. Copyright 1994 by David Fedchenko. // Version 2.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. // #import "MiscValueCell.h" #import "MiscValueField.h" @implementation MiscValueCell - initTextCell:(const char *)sz { [super initTextCell:sz]; actualValue = 0; limitMinValue = 0; limitMaxValue = 100; limitMinBound = 0; limitMaxBound = 100; fExpandLow = NO; fExpandHigh = NO; sizeStep = 1; sizeAltStep = 10; fLoop = fValidRect = NO; // Set up the NXImages so they can draw without the files. // This only works it's magic for cells set up in IB since // a regular initialization will look for the images. if (![NXImage findImageNamed:"MVCUpImage"]) { char buf[MAXPATHLEN + 1]; NXImage * idImage; [[NXBundle bundleForClass:[self class]] getPath:buf forResource:"MVCUp" ofType:"tiff"]; idImage = [[[NXImage alloc] init] setDataRetained:YES]; [idImage loadFromFile:buf]; [idImage setName:"MVCUpImage"]; [[NXBundle bundleForClass:[self class]] getPath:buf forResource:"MVCDown" ofType:"tiff"]; idImage = [[[NXImage alloc] init] setDataRetained:YES]; [idImage loadFromFile:buf]; [idImage setName:"MVCDownImage"]; } idUp = [[[[ButtonCell allocFromZone:[self zone]] initIconCell:"MVCUpImage"] setTarget:self] setAction:@selector(increment:)]; [[idUp setContinuous:YES] sendActionOn:NX_MOUSEDOWNMASK | NX_PERIODICMASK]; idDown = [[[[ButtonCell allocFromZone:[self zone]] initIconCell:"MVCDownImage"] setTarget:self] setAction:@selector(decrement:)]; [[idDown setContinuous:YES] sendActionOn:NX_MOUSEDOWNMASK | NX_PERIODICMASK]; [[[self setBezeled:YES] setEditable:YES] setContinuous:NO]; return self; } - copyFromZone:(NXZone *)zone { MiscValueCell * idNew = [super copyFromZone:zone]; if (idNew) { if ((idNew->idUp = [idUp copyFromZone:zone])) { [idNew->idUp setTarget:idNew]; } if ((idNew->idDown = [idDown copyFromZone:zone])) { [idNew->idDown setTarget:idNew]; } } return idNew; } - drawInside:(const NXRect *)aRect inView:controlView { if (!fValidRect) { rectFrame = *aRect; rectFrame.size.width -= 17; } [super drawInside:&rectFrame inView:controlView]; return self; } - drawSelf:(const NXRect *)cellFrame inView:controlView { rectFrame = *cellFrame; rectFrame.size.width -= 17; fValidRect = YES; [super drawSelf:&rectFrame inView:controlView]; fValidRect = NO; rectFrame.origin.x += rectFrame.size.width + 1; rectFrame.size.width = 16; rectFrame.size.height /= 2; [idUp drawSelf:&rectFrame inView:controlView]; rectFrame.origin.y += rectFrame.size.height; [idDown drawSelf:&rectFrame inView:controlView]; return self; } - resetCursorRect:(const NXRect *)cellFrame inView:aView { NXRect rect = *cellFrame; rect.size.width -= 17; [super resetCursorRect:&rect inView:aView]; return self; } - calcCellSize:(NXSize *)theSize inRect:(const NXRect *)aRect { NXRect rect = *aRect; rect.size.width -= 17; [super calcCellSize:theSize inRect:&rect]; theSize->height = MAX(21, theSize->height); theSize->width += 17; return self; } - edit:(const NXRect *)aRect inView:controlView editor:textObj delegate:anObject event:(NXEvent *)theEvent { NXRect rect = *aRect; NXPoint p = theEvent->location; id idWhich; BOOL fR; BOOL fSpin; int oldMask; float delay; float interv; rect.size.width -= 17; [controlView convertPoint:&p fromView:nil]; if (NXPointInRect(&p, &rect)) { [super edit:&rect inView:controlView editor:textObj delegate:anObject event:theEvent]; } else { rect = *aRect; rect.origin.x += rect.size.width - 16; rect.size.width = 16; rect.size.height /= 2; fAltKeyDown = theEvent->flags & NX_ALTERNATEMASK; if (p.y < aRect->origin.y + (aRect->size.height / 2)) { idWhich = idUp; } else { rect.origin.y += rect.size.height; idWhich = idDown; } oldMask = [[controlView window] addToEventMask:NX_MOUSEDRAGGEDMASK]; [controlView lockFocus]; [idWhich getPeriodicDelay:&delay andInterval:&interv]; fSpin = YES; do { [idWhich highlight:&rect inView:controlView lit:YES]; fR = [idWhich trackMouse:theEvent inRect:&rect ofView:controlView]; [idWhich highlight:&rect inView:controlView lit:NO]; [controlView display:&rect :1]; [idWhich setPeriodicDelay:0.0 andInterval:interv]; if (fR) { fSpin = NO; } else { theEvent = [NXApp getNextEvent:NX_MOUSEUPMASK | NX_MOUSEDRAGGEDMASK]; if (theEvent->type == NX_MOUSEUP) { fSpin = NO; } } } while (fSpin); [idWhich setPeriodicDelay:delay andInterval:interv]; [controlView unlockFocus]; [[controlView window] setEventMask:oldMask]; [NXApp sendAction:action to:target from:controlView]; } return self; } - getDrawRect:(NXRect *)theRect { theRect->size.width -= 17; [super getDrawRect:theRect]; return self; } - getTitleRect:(NXRect *)theRect { theRect->size.width -= 17; [super getTitleRect:theRect]; return self; } - highlight:(const NXRect *)cellFrame inView:aView lit:(BOOL)flag { NXRect rect = *cellFrame; rect.size.width -= 17; [super highlight:&rect inView:aView lit:flag]; return self; } - select:(const NXRect *)aRect inView:aView editor:aTextObject delegate:anObject start:(int)selStart length:(int)selLength { NXRect rect = *aRect; rect.size.width -= 17; [super select:&rect inView:aView editor:aTextObject delegate:anObject start:selStart length:selLength]; return self; } - setBezeled:(BOOL)flag { [super setBezeled:flag]; [idUp setBordered:flag]; [idDown setBordered:flag]; return self; } - setBordered:(BOOL)flag { [super setBordered:flag]; [idUp setBordered:NO]; [idDown setBordered:NO]; return self; } - setEditable:(BOOL)flag { [super setEditable:flag]; if (!flag) { [self setSelectable:YES]; } return self; } - setIntValue:(int)anInt { [self setDoubleValue:(double)anInt]; return self; } - setFloatValue:(float)aFloat { [self setDoubleValue:(double)aFloat]; return self; } - setDoubleValue:(double)aDouble { const char * sz; id sl = stringList; fLoop = YES; // so setStringValue doesn't get loopy if (!sl) { if ([[self controlView] class] == [MiscValueField class]) { sl = [[self controlView] stringList]; } } if (sl) { int indx = (int)aDouble; int cnt = (int)limitMaxValue; cnt = [sl count] - 1; indx = MAX(indx, 0); indx = MIN(indx, cnt); actualValue = indx; sz = (char *)[sl stringAt:indx]; if (sz) { [super setStringValue:sz]; } else { [super setDoubleValue:actualValue]; } } else { actualValue = MIN(aDouble, limitMaxValue); actualValue = MAX(actualValue, limitMinValue); if (fExpandLow && (actualValue < limitMinBound)) { limitMinBound = actualValue; } if (fExpandHigh && (actualValue > limitMaxBound)) { limitMaxBound = actualValue; } [super setDoubleValue:actualValue]; } fLoop = NO; return self; } - setStringValue:(const char *)aString { double value; [super setStringValue:aString]; if (!fLoop) { sscanf(aString, "%lf", &value); [self setDoubleValue:value]; } return self; } -(int) intValue { [[self controlView] validateEditing]; return (int)actualValue; } -(float) floatValue { [[self controlView] validateEditing]; return (float)actualValue; } -(double) doubleValue { [[self controlView] validateEditing]; return actualValue; } - increment:sender { double val; id sl = stringList; if (!sl) { if ([[self controlView] class] == [MiscValueField class]) { sl = [[self controlView] stringList]; } } if (sl) { [self setIntValue:[self intValue] + ((fAltKeyDown) ? sizeAltStep : 1)]; } else { val = [self doubleValue] + ((fAltKeyDown) ? sizeAltStep : sizeStep); if (fExpandHigh && (val > limitMaxBound)) { val = limitMaxBound; } [self setDoubleValue:val]; } if ([self isContinuous]) { [NXApp sendAction:action to:target from:[self controlView]]; } return self; } - decrement:sender { double val; id sl = stringList; if (!sl) { if ([[self controlView] class] == [MiscValueField class]) { sl = [[self controlView] stringList]; } } if (sl) { [self setIntValue:[self intValue] - ((fAltKeyDown) ? sizeAltStep : 1)]; } else { val = [self doubleValue] - ((fAltKeyDown) ? sizeAltStep : sizeStep); if (fExpandLow && (val < limitMinBound)) { val = limitMinBound; } [self setDoubleValue:val]; } if ([self isContinuous]) { [NXApp sendAction:action to:target from:[self controlView]]; } return self; } - setMinValue:(double)value { limitMinValue = value; return self; } - setMaxValue:(double)value { limitMaxValue = value; return self; } - setMinBoundary:(double)value { limitMinBound = value; return self; } - setMaxBoundary:(double)value { limitMaxBound = value; return self; } -(double) minValue { return limitMinValue; } -(double) maxValue { return limitMaxValue; } -(double) minBoundary { return limitMinBound; } -(double) maxBoundary { return limitMaxBound; } - setStepSize:(double)size { sizeStep = size; return self; } - setAltStepSize:(double)size { sizeAltStep = size; return self; } -(double) stepSize { return sizeStep; } -(double) altStepSize { return sizeAltStep; } - setExpandMin:(BOOL)flag { fExpandLow = flag; [self setDoubleValue:actualValue]; return self; } - setExpandMax:(BOOL)flag { fExpandHigh = flag; [self setDoubleValue:actualValue]; return self; } -(BOOL) expandMin { return fExpandLow; } -(BOOL) expandMax { return fExpandHigh; } - setStringList:anObject { if (anObject && [anObject respondsTo:@selector(stringAt:)] && [anObject respondsTo:@selector(count)]) { stringList = anObject; [self setEditable:NO]; [self setIntValue:(int)actualValue]; } return self; } - stringList { return stringList; } - write:(NXTypedStream *)stream { [super write:stream]; NXWriteTypes(stream, "ddd", &actualValue, &sizeStep, &sizeAltStep); NXWriteTypes(stream, "dd", &limitMinValue, &limitMaxValue); NXWriteTypes(stream, "dd", &limitMinBound, &limitMaxBound); NXWriteType(stream, @encode(BOOL), &fExpandLow); NXWriteType(stream, @encode(BOOL), &fExpandHigh); NXWriteObject(stream, idUp); NXWriteObject(stream, idDown); return self; } - read:(NXTypedStream *)stream { [super read:stream]; NXReadTypes(stream, "ddd", &actualValue, &sizeStep, &sizeAltStep); NXReadTypes(stream, "dd", &limitMinValue, &limitMaxValue); NXReadTypes(stream, "dd", &limitMinBound, &limitMaxBound); NXReadType(stream, @encode(BOOL), &fExpandLow); NXReadType(stream, @encode(BOOL), &fExpandHigh); idUp = NXReadObject(stream); idDown = NXReadObject(stream); return self; } - awake { [self setDoubleValue:actualValue]; return self; } - awakeFromNib { [self awake]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.