API  0.9.6
 All Classes Files Functions Variables Macros Groups Pages
CPScrollView.j
Go to the documentation of this file.
1 /*
2  * CPScrollView.j
3  * AppKit
4  *
5  * Created by Francisco Tolmasky.
6  * Copyright 2008, 280 North, Inc.
7  *
8  * Modified to match Lion style by Antoine Mercadal 2011
9  * <antoine.mercadal@archipelproject.org>
10  *
11  * This library is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public
13  * License as published by the Free Software Foundation; either
14  * version 2.1 of the License, or (at your option) any later version.
15  *
16  * This library is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with this library; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24  */
25 
26 
27 
28 #define SHOULD_SHOW_CORNER_VIEW() (_scrollerStyle === CPScrollerStyleLegacy && _verticalScroller && ![_verticalScroller isHidden])
29 
30 
32 var _isSystemUsingOverlayScrollers = function()
33 {
34 #if PLATFORM(DOM)
35  var inner = document.createElement('p'),
36  outer = document.createElement('div');
37 
38  inner.style.width = "100%";
39  inner.style.height = "200px";
40 
41  outer.style.position = "absolute";
42  outer.style.top = "0px";
43  outer.style.left = "0px";
44  outer.style.visibility = "hidden";
45  outer.style.width = "200px";
46  outer.style.height = "150px";
47  outer.style.overflow = "hidden";
48  outer.appendChild (inner);
49 
50  document.body.appendChild (outer);
51  var w1 = inner.offsetWidth;
52  outer.style.overflow = 'scroll';
53  var w2 = inner.offsetWidth;
54  if (w1 == w2)
55  w2 = outer.clientWidth;
56 
57  document.body.removeChild (outer);
58 
59  return (w1 - w2 == 0);
60 #else
61  return NO;
62 #endif
63 };
64 
74 var TIMER_INTERVAL = 0.2,
77 
79 
81  CPScrollerStyleGlobalChangeNotification = @"CPScrollerStyleGlobalChangeNotification";
82 
83 
84 @implementation CPScrollView : CPView
85 {
86  CPClipView _contentView;
87  CPClipView _headerClipView;
88  CPView _cornerView;
89  CPView _bottomCornerView;
90 
91  id _delegate;
92  CPTimer _scrollTimer;
93 
94  BOOL _hasVerticalScroller;
95  BOOL _hasHorizontalScroller;
96  BOOL _autohidesScrollers;
97 
98  CPScroller _verticalScroller;
99  CPScroller _horizontalScroller;
100 
101  CPInteger _recursionCount;
102  CPInteger _implementedDelegateMethods;
103 
104  float _verticalLineScroll;
105  float _verticalPageScroll;
106  float _horizontalLineScroll;
107  float _horizontalPageScroll;
108 
109  CPBorderType _borderType;
110 
111  CPTimer _timerScrollersHide;
112 
113  int _scrollerStyle;
114  int _scrollerKnobStyle;
115 }
116 
117 
118 #pragma mark -
119 #pragma mark Class methods
120 
121 + (void)initialize
122 {
123  if (self !== [CPScrollView class])
124  return;
125 
126  var globalValue = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPScrollersGlobalStyle"];
127 
128  if (globalValue == nil || globalValue == -1)
129  CPScrollerStyleGlobal = _isSystemUsingOverlayScrollers() ? CPScrollerStyleOverlay : CPScrollerStyleLegacy
130  else
131  CPScrollerStyleGlobal = globalValue;
132 }
133 
134 + (CPString)defaultThemeClass
135 {
136  return @"scrollview"
137 }
138 
139 + (CPDictionary)themeAttributes
140 {
142  @"bottom-corner-color": [CPColor whiteColor],
143  @"border-color": [CPColor blackColor]
144  }];
145 }
146 
147 + (CGSize)contentSizeForFrameSize:(CGSize)frameSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType
148 {
149  var bounds = [self _insetBounds:_CGRectMake(0.0, 0.0, frameSize.width, frameSize.height) borderType:borderType],
150  scrollerWidth = [CPScroller scrollerWidth];
151 
152  if (hFlag)
153  bounds.size.height -= scrollerWidth;
154 
155  if (vFlag)
156  bounds.size.width -= scrollerWidth;
157 
158  return bounds.size;
159 }
160 
161 + (CGSize)frameSizeForContentSize:(CGSize)contentSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType
162 {
163  var bounds = [self _insetBounds:_CGRectMake(0.0, 0.0, contentSize.width, contentSize.height) borderType:borderType],
164  widthInset = contentSize.width - bounds.size.width,
165  heightInset = contentSize.height - bounds.size.height,
166  frameSize = _CGSizeMake(contentSize.width + widthInset, contentSize.height + heightInset),
167  scrollerWidth = [CPScroller scrollerWidth];
168 
169  if (hFlag)
170  frameSize.height += scrollerWidth;
171 
172  if (vFlag)
173  frameSize.width += scrollerWidth;
174 
175  return frameSize;
176 }
177 
178 + (CGRect)_insetBounds:(CGRect)bounds borderType:(CPBorderType)borderType
179 {
180  switch (borderType)
181  {
182  case CPLineBorder:
183  case CPBezelBorder:
184  return _CGRectInset(bounds, 1.0, 1.0);
185 
186  case CPGrooveBorder:
187  bounds = _CGRectInset(bounds, 2.0, 2.0);
188  ++bounds.origin.y;
189  --bounds.size.height;
190  return bounds;
191 
192  case CPNoBorder:
193  default:
194  return bounds;
195  }
196 }
197 
201 + (int)globalScrollerStyle
202 {
203  return CPScrollerStyleGlobal;
204 }
205 
211 + (void)setGlobalScrollerStyle:(int)aStyle
212 {
213  CPScrollerStyleGlobal = aStyle;
214  [[CPNotificationCenter defaultCenter] postNotificationName:CPScrollerStyleGlobalChangeNotification object:nil];
215 }
216 
217 
218 #pragma mark -
219 #pragma mark Initialization
220 
221 - (id)initWithFrame:(CGRect)aFrame
222 {
223  self = [super initWithFrame:aFrame];
224 
225  if (self)
226  {
227  _verticalLineScroll = 10.0;
228  _verticalPageScroll = 10.0;
229 
230  _horizontalLineScroll = 10.0;
231  _horizontalPageScroll = 10.0;
232 
233  _borderType = CPNoBorder;
234 
235  _contentView = [[CPClipView alloc] initWithFrame:[self _insetBounds]];
236  [self addSubview:_contentView];
237 
238  _headerClipView = [[CPClipView alloc] init];
239  [self addSubview:_headerClipView];
240 
241  _bottomCornerView = [[CPView alloc] init];
242  [self addSubview:_bottomCornerView];
243 
244  [self setHasVerticalScroller:YES];
245  [self setHasHorizontalScroller:YES];
246  _scrollerKnobStyle = CPScrollerKnobStyleDefault;
247  [self setScrollerStyle:CPScrollerStyleGlobal];
248 
249  _delegate = nil;
250  _scrollTimer = nil;
251  _implementedDelegateMethods = 0;
252 
255  name:CPScrollerStyleGlobalChangeNotification
256  object:nil];
257  }
258 
259  return self;
260 }
261 
262 
263 #pragma mark -
264 #pragma mark Getters / Setters
265 
269 - (id)delegate
270 {
271  return _delegate;
272 }
273 
289 - (void)setDelegate:(id)aDelegate
290 {
291  if (aDelegate === _delegate)
292  return;
293 
294  _delegate = aDelegate;
295  _implementedDelegateMethods = 0;
296 
297  if (_delegate === nil)
298  return;
299 
300  if ([_delegate respondsToSelector:@selector(scrollViewWillScroll:)])
301  _implementedDelegateMethods |= CPScrollViewDelegate_scrollViewWillScroll_;
302 
303  if ([_delegate respondsToSelector:@selector(scrollViewDidScroll:)])
304  _implementedDelegateMethods |= CPScrollViewDelegate_scrollViewDidScroll_;
305 }
306 
307 - (int)scrollerStyle
308 {
309  return _scrollerStyle;
310 }
311 
318 - (void)setScrollerStyle:(int)aStyle
319 {
320  if (_scrollerStyle === aStyle)
321  return;
322 
323  _scrollerStyle = aStyle;
324 
325  [self _updateScrollerStyle];
326 }
327 
338 - (int)scrollerKnobStyle
339 {
340  return _scrollerKnobStyle;
341 }
342 
353 - (void)setScrollerKnobStyle:(int)newScrollerKnobStyle
354 {
355  if (_scrollerKnobStyle === newScrollerKnobStyle)
356  return;
357 
358  _scrollerKnobStyle = newScrollerKnobStyle;
359 
360  [self _updateScrollerStyle];
361 }
362 
366 - (CPClipView)contentView
367 {
368  return _contentView;
369 }
370 
376 - (void)setContentView:(CPClipView)aContentView
377 {
378  if (_contentView === aContentView || !aContentView)
379  return;
380 
381  var documentView = [aContentView documentView];
382 
383  if (documentView)
384  [documentView removeFromSuperview];
385 
386  [_contentView removeFromSuperview];
387 
388  _contentView = aContentView;
389 
390  [_contentView setDocumentView:documentView];
391 
392  [self addSubview:_contentView];
393 
394  // This will size the content view appropriately, so no need to size it in this method.
395  [self reflectScrolledClipView:_contentView];
396 }
397 
401 - (CGSize)contentSize
402 {
403  return [_contentView frame].size;
404 }
405 
409 - (id)documentView
410 {
411  return [_contentView documentView];
412 }
413 
419 - (void)setDocumentView:(CPView)aView
420 {
421  [_contentView setDocumentView:aView];
422 
423  // FIXME: This should be observed.
424  [self _updateCornerAndHeaderView];
425  [self reflectScrolledClipView:_contentView];
426 }
427 
431 - (CPBorderType)borderType
432 {
433  return _borderType;
434 }
435 
446 - (void)setBorderType:(CPBorderType)borderType
447 {
448  if (_borderType == borderType)
449  return;
450 
451  _borderType = borderType;
452 
453  [self reflectScrolledClipView:_contentView];
454  [self setNeedsDisplay:YES];
455 }
456 
457 
461 - (CPScroller)horizontalScroller
462 {
463  return _horizontalScroller;
464 }
465 
471 - (void)setHorizontalScroller:(CPScroller)aScroller
472 {
473  if (_horizontalScroller === aScroller)
474  return;
475 
476  [_horizontalScroller removeFromSuperview];
477  [_horizontalScroller setTarget:nil];
478  [_horizontalScroller setAction:nil];
479 
480  _horizontalScroller = aScroller;
481 
482  [_horizontalScroller setTarget:self];
483  [_horizontalScroller setAction:@selector(_horizontalScrollerDidScroll:)];
484 
485  [self addSubview:_horizontalScroller];
486 
487  [self _updateScrollerStyle];
488 }
489 
493 - (BOOL)hasHorizontalScroller
494 {
495  return _hasHorizontalScroller;
496 }
497 
504 - (void)setHasHorizontalScroller:(BOOL)shouldHaveHorizontalScroller
505 {
506  if (_hasHorizontalScroller === shouldHaveHorizontalScroller)
507  return;
508 
509  _hasHorizontalScroller = shouldHaveHorizontalScroller;
510 
511  if (_hasHorizontalScroller && !_horizontalScroller)
512  {
513  var bounds = [self _insetBounds];
514 
515  [self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(_CGRectGetWidth(bounds), [CPScroller scrollerWidthInStyle:_scrollerStyle] + 1), [CPScroller scrollerWidthInStyle:_scrollerStyle])]];
516  [[self horizontalScroller] setFrameSize:CGSizeMake(_CGRectGetWidth(bounds), [CPScroller scrollerWidthInStyle:_scrollerStyle])];
517  }
518 
519  [self reflectScrolledClipView:_contentView];
520 }
521 
525 - (CPScroller)verticalScroller
526 {
527  return _verticalScroller;
528 }
529 
535 - (void)setVerticalScroller:(CPScroller)aScroller
536 {
537  if (_verticalScroller === aScroller)
538  return;
539 
540  [_verticalScroller removeFromSuperview];
541  [_verticalScroller setTarget:nil];
542  [_verticalScroller setAction:nil];
543 
544  _verticalScroller = aScroller;
545 
546  [_verticalScroller setTarget:self];
547  [_verticalScroller setAction:@selector(_verticalScrollerDidScroll:)];
548 
549  [self addSubview:_verticalScroller];
550 
551  [self _updateScrollerStyle];
552 }
553 
557 - (BOOL)hasVerticalScroller
558 {
559  return _hasVerticalScroller;
560 }
561 
569 - (void)setHasVerticalScroller:(BOOL)shouldHaveVerticalScroller
570 {
571  if (_hasVerticalScroller === shouldHaveVerticalScroller)
572  return;
573 
574  _hasVerticalScroller = shouldHaveVerticalScroller;
575 
576  if (_hasVerticalScroller && !_verticalScroller)
577  {
578  var bounds = [self _insetBounds];
579 
580  [self setVerticalScroller:[[CPScroller alloc] initWithFrame:_CGRectMake(0.0, 0.0, [CPScroller scrollerWidthInStyle:_scrollerStyle], MAX(_CGRectGetHeight(bounds), [CPScroller scrollerWidthInStyle:_scrollerStyle] + 1))]];
581  [[self verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidthInStyle:_scrollerStyle], _CGRectGetHeight(bounds))];
582  }
583 
584  [self reflectScrolledClipView:_contentView];
585 }
586 
590 - (BOOL)autohidesScrollers
591 {
592  return _autohidesScrollers;
593 }
594 
601 - (void)setAutohidesScrollers:(BOOL)autohidesScrollers
602 {
603  if (_autohidesScrollers == autohidesScrollers)
604  return;
605 
606  _autohidesScrollers = autohidesScrollers;
607 
608  [self reflectScrolledClipView:_contentView];
609 }
610 
611 - (CPView)bottomCornerView
612 {
613  return _bottomCornerView;
614 }
615 
616 - (void)setBottomCornerView:(CPView)aBottomCornerView
617 {
618  if (_bottomCornerView === aBottomCornerView)
619  return;
620 
621  [_bottomCornerView removeFromSuperview];
622 
623  [aBottomCornerView setFrame:[self _bottomCornerViewFrame]];
624  [self addSubview:aBottomCornerView];
625 
626  _bottomCornerView = aBottomCornerView;
627 
628  [self _updateCornerAndHeaderView];
629 }
630 
634 - (float)lineScroll
635 {
636  return [self horizontalLineScroll];
637 }
638 
644 - (void)setLineScroll:(float)aLineScroll
645 {
646  [self setHorizontalLineScroll:aLineScroll];
647  [self setVerticalLineScroll:aLineScroll];
648 }
649 
653 - (float)horizontalLineScroll
654 {
655  return _horizontalLineScroll;
656 }
657 
663 - (void)setHorizontalLineScroll:(float)aLineScroll
664 {
665  _horizontalLineScroll = aLineScroll;
666 }
667 
671 - (float)verticalLineScroll
672 {
673  return _verticalLineScroll;
674 }
675 
681 - (void)setVerticalLineScroll:(float)aLineScroll
682 {
683  _verticalLineScroll = aLineScroll;
684 }
685 
689 - (float)pageScroll
690 {
691  return [self horizontalPageScroll];
692 }
693 
699 - (void)setPageScroll:(float)aPageScroll
700 {
701  [self setHorizontalPageScroll:aPageScroll];
702  [self setVerticalPageScroll:aPageScroll];
703 }
704 
708 - (float)horizontalPageScroll
709 {
710  return _horizontalPageScroll;
711 }
712 
718 - (void)setHorizontalPageScroll:(float)aPageScroll
719 {
720  _horizontalPageScroll = aPageScroll;
721 }
722 
726 - (float)verticalPageScroll
727 {
728  return _verticalPageScroll;
729 }
730 
736 - (void)setVerticalPageScroll:(float)aPageScroll
737 {
738  _verticalPageScroll = aPageScroll;
739 }
740 
741 
742 #pragma mark -
743 #pragma mark Privates
744 
745 /* @ignore */
746 - (void)_updateScrollerStyle
747 {
748  if (_hasHorizontalScroller)
749  {
750  [_horizontalScroller setStyle:_scrollerStyle];
751  [_horizontalScroller unsetThemeState:CPThemeStateSelected];
752 
753  switch (_scrollerKnobStyle)
754  {
756  [_horizontalScroller unsetThemeState:CPThemeStateScrollerKnobDark];
757  [_horizontalScroller setThemeState:CPThemeStateScrollerKnobLight];
758  break;
759 
761  [_horizontalScroller unsetThemeState:CPThemeStateScrollerKnobLight];
762  [_horizontalScroller setThemeState:CPThemeStateScrollerKnobDark];
763  break;
764 
765  default:
766  [_horizontalScroller unsetThemeState:CPThemeStateScrollerKnobLight];
767  [_horizontalScroller unsetThemeState:CPThemeStateScrollerKnobDark];
768  }
769  }
770 
771  if (_hasVerticalScroller)
772  {
773  [_verticalScroller setStyle:_scrollerStyle];
774  [_verticalScroller unsetThemeState:CPThemeStateSelected];
775 
776  switch (_scrollerKnobStyle)
777  {
779  [_verticalScroller unsetThemeState:CPThemeStateScrollerKnobDark];
780  [_verticalScroller setThemeState:CPThemeStateScrollerKnobLight];
781  break;
782 
784  [_verticalScroller unsetThemeState:CPThemeStateScrollerKnobLight];
785  [_verticalScroller setThemeState:CPThemeStateScrollerKnobDark];
786  break;
787 
788  default:
789  [_verticalScroller unsetThemeState:CPThemeStateScrollerKnobLight];
790  [_verticalScroller unsetThemeState:CPThemeStateScrollerKnobDark];
791  }
792  }
793 
794  if (_scrollerStyle == CPScrollerStyleOverlay)
795  {
796  if (_timerScrollersHide)
797  [_timerScrollersHide invalidate];
798 
799  _timerScrollersHide = [CPTimer scheduledTimerWithTimeInterval:CPScrollViewFadeOutTime target:self selector:@selector(_hideScrollers:) userInfo:nil repeats:NO];
800  [[self bottomCornerView] setHidden:YES];
801  }
802  else
803  [[self bottomCornerView] setHidden:NO];
804 
805  [self reflectScrolledClipView:_contentView];
806 }
807 
808 /* @ignore */
809 - (CGRect)_insetBounds
810 {
811  return [[self class] _insetBounds:[self bounds] borderType:_borderType];
812 }
813 
814 /* @ignore */
815 - (void)_updateCornerAndHeaderView
816 {
817  var documentView = [self documentView],
818  currentHeaderView = [self _headerView],
819  documentHeaderView = [documentView respondsToSelector:@selector(headerView)] ? [documentView headerView] : nil;
820 
821  if (currentHeaderView !== documentHeaderView)
822  {
823  [currentHeaderView removeFromSuperview];
824  [_headerClipView setDocumentView:documentHeaderView];
825  }
826 
827  var documentCornerView = [documentView respondsToSelector:@selector(cornerView)] ? [documentView cornerView] : nil;
828 
829  if (_cornerView !== documentCornerView)
830  {
831  [_cornerView removeFromSuperview];
832 
833  _cornerView = documentCornerView;
834 
835  if (_cornerView)
836  {
837  [_cornerView setHidden:!SHOULD_SHOW_CORNER_VIEW()];
838  [self addSubview:_cornerView];
839  }
840  }
841 
842  [self reflectScrolledClipView:_contentView];
843  [documentHeaderView setNeedsLayout];
844  [documentHeaderView setNeedsDisplay:YES];
845 }
846 
847 /* @ignore */
848 - (CPView)_headerView
849 {
850  return [_headerClipView documentView];
851 }
852 
853 /* @ignore */
854 - (CGRect)_cornerViewFrame
855 {
856  if (!_cornerView)
857  return _CGRectMakeZero();
858 
859  var bounds = [self _insetBounds],
860  frame = [_cornerView frame];
861 
862  frame.origin.x = _CGRectGetMaxX(bounds) - _CGRectGetWidth(frame);
863  frame.origin.y = _CGRectGetMinY(bounds);
864 
865  return frame;
866 }
867 
868 /* @ignore */
869 - (CGRect)_headerClipViewFrame
870 {
871  var headerView = [self _headerView];
872 
873  if (!headerView)
874  return _CGRectMakeZero();
875 
876  var frame = [self _insetBounds];
877 
878  frame.size.height = _CGRectGetHeight([headerView frame]);
879 
881  frame.size.width -= _CGRectGetWidth([self _cornerViewFrame]);
882 
883  return frame;
884 }
885 
886 /* @ignore */
887 - (CGRect)_bottomCornerViewFrame
888 {
889  if ([[self horizontalScroller] isHidden] || [[self verticalScroller] isHidden])
890  return CGRectMakeZero();
891 
892  var verticalFrame = [[self verticalScroller] frame],
893  bottomCornerFrame = CGRectMakeZero();
894 
895  bottomCornerFrame.origin.x = CGRectGetMinX(verticalFrame);
896  bottomCornerFrame.origin.y = CGRectGetMaxY(verticalFrame);
897  bottomCornerFrame.size.width = [CPScroller scrollerWidthInStyle:_scrollerStyle];
898  bottomCornerFrame.size.height = [CPScroller scrollerWidthInStyle:_scrollerStyle];
899 
900  return bottomCornerFrame;
901 }
902 
903 /* @ignore */
904 - (void)_verticalScrollerDidScroll:(CPScroller)aScroller
905 {
906  var value = [aScroller floatValue],
907  documentFrame = [[_contentView documentView] frame],
908  contentBounds = [_contentView bounds];
909 
910 
911  switch ([_verticalScroller hitPart])
912  {
914  contentBounds.origin.y -= _verticalLineScroll;
915  break;
916 
918  contentBounds.origin.y += _verticalLineScroll;
919  break;
920 
922  contentBounds.origin.y -= _CGRectGetHeight(contentBounds) - _verticalPageScroll;
923  break;
924 
926  contentBounds.origin.y += _CGRectGetHeight(contentBounds) - _verticalPageScroll;
927  break;
928 
929  // We want integral bounds!
930  case CPScrollerKnobSlot:
931  case CPScrollerKnob:
932  default:
933  contentBounds.origin.y = ROUND(value * (_CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentBounds)));
934  }
935 
936  [self _sendDelegateMessages];
937 
938  [_contentView scrollToPoint:contentBounds.origin];
939 }
940 
941 /* @ignore */
942 - (void)_horizontalScrollerDidScroll:(CPScroller)aScroller
943 {
944  var value = [aScroller floatValue],
945  documentFrame = [[self documentView] frame],
946  contentBounds = [_contentView bounds];
947 
948  switch ([_horizontalScroller hitPart])
949  {
951  contentBounds.origin.x -= _horizontalLineScroll;
952  break;
953 
955  contentBounds.origin.x += _horizontalLineScroll;
956  break;
957 
959  contentBounds.origin.x -= _CGRectGetWidth(contentBounds) - _horizontalPageScroll;
960  break;
961 
963  contentBounds.origin.x += _CGRectGetWidth(contentBounds) - _horizontalPageScroll;
964  break;
965 
966  // We want integral bounds!
967  case CPScrollerKnobSlot:
968  case CPScrollerKnob:
969  default:
970  contentBounds.origin.x = ROUND(value * (_CGRectGetWidth(documentFrame) - _CGRectGetWidth(contentBounds)));
971  }
972 
973  [self _sendDelegateMessages];
974 
975  [_contentView scrollToPoint:contentBounds.origin];
976  [_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0.0)];
977 }
978 
979 /* @ignore */
980 - (void)_sendDelegateMessages
981 {
982  if (_implementedDelegateMethods == 0)
983  return;
984 
985  if (!_scrollTimer)
986  {
987  [self _scrollViewWillScroll];
988  _scrollTimer = [CPTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL target:self selector:@selector(_scrollViewDidScroll) userInfo:nil repeats:YES];
989  }
990  else
991  [_scrollTimer setFireDate:[CPDate dateWithTimeIntervalSinceNow:TIMER_INTERVAL]];
992 }
993 
994 /* @ignore */
995 - (void)_hideScrollers:(CPTimer)theTimer
996 {
997  if ([_verticalScroller allowFadingOut])
998  [_verticalScroller fadeOut];
999  if ([_horizontalScroller allowFadingOut])
1000  [_horizontalScroller fadeOut];
1001  _timerScrollersHide = nil;
1002 }
1003 
1004 /* @ignore */
1005 - (void)_respondToScrollWheelEventWithDeltaX:(float)deltaX deltaY:(float)deltaY
1006 {
1007  var documentFrame = [[self documentView] frame],
1008  contentBounds = [_contentView bounds],
1009  contentFrame = [_contentView frame],
1010  enclosingScrollView = [self enclosingScrollView];
1011 
1012  // We want integral bounds!
1013  contentBounds.origin.x = ROUND(contentBounds.origin.x + deltaX);
1014  contentBounds.origin.y = ROUND(contentBounds.origin.y + deltaY);
1015 
1016  var constrainedOrigin = [_contentView constrainScrollPoint:CGPointCreateCopy(contentBounds.origin)],
1017  extraX = contentBounds.origin.x - constrainedOrigin.x,
1018  extraY = contentBounds.origin.y - constrainedOrigin.y;
1019 
1020  [self _sendDelegateMessages];
1021 
1022  [_contentView scrollToPoint:constrainedOrigin];
1023  [_headerClipView scrollToPoint:CGPointMake(constrainedOrigin.x, 0.0)];
1024 
1025  if (extraX || extraY)
1026  [enclosingScrollView _respondToScrollWheelEventWithDeltaX:extraX deltaY:extraY];
1027 }
1028 
1029 /* @ignore */
1030 - (void)_scrollViewWillScroll
1031 {
1032  if (_implementedDelegateMethods & CPScrollViewDelegate_scrollViewWillScroll_)
1033  [_delegate scrollViewWillScroll:self];
1034 }
1035 
1036 /* @ignore */
1037 - (void)_scrollViewDidScroll
1038 {
1039  [_scrollTimer invalidate];
1040  _scrollTimer = nil;
1041 
1042  if (_implementedDelegateMethods & CPScrollViewDelegate_scrollViewDidScroll_)
1043  [_delegate scrollViewDidScroll:self];
1044 }
1045 
1047 - (void)_didReceiveDefaultStyleChange:(CPNotification)aNotification
1048 {
1049  [self setScrollerStyle:CPScrollerStyleGlobal];
1050 }
1051 
1052 
1053 
1054 #pragma mark -
1055 #pragma mark Utilities
1056 
1060 - (void)tile
1061 {
1062  // yuck.
1063  // RESIZE: tile->setHidden AND refl
1064  // Outside Change: refl->tile->setHidden AND refl
1065  // scroll: refl.
1066 }
1067 
1073 - (void)reflectScrolledClipView:(CPClipView)aClipView
1074 {
1075  if (_contentView !== aClipView)
1076  return;
1077 
1078  if (_recursionCount > 5)
1079  return;
1080 
1081  ++_recursionCount;
1082 
1083  var documentView = [self documentView];
1084 
1085  if (!documentView)
1086  {
1087  if (_autohidesScrollers)
1088  {
1089  [_verticalScroller setHidden:YES];
1090  [_horizontalScroller setHidden:YES];
1091  }
1092 
1093  [_contentView setFrame:[self _insetBounds]];
1094  [_headerClipView setFrame:_CGRectMakeZero()];
1095 
1096  --_recursionCount;
1097 
1098  return;
1099  }
1100 
1101  var documentFrame = [documentView frame], // the size of the whole document
1102  contentFrame = [self _insetBounds], // assume it takes up the entire size of the scrollview (no scrollers)
1103  headerClipViewFrame = [self _headerClipViewFrame],
1104  headerClipViewHeight = _CGRectGetHeight(headerClipViewFrame);
1105 
1106  contentFrame.origin.y += headerClipViewHeight;
1107  contentFrame.size.height -= headerClipViewHeight;
1108 
1109  var difference = _CGSizeMake(_CGRectGetWidth(documentFrame) - _CGRectGetWidth(contentFrame), _CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentFrame)),
1110  verticalScrollerWidth = _CGRectGetWidth([_verticalScroller frame]),
1111  horizontalScrollerHeight = _CGRectGetHeight([_horizontalScroller frame]),
1112  hasVerticalScroll = difference.height > 0.0,
1113  hasHorizontalScroll = difference.width > 0.0,
1114  shouldShowVerticalScroller = _hasVerticalScroller && (!_autohidesScrollers || hasVerticalScroll),
1115  shouldShowHorizontalScroller = _hasHorizontalScroller && (!_autohidesScrollers || hasHorizontalScroll);
1116 
1117  // Now we have to account for the shown scrollers affecting the deltas.
1118  if (shouldShowVerticalScroller)
1119  {
1120  if (_scrollerStyle === CPScrollerStyleLegacy)
1121  difference.width += verticalScrollerWidth;
1122  hasHorizontalScroll = difference.width > 0.0;
1123  shouldShowHorizontalScroller = _hasHorizontalScroller && (!_autohidesScrollers || hasHorizontalScroll);
1124  }
1125 
1126  if (shouldShowHorizontalScroller)
1127  {
1128  if (_scrollerStyle === CPScrollerStyleLegacy)
1129  difference.height += horizontalScrollerHeight;
1130  hasVerticalScroll = difference.height > 0.0;
1131  shouldShowVerticalScroller = _hasVerticalScroller && (!_autohidesScrollers || hasVerticalScroll);
1132  }
1133 
1134  // We now definitively know which scrollers are shown or not, as well as whether they are showing scroll values.
1135  [_verticalScroller setHidden:!shouldShowVerticalScroller];
1136  [_verticalScroller setEnabled:hasVerticalScroll];
1137 
1138  [_horizontalScroller setHidden:!shouldShowHorizontalScroller];
1139  [_horizontalScroller setEnabled:hasHorizontalScroll];
1140 
1141  var overlay = [CPScroller scrollerOverlay];
1142  if (_scrollerStyle === CPScrollerStyleLegacy)
1143  {
1144  // We can thus appropriately account for them changing the content size.
1145  if (shouldShowVerticalScroller)
1146  contentFrame.size.width -= verticalScrollerWidth;
1147 
1148  if (shouldShowHorizontalScroller)
1149  contentFrame.size.height -= horizontalScrollerHeight;
1150  overlay = 0;
1151  }
1152 
1153  var scrollPoint = [_contentView bounds].origin,
1154  wasShowingVerticalScroller = ![_verticalScroller isHidden],
1155  wasShowingHorizontalScroller = ![_horizontalScroller isHidden];
1156 
1157  if (shouldShowVerticalScroller)
1158  {
1159  var verticalScrollerY =
1160  MAX(_CGRectGetMinY(contentFrame), MAX(_CGRectGetMaxY([self _cornerViewFrame]), _CGRectGetMaxY(headerClipViewFrame)));
1161 
1162  var verticalScrollerHeight = _CGRectGetMaxY(contentFrame) - verticalScrollerY;
1163 
1164  // Make a gap at the bottom of the vertical scroller so that the horizontal and vertical can't overlap.
1165  if (_scrollerStyle === CPScrollerStyleOverlay && hasHorizontalScroll)
1166  verticalScrollerHeight -= horizontalScrollerHeight;
1167 
1168  var documentHeight = _CGRectGetHeight(documentFrame);
1169  [_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height];
1170  [_verticalScroller setKnobProportion:documentHeight > 0 ? _CGRectGetHeight(contentFrame) / documentHeight : 1.0];
1171  [_verticalScroller setFrame:_CGRectMake(_CGRectGetMaxX(contentFrame) - overlay, verticalScrollerY, verticalScrollerWidth, verticalScrollerHeight)];
1172  }
1173  else if (wasShowingVerticalScroller)
1174  {
1175  [_verticalScroller setFloatValue:0.0];
1176  [_verticalScroller setKnobProportion:1.0];
1177  }
1178 
1179  if (shouldShowHorizontalScroller)
1180  {
1181  var horizontalScrollerWidth = _CGRectGetWidth(contentFrame);
1182  // Make a gap at the bottom of the vertical scroller so that the horizontal and vertical can't overlap.
1183  if (_scrollerStyle === CPScrollerStyleOverlay && hasVerticalScroll)
1184  horizontalScrollerWidth -= verticalScrollerWidth;
1185 
1186  var documentWidth = _CGRectGetWidth(documentFrame);
1187 
1188  [_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width];
1189  [_horizontalScroller setKnobProportion:documentWidth > 0 ? _CGRectGetWidth(contentFrame) / documentWidth : 1.0];
1190  [_horizontalScroller setFrame:_CGRectMake(_CGRectGetMinX(contentFrame), _CGRectGetMaxY(contentFrame) - overlay, horizontalScrollerWidth, horizontalScrollerHeight)];
1191  }
1192  else if (wasShowingHorizontalScroller)
1193  {
1194  [_horizontalScroller setFloatValue:0.0];
1195  [_horizontalScroller setKnobProportion:1.0];
1196  }
1197 
1198  [_contentView setFrame:contentFrame];
1199  [_headerClipView setFrame:[self _headerClipViewFrame]];
1200  [[_headerClipView documentView] setNeedsDisplay:YES];
1202  {
1203  [_cornerView setFrame:[self _cornerViewFrame]];
1204  [_cornerView setHidden:NO];
1205  }
1206  else
1207  [_cornerView setHidden:YES];
1208 
1209  if (_scrollerStyle === CPScrollerStyleLegacy)
1210  {
1211  [[self bottomCornerView] setFrame:[self _bottomCornerViewFrame]];
1212  [[self bottomCornerView] setBackgroundColor:[self currentValueForThemeAttribute:@"bottom-corner-color"]];
1213  }
1214 
1215  --_recursionCount;
1216 }
1217 
1221 - (void)flashScrollers
1222 {
1223  if (_scrollerStyle === CPScrollerStyleLegacy)
1224  return;
1225 
1226  if (_hasHorizontalScroller)
1227  {
1228  [_horizontalScroller setHidden:NO];
1229  [_horizontalScroller fadeIn];
1230  }
1231 
1232  if (_hasVerticalScroller)
1233  {
1234  [_verticalScroller setHidden:NO];
1235  [_verticalScroller fadeIn];
1236  }
1237 
1238  if (_timerScrollersHide)
1239  [_timerScrollersHide invalidate]
1240 
1241  _timerScrollersHide = [CPTimer scheduledTimerWithTimeInterval:CPScrollViewFadeOutTime target:self selector:@selector(_hideScrollers:) userInfo:nil repeats:NO];
1242 }
1243 
1244 /* @ignore */
1245 - (void)resizeSubviewsWithOldSize:(CGSize)aSize
1246 {
1247  [self reflectScrolledClipView:_contentView];
1248 }
1249 
1250 
1251 #pragma mark -
1252 #pragma mark Overrides
1253 
1254 - (void)drawRect:(CPRect)aRect
1255 {
1256  [super drawRect:aRect];
1257 
1258  if (_borderType == CPNoBorder)
1259  return;
1260 
1261  var strokeRect = [self bounds],
1263 
1264  CGContextSetLineWidth(context, 1);
1265 
1266  switch (_borderType)
1267  {
1268  case CPLineBorder:
1269  CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:@"border-color"]);
1270  CGContextStrokeRect(context, _CGRectInset(strokeRect, 0.5, 0.5));
1271  break;
1272 
1273  case CPBezelBorder:
1274  [self _drawGrayBezelInContext:context bounds:strokeRect];
1275  break;
1276 
1277  case CPGrooveBorder:
1278  [self _drawGrooveInContext:context bounds:strokeRect];
1279  break;
1280 
1281  default:
1282  break;
1283  }
1284 }
1285 
1286 - (void)_drawGrayBezelInContext:(CGContext)context bounds:(CGRect)aRect
1287 {
1288  var minX = _CGRectGetMinX(aRect),
1289  maxX = _CGRectGetMaxX(aRect),
1290  minY = _CGRectGetMinY(aRect),
1291  maxY = _CGRectGetMaxY(aRect),
1292  y = minY + 0.5;
1293 
1294  // Slightly darker line on top.
1295  CGContextSetStrokeColor(context, [CPColor colorWithWhite:142.0 / 255.0 alpha:1.0]);
1296  CGContextBeginPath(context);
1297  CGContextMoveToPoint(context, minX, y);
1298  CGContextAddLineToPoint(context, maxX, y);
1299  CGContextStrokePath(context);
1300 
1301  // The rest of the border.
1302  CGContextSetStrokeColor(context, [CPColor colorWithWhite:192.0 / 255.0 alpha:1.0]);
1303 
1304  var x = maxX - 0.5;
1305 
1306  CGContextBeginPath(context);
1307  CGContextMoveToPoint(context, x, minY + 1.0);
1308  CGContextAddLineToPoint(context, x, maxY);
1309  CGContextMoveToPoint(context, x - 0.5, maxY - 0.5);
1310  CGContextAddLineToPoint(context, minX, maxY - 0.5);
1311 
1312  x = minX + 0.5;
1313 
1314  CGContextMoveToPoint(context, x, maxY);
1315  CGContextAddLineToPoint(context, x, minY + 1.0);
1316 
1317  CGContextStrokePath(context);
1318 }
1319 
1320 - (void)_drawGrooveInContext:(CGContext)context bounds:(CGRect)aRect
1321 {
1322  var minX = _CGRectGetMinX(aRect),
1323  maxX = _CGRectGetMaxX(aRect),
1324  minY = _CGRectGetMinY(aRect),
1325  maxY = _CGRectGetMaxY(aRect);
1326 
1327  CGContextBeginPath(context);
1328  CGContextSetStrokeColor(context, [CPColor colorWithWhite:159.0 / 255.0 alpha:1.0]);
1329 
1330  var y = minY + 0.5;
1331 
1332  CGContextMoveToPoint(context, minX, y);
1333  CGContextAddLineToPoint(context, maxX, y);
1334 
1335  var x = maxX - 1.5;
1336 
1337  CGContextMoveToPoint(context, x, minY + 2.0);
1338  CGContextAddLineToPoint(context, x, maxY - 1.0);
1339 
1340  y = maxY - 1.5;
1341 
1342  CGContextMoveToPoint(context, maxX - 1.0, y);
1343  CGContextAddLineToPoint(context, minX + 2.0, y);
1344 
1345  x = minX + 0.5;
1346 
1347  CGContextMoveToPoint(context, x, maxY);
1348  CGContextAddLineToPoint(context, x, minY);
1349 
1350  CGContextStrokePath(context);
1351 
1352  CGContextBeginPath(context);
1353  CGContextSetStrokeColor(context, [CPColor whiteColor]);
1354 
1355  var rect = _CGRectOffset(aRect, 1.0, 1.0);
1356 
1357  rect.size.width -= 1.0;
1358  rect.size.height -= 1.0;
1359  CGContextStrokeRect(context, _CGRectInset(rect, 0.5, 0.5));
1360 
1361  CGContextBeginPath(context);
1362  CGContextSetStrokeColor(context, [CPColor colorWithWhite:192.0 / 255.0 alpha:1.0]);
1363 
1364  y = minY + 2.5;
1365 
1366  CGContextMoveToPoint(context, minX + 2.0, y);
1367  CGContextAddLineToPoint(context, maxX - 2.0, y);
1368  CGContextStrokePath(context);
1369 }
1370 
1376 - (void)scrollWheel:(CPEvent)anEvent
1377 {
1378  if (_timerScrollersHide)
1379  [_timerScrollersHide invalidate];
1380  if (![_verticalScroller isHidden])
1381  [_verticalScroller fadeIn];
1382  if (![_horizontalScroller isHidden])
1383  [_horizontalScroller fadeIn];
1384  if (![_horizontalScroller isHidden] || ![_verticalScroller isHidden])
1385  _timerScrollersHide = [CPTimer scheduledTimerWithTimeInterval:CPScrollViewFadeOutTime target:self selector:@selector(_hideScrollers:) userInfo:nil repeats:NO];
1386 
1387  [self _respondToScrollWheelEventWithDeltaX:[anEvent deltaX] deltaY:[anEvent deltaY]];
1388 }
1389 
1390 - (void)scrollPageUp:(id)sender
1391 {
1392  var contentBounds = [_contentView bounds];
1393  [self moveByOffset:CGSizeMake(0.0, -(_CGRectGetHeight(contentBounds) - _verticalPageScroll))];
1394 }
1395 
1396 - (void)scrollPageDown:(id)sender
1397 {
1398  var contentBounds = [_contentView bounds];
1399  [self moveByOffset:CGSizeMake(0.0, _CGRectGetHeight(contentBounds) - _verticalPageScroll)];
1400 }
1401 
1402 - (void)scrollToBeginningOfDocument:(id)sender
1403 {
1404  [_contentView scrollToPoint:_CGPointMakeZero()];
1405  [_headerClipView scrollToPoint:_CGPointMakeZero()];
1406 }
1407 
1408 - (void)scrollToEndOfDocument:(id)sender
1409 {
1410  var contentBounds = [_contentView bounds],
1411  documentFrame = [[self documentView] frame],
1412  scrollPoint = _CGPointMake(0.0, _CGRectGetHeight(documentFrame) - _CGRectGetHeight(contentBounds));
1413 
1414  [_contentView scrollToPoint:scrollPoint];
1415  [_headerClipView scrollToPoint:_CGPointMakeZero()];
1416 }
1417 
1418 - (void)moveLeft:(id)sender
1419 {
1420  [self moveByOffset:CGSizeMake(-_horizontalLineScroll, 0.0)];
1421 }
1422 
1423 - (void)moveRight:(id)sender
1424 {
1425  [self moveByOffset:CGSizeMake(_horizontalLineScroll, 0.0)];
1426 }
1427 
1428 - (void)moveUp:(id)sender
1429 {
1430  [self moveByOffset:CGSizeMake(0.0, -_verticalLineScroll)];
1431 }
1432 
1433 - (void)moveDown:(id)sender
1434 {
1435  [self moveByOffset:CGSizeMake(0.0, _verticalLineScroll)];
1436 }
1437 
1438 - (void)moveByOffset:(CGSize)aSize
1439 {
1440  var documentFrame = [[self documentView] frame],
1441  contentBounds = [_contentView bounds];
1442 
1443  contentBounds.origin.x += aSize.width;
1444  contentBounds.origin.y += aSize.height;
1445 
1446  [_contentView scrollToPoint:contentBounds.origin];
1447  [_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0)];
1448 }
1449 
1450 @end
1451 
1452 
1453 var CPScrollViewContentViewKey = @"CPScrollViewContentView",
1454  CPScrollViewHeaderClipViewKey = @"CPScrollViewHeaderClipViewKey",
1455  CPScrollViewVLineScrollKey = @"CPScrollViewVLineScroll",
1456  CPScrollViewHLineScrollKey = @"CPScrollViewHLineScroll",
1457  CPScrollViewVPageScrollKey = @"CPScrollViewVPageScroll",
1458  CPScrollViewHPageScrollKey = @"CPScrollViewHPageScroll",
1459  CPScrollViewHasVScrollerKey = @"CPScrollViewHasVScroller",
1460  CPScrollViewHasHScrollerKey = @"CPScrollViewHasHScroller",
1461  CPScrollViewVScrollerKey = @"CPScrollViewVScroller",
1462  CPScrollViewHScrollerKey = @"CPScrollViewHScroller",
1463  CPScrollViewAutohidesScrollerKey = @"CPScrollViewAutohidesScroller",
1464  CPScrollViewCornerViewKey = @"CPScrollViewCornerViewKey",
1465  CPScrollViewBottomCornerViewKey = @"CPScrollViewBottomCornerViewKey",
1466  CPScrollViewBorderTypeKey = @"CPScrollViewBorderTypeKey",
1467  CPScrollViewScrollerStyleKey = @"CPScrollViewScrollerStyleKey",
1468  CPScrollViewScrollerKnobStyleKey = @"CPScrollViewScrollerKnobStyleKey";
1469 
1471 
1472 - (id)initWithCoder:(CPCoder)aCoder
1473 {
1474  if (self = [super initWithCoder:aCoder])
1475  {
1476  _verticalLineScroll = [aCoder decodeFloatForKey:CPScrollViewVLineScrollKey];
1477  _verticalPageScroll = [aCoder decodeFloatForKey:CPScrollViewVPageScrollKey];
1478 
1479  _horizontalLineScroll = [aCoder decodeFloatForKey:CPScrollViewHLineScrollKey];
1480  _horizontalPageScroll = [aCoder decodeFloatForKey:CPScrollViewHPageScrollKey];
1481 
1482  _contentView = [aCoder decodeObjectForKey:CPScrollViewContentViewKey];
1483  _headerClipView = [aCoder decodeObjectForKey:CPScrollViewHeaderClipViewKey];
1484 
1485  if (!_headerClipView)
1486  {
1487  _headerClipView = [[CPClipView alloc] init];
1488  [self addSubview:_headerClipView];
1489  }
1490 
1491  _verticalScroller = [aCoder decodeObjectForKey:CPScrollViewVScrollerKey];
1492  _horizontalScroller = [aCoder decodeObjectForKey:CPScrollViewHScrollerKey];
1493 
1494  _hasVerticalScroller = [aCoder decodeBoolForKey:CPScrollViewHasVScrollerKey];
1495  _hasHorizontalScroller = [aCoder decodeBoolForKey:CPScrollViewHasHScrollerKey];
1496  _autohidesScrollers = [aCoder decodeBoolForKey:CPScrollViewAutohidesScrollerKey];
1497 
1498  _borderType = [aCoder decodeIntForKey:CPScrollViewBorderTypeKey];
1499 
1500  _cornerView = [aCoder decodeObjectForKey:CPScrollViewCornerViewKey];
1501  _bottomCornerView = [aCoder decodeObjectForKey:CPScrollViewBottomCornerViewKey];
1502 
1503  _delegate = nil;
1504  _scrollTimer = nil;
1505  _implementedDelegateMethods = 0;
1506 
1507  _scrollerStyle = [aCoder decodeObjectForKey:CPScrollViewScrollerStyleKey] || CPScrollerStyleGlobal;
1508  _scrollerKnobStyle = [aCoder decodeObjectForKey:CPScrollViewScrollerKnobStyleKey] || CPScrollerKnobStyleDefault;
1509 
1512  name:CPScrollerStyleGlobalChangeNotification
1513  object:nil];
1514  }
1515 
1516  return self;
1517 }
1518 
1522 - (void)awakeFromCib
1523 {
1524  [self _updateScrollerStyle];
1525  [self _updateCornerAndHeaderView];
1526 }
1527 
1528 - (void)encodeWithCoder:(CPCoder)aCoder
1529 {
1530  [super encodeWithCoder:aCoder];
1531 
1532  [aCoder encodeObject:_contentView forKey:CPScrollViewContentViewKey];
1533  [aCoder encodeObject:_headerClipView forKey:CPScrollViewHeaderClipViewKey];
1534 
1535  [aCoder encodeObject:_verticalScroller forKey:CPScrollViewVScrollerKey];
1536  [aCoder encodeObject:_horizontalScroller forKey:CPScrollViewHScrollerKey];
1537 
1538  [aCoder encodeFloat:_verticalLineScroll forKey:CPScrollViewVLineScrollKey];
1539  [aCoder encodeFloat:_verticalPageScroll forKey:CPScrollViewVPageScrollKey];
1540  [aCoder encodeFloat:_horizontalLineScroll forKey:CPScrollViewHLineScrollKey];
1541  [aCoder encodeFloat:_horizontalPageScroll forKey:CPScrollViewHPageScrollKey];
1542 
1543  [aCoder encodeBool:_hasVerticalScroller forKey:CPScrollViewHasVScrollerKey];
1544  [aCoder encodeBool:_hasHorizontalScroller forKey:CPScrollViewHasHScrollerKey];
1545  [aCoder encodeBool:_autohidesScrollers forKey:CPScrollViewAutohidesScrollerKey];
1546 
1547  [aCoder encodeObject:_cornerView forKey:CPScrollViewCornerViewKey];
1548  [aCoder encodeObject:_bottomCornerView forKey:CPScrollViewBottomCornerViewKey];
1549 
1550  [aCoder encodeInt:_borderType forKey:CPScrollViewBorderTypeKey];
1551 
1552  [aCoder encodeInt:_scrollerStyle forKey:CPScrollViewScrollerStyleKey];
1553  [aCoder encodeInt:_scrollerKnobStyle forKey:CPScrollViewScrollerKnobStyleKey];
1554 }
1555 
1556 @end