38 double _altIncrementValue;
51 forKeys:[@"knob-color", @"knob-size", @"track-width", @"track-color"]];
54 - (id)initWithFrame:(CGRect)aFrame
67 [
self _recalculateIsVertical];
73 - (void)setMinValue:(
float)aMinimumValue
75 if (_minValue === aMinimumValue)
78 _minValue = aMinimumValue;
82 if (doubleValue < _minValue)
95 - (void)setMaxValue:(
float)aMaximumValue
97 if (_maxValue === aMaximumValue)
100 _maxValue = aMaximumValue;
104 if (doubleValue > _maxValue)
117 - (void)setObjectValue:(
id)aValue
125 - (void)setSliderType:(CPSliderType)aSliderType
133 - (CPSliderType)sliderType
138 - (CGRect)trackRectForBounds:(CGRect)bounds
142 var originalBounds = CGRectCreateCopy(bounds);
144 bounds.size.width = MIN(bounds.size.width, bounds.size.height);
145 bounds.size.height = bounds.size.width;
147 if (bounds.size.width < originalBounds.size.width)
148 bounds.origin.x += (originalBounds.size.width - bounds.size.width) / 2.0;
150 bounds.origin.y += (originalBounds.size.height - bounds.size.height) / 2.0;
157 return _CGRectMakeZero();
159 if ([
self isVertical])
161 bounds.origin.x = (_CGRectGetWidth(bounds) - trackWidth) / 2.0;
162 bounds.size.width = trackWidth;
166 bounds.origin.y = (_CGRectGetHeight(bounds) - trackWidth) / 2.0;
167 bounds.size.height = trackWidth;
174 - (CGRect)knobRectForBounds:(CGRect)bounds
178 if (knobSize.width <= 0 || knobSize.height <= 0)
179 return _CGRectMakeZero();
181 var knobRect = _CGRectMake(0.0, 0.0, knobSize.width, knobSize.height),
185 if (!trackRect || _CGRectIsEmpty(trackRect))
190 var angle = 3 * PI_2 - (1.0 - [
self doubleValue] - _minValue) / (_maxValue - _minValue) * PI2,
191 radius = CGRectGetWidth(trackRect) / 2.0 - 8.0;
193 knobRect.origin.x = radius * COS(angle) + CGRectGetMidX(trackRect) - 3.0;
194 knobRect.origin.y = radius * SIN(angle) + CGRectGetMidY(trackRect) - 2.0;
196 else if ([
self isVertical])
198 knobRect.origin.x = _CGRectGetMidX(trackRect) - knobSize.width / 2.0;
199 knobRect.origin.y = ((_maxValue - [
self doubleValue]) / (_maxValue - _minValue)) * (_CGRectGetHeight(trackRect) - knobSize.height);
203 knobRect.origin.x = (([
self doubleValue] - _minValue) / (_maxValue - _minValue)) * (_CGRectGetWidth(trackRect) - knobSize.width);
204 knobRect.origin.y = _CGRectGetMidY(trackRect) - knobSize.height / 2.0;
210 - (CGRect)rectForEphemeralSubviewNamed:(
CPString)aName
212 if (aName ===
"track-view")
215 else if (aName ===
"knob-view")
223 if (aName ===
"track-view" || aName ===
"knob-view")
227 [view setHitTests:NO];
235 - (void)setAltIncrementValue:(
float)anAltIncrementValue
237 _altIncrementValue = anAltIncrementValue;
240 - (float)altIncrementValue
242 return _altIncrementValue;
245 - (void)setFrameSize:(CGSize)aSize
248 [
self _recalculateIsVertical];
251 - (void)_recalculateIsVertical
254 var bounds = [
self bounds],
255 width = _CGRectGetWidth(bounds),
256 height = _CGRectGetHeight(bounds);
258 _isVertical = width < height ? 1 : (width > height ? 0 : -1);
260 if (_isVertical === 1)
261 [
self setThemeState:CPThemeStateVertical];
262 else if (_isVertical === 0)
263 [
self unsetThemeState:CPThemeStateVertical];
271 - (void)layoutSubviews
288 - (BOOL)tracksMouseOutsideOfFrame
293 - (float)_valueAtPoint:(CGPoint)aPoint
295 var bounds = [
self bounds],
296 knobRect = [
self knobRectForBounds:bounds],
297 trackRect = [
self trackRectForBounds:bounds];
301 var knobWidth = _CGRectGetWidth(knobRect);
303 trackRect.origin.x += knobWidth / 2;
304 trackRect.size.width -= knobWidth;
306 var minValue = [
self minValue],
307 dx = aPoint.x - _CGRectGetMidX(trackRect),
308 dy = aPoint.y - _CGRectGetMidY(trackRect);
310 return MAX(0.0, MIN(1.0, 1.0 - (3 * PI_2 - ATAN2(dy, dx)) % PI2 / PI2)) * ([
self maxValue] - minValue) + minValue;
312 else if ([
self isVertical])
314 var knobHeight = _CGRectGetHeight(knobRect);
316 trackRect.origin.y += knobHeight / 2;
317 trackRect.size.height -= knobHeight;
319 var minValue = [
self minValue];
321 return MAX(0.0, MIN(1.0, (_CGRectGetMaxY(trackRect) - aPoint.y) / _CGRectGetHeight(trackRect))) * ([
self maxValue] - minValue) + minValue;
325 var knobWidth = _CGRectGetWidth(knobRect);
327 trackRect.origin.x += knobWidth / 2;
328 trackRect.size.width -= knobWidth;
330 var minValue = [
self minValue];
332 return MAX(0.0, MIN(1.0, (aPoint.x - _CGRectGetMinX(trackRect)) / _CGRectGetWidth(trackRect))) * ([
self maxValue] - minValue) + minValue;
336 - (BOOL)startTrackingAt:(CGPoint)aPoint
338 var bounds = [
self bounds],
341 if (_CGRectContainsPoint(knobRect, aPoint))
342 _dragOffset = _CGSizeMake(_CGRectGetMidX(knobRect) - aPoint.x, _CGRectGetMidY(knobRect) - aPoint.y);
347 if (trackRect && _CGRectContainsPoint(trackRect, aPoint))
349 _dragOffset = _CGSizeMakeZero();
366 - (BOOL)continueTracking:(CGPoint)lastPoint at:(CGPoint)aPoint
368 [
self setObjectValue:[
self _valueAtPoint:_CGPointMake(aPoint.x + _dragOffset.width, aPoint.y + _dragOffset.height)]];
373 - (void)stopTracking:(CGPoint)lastPoint at:(CGPoint)aPoint mouseIsUp:(BOOL)mouseIsUp
377 if ([_target respondsToSelector:
@selector(sliderDidFinish:)])
378 [_target sliderDidFinish:self];
393 - (void)setContinuous:(BOOL)flag
403 var count = objects.length,
409 if (value !== ([objects[count] valueForKeyPath:aKeyPath]))
423 _minValue = [aCoder decodeDoubleForKey:CPSliderMinValueKey];
424 _maxValue = [aCoder decodeDoubleForKey:CPSliderMaxValueKey];
430 _altIncrementValue = [aCoder decodeDoubleForKey:CPSliderAltIncrValueKey];
432 [
self _recalculateIsVertical];
445 [aCoder encodeDouble:_minValue forKey:CPSliderMinValueKey];
446 [aCoder encodeDouble:_maxValue forKey:CPSliderMaxValueKey];
447 [aCoder encodeDouble:_altIncrementValue forKey:CPSliderAltIncrValueKey];
456 CPLog.warn(
"[CPSlider value] is deprecated, use doubleValue or objectValue instead.");
461 - (void)setValue:(
id)aValue
463 CPLog.warn(
"[CPSlider setValue:] is deprecated, use setDoubleValue: or setObjectValue: instead.");