26 #include "../Foundation/Foundation.h" 32 @
typedef CPScrollerPart
44 @
typedef CPUsableScrollerParts
49 var
PARTS_ARRANGEMENT = [CPScrollerKnobSlot, CPScrollerDecrementLine, CPScrollerIncrementLine, CPScrollerKnob],
53 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
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"];
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
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
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))
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);
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);
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];
516 [
self _adjustScrollerSize];
523 for (; index < count; ++index)
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];
674 else if (type ==
CPPeriodic && CGRectContainsPoint([
self rectForPart:_trackingPart], _trackingStartPoint))
677 [CPApp setTarget:self selector:@selector(trackScrollButtons:) forNextEventMatchingMask:CPPeriodicMask | CPLeftMouseDraggedMask | CPLeftMouseUpMask untilDate:nil inMode:nil dequeue:YES];
691 - (void)setFrameSize:(CGSize)aSize
701 #pragma mark Overrides 703 - (id)currentValueForThemeAttribute:(
CPString)anAttributeName
705 var themeState = _themeState;
710 return [
self valueForThemeAttribute:anAttributeName inState:themeState];
738 [_timerFadeOut invalidate];
743 _allowFadingOut = NO;
746 if ([
self alphaValue] > 0 && _knobProportion != 1.0)
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
858 return _allowFadingOut;
Used to implement exception handling (creating & raising).
BOOL setThemeState:(ThemeState aState)
An object representation of nil.
CPViewAnimationFadeOutEffect
void mouseExited:(CPEvent anEvent)
CGPoint locationInWindow()
void raise:reason:(CPString aName, [reason] CPString aReason)
A mutable key-value pair collection.
An immutable string (collection of characters).
CGPoint convertPoint:fromView:(CGPoint aPoint, [fromView] CPView aView)
void stopPeriodicEvents()
if(CPFeatureIsCompatible(CPHTMLCanvasFeature))
id initWithDuration:animationCurve:(float aDuration, [animationCurve] CPAnimationCurve anAnimationCurve)
BOOL sendAction:to:(SEL anAction, [to] id anObject)
void setFloatValue:(float aValue)
void setNeedsDisplay:(BOOL aFlag)
void setObjectValue:(id anObject)
CPTimer scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:(CPTimeInterval seconds, [target] id aTarget, [selector] SEL aSelector, [userInfo] id userInfo, [repeats] BOOL shouldRepeat)
void setAlphaValue:(float anAlphaValue)
void highlight:(BOOL shouldHighlight)
A timer object that can send a message after the given time interval.
Defines methods for use when archiving & restoring (enc/decoding).
void mouseEntered:(CPEvent anEvent)
BOOL unsetThemeState:(ThemeState aState)
void setFrameSize:(CGSize aSize)
void startPeriodicEventsAfterDelay:withPeriod:(CPTimeInterval aDelay, [withPeriod] CPTimeInterval aPeriod)
void encodeWithCoder:(CPCoder aCoder)
CPView layoutEphemeralSubviewNamed:positioned:relativeToEphemeralSubviewNamed:(CPString aViewName, [positioned] CPWindowOrderingMode anOrderingMode, [relativeToEphemeralSubviewNamed] CPString relativeToViewName)