1/* xscreensaver, Copyright (c) 2006-2015 Jamie Zawinski <jwz@jwz.org> 2 * 3 * Permission to use, copy, modify, distribute, and sell this software and its 4 * documentation for any purpose is hereby granted without fee, provided that 5 * the above copyright notice appear in all copies and that both that 6 * copyright notice and this permission notice appear in supporting 7 * documentation. No representations are made about the suitability of this 8 * software for any purpose. It is provided "as is" without express or 9 * implied warranty. 10 * 11 * This is a subclass of NSSlider that is flipped horizontally: 12 * the high value is on the left and the low value is on the right. 13 */ 14 15#import "InvertedSlider.h" 16 17@implementation InvertedSlider 18 19- (id) initWithFrame:(NSRect)r 20{ 21 self = [super initWithFrame:r]; 22 if (! self) return 0; 23 inverted = YES; 24 integers = NO; 25 return self; 26} 27 28- (id) initWithFrame:(NSRect)r inverted:(BOOL)_inv integers:(BOOL)_int 29{ 30 self = [self initWithFrame:r]; 31 inverted = _inv; 32 integers = _int; 33 return self; 34} 35 36 37-(double) transformValue:(double) value 38{ 39 double v2 = (integers 40 ? (int) (value + (value < 0 ? -0.5 : 0.5)) 41 : value); 42 double low = [self minValue]; 43 double high = [self maxValue]; 44 double range = high - low; 45 double off = v2 - low; 46 if (inverted) 47 v2 = low + (range - off); 48 // NSLog (@" ... %.1f -> %.1f [%.1f - %.1f]", value, v2, low, high); 49 return v2; 50} 51 52#ifndef USE_IPHONE 53 54/* On MacOS, we have to transform the value on every entry and exit point 55 to this class. So, we implement doubleValue and setDoubleValue to 56 transform the value; and we then have to re-implement every getter and 57 setter in terms of those. There's no way to simply change how the 58 slider is displayed without mucking with the value inside of it. 59 */ 60 61-(double) doubleValue 62{ 63 return [self transformValue:[super doubleValue]]; 64} 65 66-(void) setDoubleValue:(double)v 67{ 68 return [super setDoubleValue:[self transformValue:v]]; 69} 70 71-(float)floatValue { return (float) [self doubleValue]; } 72-(int)intValue { return (int) [self doubleValue]; } 73-(NSInteger)integerValue { return (NSInteger) [self doubleValue]; } 74-(id)objectValue { return [NSNumber numberWithDouble:[self doubleValue]]; } 75 76-(NSString *)stringValue 77{ 78 if (integers) 79 return [NSString stringWithFormat:@"%d", [self intValue]]; 80 else 81 return [NSString stringWithFormat:@"%f", [self doubleValue]]; 82} 83 84- (NSAttributedString *)attributedStringValue; 85{ 86 return [[[NSAttributedString alloc] initWithString:[self stringValue]] 87 autorelease]; 88} 89 90-(void)setFloatValue:(float)v { [self setDoubleValue: (double) v]; } 91-(void)setIntValue: (int)v { [self setDoubleValue: (double) v]; } 92-(void)setIntegerValue:(NSInteger)v { [self setDoubleValue: (double) v]; } 93-(void)setStringValue:(NSString *)v { [self setDoubleValue: [v doubleValue]]; } 94-(void)takeIntValueFrom:(id)f { [self setIntValue: [f intValue]]; } 95-(void)takeFloatValueFrom:(id)f { [self setFloatValue: [f floatValue]]; } 96-(void)takeDoubleValueFrom:(id)f { [self setDoubleValue: [f doubleValue]]; } 97-(void)takeStringValueFrom:(id)f { [self setStringValue: [f stringValue]]; } 98-(void)takeObjectValueFrom:(id)f { [self setObjectValue: [f objectValue]]; } 99-(void)takeIntegerValueFrom:(id)f { [self setIntegerValue:[f integerValue]];} 100-(void) setAttributedStringValue:(NSAttributedString *)v { 101 [self setStringValue:[v string]]; 102} 103 104-(void) setObjectValue:(id <NSCopying>)v 105{ 106 NSAssert2((v == nil) || 107 [(NSObject *) v respondsToSelector:@selector(doubleValue)], 108 @"argument %@ to %s does not respond to doubleValue", 109 v, __PRETTY_FUNCTION__); 110 [self setDoubleValue:[((NSNumber *) v) doubleValue]]; 111} 112 113#else // USE_IPHONE 114 115/* On iOS, we have control over how the value is displayed, but there's no 116 way to transform the value on input and output: if we wrap 'value' and 117 'setValue' analagously to what we do on MacOS, things fail in weird 118 ways. Presumably some parts of the system are accessing the value 119 instance variable directly instead of going through the methods. 120 121 So the only way around this is to enforce that all of our calls into 122 this object use a new API: 'transformedValue' and 'setTransformedValue'. 123 The code in XScreenSaverConfigSheet uses that instead. 124 */ 125 126- (CGRect)thumbRectForBounds:(CGRect)bounds 127 trackRect:(CGRect)rect 128 value:(float)value 129{ 130 CGRect thumb = [super thumbRectForBounds: bounds 131 trackRect: rect 132 value: [self transformValue:value]]; 133 if (inverted) 134 thumb.origin.x = rect.size.width - thumb.origin.x - thumb.size.width; 135 return thumb; 136} 137 138-(double) transformedValue 139{ 140 return [self transformValue: [self value]]; 141} 142 143-(void) setTransformedValue:(double)v 144{ 145 [self setValue: [self transformValue: v]]; 146} 147 148#endif // USE_IPHONE 149 150 151@end 152