home *** CD-ROM | disk | FTP | other *** search
- //
- // 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
- {
- return (int)actualValue;
- }
-
- -(float) floatValue
- {
- return (float)actualValue;
- }
-
- -(double) doubleValue
- {
- 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
-