26 #include "../Foundation/Foundation.h"
32 @
typedef CPScrollerPart
44 @
typedef CPUsableScrollerParts
57 var _CACHED_THEME_SCROLLER = nil;
78 CPUsableScrollerParts _usableParts;
82 float _knobProportion;
84 CPScrollerPart _hitPart;
86 CPScrollerPart _trackingPart;
87 float _trackingFloatValue;
88 CGPoint _trackingStartPoint;
100 #pragma mark Class methods
110 @"scroller-width": 7.0,
115 @"decrement-line-size": CGSizeMakeZero(),
116 @"increment-line-size": CGSizeMakeZero(),
117 @"track-inset": CGInsetMakeZero(),
118 @"knob-inset": CGInsetMakeZero(),
119 @"minimum-knob-length": 21.0,
120 @"track-border-overlay": 9.0
124 + (float)scrollerWidth
132 + (float)scrollerWidthInStyle:(
int)aStyle
134 if (!_CACHED_THEME_SCROLLER)
135 _CACHED_THEME_SCROLLER = [[
self alloc] init];
138 return [_CACHED_THEME_SCROLLER valueForThemeAttribute:@"scroller-width" inState:CPThemeStateScrollViewLegacy];
140 return [_CACHED_THEME_SCROLLER currentValueForThemeAttribute:@"scroller-width"];
146 + (float)scrollerOverlay
148 if (!_CACHED_THEME_SCROLLER)
149 _CACHED_THEME_SCROLLER = [[
self alloc] init];
151 return [_CACHED_THEME_SCROLLER currentValueForThemeAttribute:@"track-border-overlay"];
158 + (float)scrollerWidthForControlSize:(CPControlSize)aControlSize
165 #pragma mark Initialization
167 - (id)initWithFrame:(CGRect)aFrame
169 if (
self = [super initWithFrame:aFrame])
177 _allowFadingOut = YES;
181 var paramAnimFadeOut = @{
187 [_animationScroller setViewAnimations:[paramAnimFadeOut]];
188 [_animationScroller setDelegate:self];
193 [
self _setIsVertical:CGRectGetHeight(aFrame) >= CGRectGetWidth(aFrame)];
201 #pragma mark Getters / Setters
215 - (void)setStyle:(
id)aStyle
217 if (_style != nil && _style === aStyle)
229 _allowFadingOut = YES;
236 - (void)setObjectValue:(
id)aValue
244 - (float)knobProportion
246 return _knobProportion;
253 - (void)setKnobProportion:(
float)aProportion
255 if (!_IS_NUMERIC(aProportion))
258 _knobProportion = MIN(1.0, MAX(0.0001, aProportion));
266 #pragma mark Privates
269 - (void)_adjustScrollerSize
271 var
frame = [
self frame],
272 scrollerWidth = [
self currentValueForThemeAttribute:@"scroller-width"];
274 if ([
self isVertical] && CGRectGetWidth(
frame) !== scrollerWidth)
275 frame.size.width = scrollerWidth;
277 if (![
self isVertical] && CGRectGetHeight(
frame) !== scrollerWidth)
278 frame.size.height = scrollerWidth;
280 [
self setFrame:frame];
284 - (void)_performFadeOut:(
CPTimer)aTimer
292 #pragma mark Utilities
294 - (CGRect)rectForPart:(CPScrollerPart)aPart
297 return CGRectMakeZero();
299 return _partRects[aPart];
307 - (CPScrollerPart)testPart:(CGPoint)aPoint
317 if (CGRectContainsPoint([
self rectForPart:
CPScrollerKnob], aPoint))
341 - (void)checkSpaceForParts
346 if (_knobProportion === 1.0)
350 _partRects[CPScrollerDecrementPage] = CGRectMakeZero();
351 _partRects[CPScrollerKnob] = CGRectMakeZero();
352 _partRects[CPScrollerIncrementPage] = CGRectMakeZero();
353 _partRects[CPScrollerDecrementLine] = CGRectMakeZero();
354 _partRects[CPScrollerIncrementLine] = CGRectMakeZero();
357 _partRects[CPScrollerKnobSlot] = CGRectMakeCopy(
bounds);
368 height = CGRectGetHeight(
bounds);
370 if ([
self isVertical])
374 effectiveDecrementLineHeight = decrementLineSize.height + trackInset.top,
375 effectiveIncrementLineHeight = incrementLineSize.height + trackInset.bottom,
376 slotSize = height - effectiveDecrementLineHeight - effectiveIncrementLineHeight,
378 knobWidth =
width - knobInset.left - knobInset.right,
379 knobHeight = MAX(minimumKnobLength, (slotSize * _knobProportion)),
380 knobLocation = effectiveDecrementLineHeight + (slotSize - knobHeight) * [
self floatValue];
382 _partRects[CPScrollerDecrementPage] = CGRectMake(0.0, effectiveDecrementLineHeight,
width, knobLocation - effectiveDecrementLineHeight);
383 _partRects[CPScrollerKnob] = CGRectMake(knobInset.left, knobLocation, knobWidth, knobHeight);
384 _partRects[CPScrollerIncrementPage] = CGRectMake(0.0, knobLocation + knobHeight,
width, height - (knobLocation + knobHeight) - effectiveIncrementLineHeight);
385 _partRects[CPScrollerKnobSlot] = CGRectMake(trackInset.left, effectiveDecrementLineHeight,
width - trackInset.left - trackInset.right, slotSize);
386 _partRects[CPScrollerDecrementLine] = CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
387 _partRects[CPScrollerIncrementLine] = CGRectMake(0.0, height - incrementLineSize.height, incrementLineSize.width, incrementLineSize.height);
389 if (height < knobHeight + decrementLineSize.height + incrementLineSize.height + trackInset.top + trackInset.bottom)
390 _partRects[CPScrollerKnob] = CGRectMakeZero();
392 if (height < decrementLineSize.height + incrementLineSize.height - 2)
394 _partRects[CPScrollerIncrementLine] = CGRectMakeZero();
395 _partRects[CPScrollerDecrementLine] = CGRectMakeZero();
396 _partRects[CPScrollerKnobSlot] = CGRectMake(trackInset.left, 0,
width - trackInset.left - trackInset.right, height);
403 effectiveDecrementLineWidth = decrementLineSize.width + trackInset.left,
404 effectiveIncrementLineWidth = incrementLineSize.width + trackInset.right,
405 slotSize =
width - effectiveDecrementLineWidth - effectiveIncrementLineWidth,
407 knobWidth = MAX(minimumKnobLength, (slotSize * _knobProportion)),
408 knobHeight = height - knobInset.top - knobInset.bottom,
409 knobLocation = effectiveDecrementLineWidth + (slotSize - knobWidth) * [
self floatValue];
411 _partRects[CPScrollerDecrementPage] = CGRectMake(effectiveDecrementLineWidth, 0.0, knobLocation - effectiveDecrementLineWidth, height);
412 _partRects[CPScrollerKnob] = CGRectMake(knobLocation, knobInset.top, knobWidth, knobHeight);
413 _partRects[CPScrollerIncrementPage] = CGRectMake(knobLocation + knobWidth, 0.0,
width - (knobLocation + knobWidth) - effectiveIncrementLineWidth, height);
414 _partRects[CPScrollerKnobSlot] = CGRectMake(effectiveDecrementLineWidth, trackInset.top, slotSize, height - trackInset.top - trackInset.bottom);
415 _partRects[CPScrollerDecrementLine] = CGRectMake(0.0, 0.0, decrementLineSize.width, decrementLineSize.height);
416 _partRects[CPScrollerIncrementLine] = CGRectMake(
width - incrementLineSize.width, 0.0, incrementLineSize.width, incrementLineSize.height);
418 if (
width < knobWidth + decrementLineSize.width + incrementLineSize.width + trackInset.left + trackInset.right)
419 _partRects[CPScrollerKnob] = CGRectMakeZero();
421 if (
width < decrementLineSize.width + incrementLineSize.width - 2)
423 _partRects[CPScrollerIncrementLine] = CGRectMakeZero();
424 _partRects[CPScrollerDecrementLine] = CGRectMakeZero();
425 _partRects[CPScrollerKnobSlot] = CGRectMake(0.0, 0.0,
width, slotSize);
434 - (CPUsableScrollerParts)usableParts
444 if (_isMouseOver && _knobProportion != 1.0)
448 [_timerFadeOut invalidate];
461 [_animationScroller startAnimation];
473 - (void)drawArrow:(CPScrollerArrow)anArrow highlight:(BOOL)shouldHighlight
491 - (
CPView)createViewForPart:(CPScrollerPart)aPart
493 var view = [[
CPView alloc] initWithFrame:CGRectMakeZero()];
495 [view setHitTests:NO];
500 - (CGRect)rectForEphemeralSubviewNamed:(
CPString)aName
502 return _partRects[aName];
507 var view = [[
CPView alloc] initWithFrame:CGRectMakeZero()];
509 [view setHitTests:NO];
514 - (void)layoutSubviews
516 [
self _adjustScrollerSize];
523 for (; index < count; ++index)
552 - (CPScrollerPart)hitPart
563 var type = [anEvent
type];
581 knobSlotRect = [
self rectForPart:CPScrollerKnobSlot],
582 remainder = ![
self isVertical] ? (CGRectGetWidth(knobSlotRect) - CGRectGetWidth(knobRect)) : (CGRectGetHeight(knobSlotRect) - CGRectGetHeight(knobRect));
589 delta = ![
self isVertical] ? location.x - _trackingStartPoint.x : location.y - _trackingStartPoint.y;
591 [
self setFloatValue:_trackingFloatValue + delta / remainder];
595 [CPApp setTarget:self selector:@selector(trackKnob:) forNextEventMatchingMask:CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
607 var type = [anEvent
type];
621 _trackingPart = [
self hitPart];
636 knobWidth = ![
self isVertical] ? CGRectGetWidth(knobRect) : CGRectGetHeight(knobRect),
637 knobSlotRect = [
self rectForPart:CPScrollerKnobSlot],
638 remainder = (![
self isVertical] ? CGRectGetWidth(knobSlotRect) : CGRectGetHeight(knobSlotRect)) - knobWidth;
640 [
self setFloatValue:((![
self isVertical] ? _trackingStartPoint.x - CGRectGetMinX(knobSlotRect) : _trackingStartPoint.y - CGRectGetMinY(knobSlotRect)) - knobWidth / 2.0) / remainder];
667 _trackingPart = hitPart;
674 else if (type ==
CPPeriodic && CGRectContainsPoint([
self rectForPart:_trackingPart], _trackingStartPoint))
675 [
self sendAction:[
self action] to:[
self target]];
677 [CPApp setTarget:self selector:@selector(trackScrollButtons:) forNextEventMatchingMask:CPPeriodicMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
681 - (void)_setIsVertical:(BOOL)isVertical
683 _isVertical = isVertical;
686 [
self setThemeState:CPThemeStateVertical];
688 [
self unsetThemeState:CPThemeStateVertical];
691 - (void)setFrameSize:(CGSize)aSize
701 #pragma mark Overrides
703 - (id)currentValueForThemeAttribute:(
CPString)anAttributeName
705 var themeState = _themeState;
715 if (![
self isEnabled])
738 [_timerFadeOut invalidate];
740 if (![
self isEnabled])
743 _allowFadingOut = NO;
746 if ([
self alphaValue] > 0 && _knobProportion != 1.0)
754 if ([
self isHidden] || ![
self isEnabled] || !_isMouseOver)
757 _allowFadingOut = YES;
761 [_timerFadeOut invalidate];
768 #pragma mark Delegates
785 if (
self = [super initWithCoder:aCoder])
787 _knobProportion = 1.0;
790 _knobProportion = [aCoder decodeFloatForKey:CPScrollerKnobProportionKey];
796 _allowFadingOut = YES;
799 var paramAnimFadeOut = @{
805 [_animationScroller setViewAnimations:[paramAnimFadeOut]];
806 [_animationScroller setDelegate:self];
809 [
self setStyle:[aCoder decodeIntForKey:CPScrollerStyleKey]];
811 [
self _setIsVertical:[aCoder decodeBoolForKey:CPScrollerIsVerticalKey]];
821 [aCoder encodeInt:_isVertical forKey:CPScrollerIsVerticalKey];
822 [aCoder encodeFloat:_knobProportion forKey:CPScrollerKnobProportionKey];
823 [aCoder encodeInt:_style forKey:CPScrollerStyleKey];
835 - (void)setFloatValue:(
float)aValue knobProportion:(
float)aProportion
856 - (BOOL)allowFadingOut
858 return _allowFadingOut;