API  0.9.8
 All Classes Files Functions Variables Typedefs 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 
33 @optional
34 - (void)scrollViewWillScroll:(CPScrollView)aScrollView;
35 - (void)scrollViewDidScroll:(CPScrollView)aScrollView;
36 
37 @end
38 
39 
41 var _isBrowserUsingOverlayScrollers = function()
42 {
43 #if PLATFORM(DOM)
44  /*
45  Even if the system supports overlay (Lion) scrollers,
46  the browser (e.g. FireFox *cough*) may not.
47 
48  To determine if the browser is using overlay scrollbars,
49  we put a <p> element inside a shorter <div> and set its
50  overflow to scroll. If the browser is using visible scrollers,
51  the outer div's clientWidth will less than the offsetWidth, because
52  clientWidth does not include scrollbars, whereas offsetWidth does.
53  So if clientWidth === offsetWidth, the scrollers must be overlay.
54  Even IE gets this right.
55  */
56  var outer = document.createElement('div'),
57  inner = document.createElement('p');
58 
59  // position it absolute so it doesn't affect existing DOM elements
60  outer.style.position = "absolute";
61  outer.style.top = "0px";
62  outer.style.left = "0px";
63  outer.style.visibility = "hidden";
64  outer.style.width = "200px";
65  outer.style.height = "150px";
66  outer.style.overflow = "scroll";
67 
68  inner.style.width = "100%";
69  inner.style.height = "200px";
70  outer.appendChild(inner);
71 
72  document.body.appendChild(outer);
73 
74  var usingOverlayScrollers = outer.clientWidth === outer.offsetWidth;
75 
76  document.body.removeChild(outer);
77 
78  return usingOverlayScrollers;
79 #else
80  return NO;
81 #endif
82 };
83 
92 var TIMER_INTERVAL = 0.2,
95 
97 
99  CPScrollerStyleGlobalChangeNotification = @"CPScrollerStyleGlobalChangeNotification";
100 
101 
102 @implementation CPScrollView : CPView
103 {
104  CPClipView _contentView;
105  CPClipView _headerClipView;
106  CPView _cornerView;
107  CPView _bottomCornerView;
108 
109  id <CPScrollViewDelegate> _delegate;
110  CPTimer _scrollTimer;
111 
112  BOOL _hasVerticalScroller;
113  BOOL _hasHorizontalScroller;
114  BOOL _autohidesScrollers;
115 
116  CPScroller _verticalScroller;
117  CPScroller _horizontalScroller;
118 
119  CPInteger _recursionCount;
120  CPInteger _implementedDelegateMethods;
121 
122  float _verticalLineScroll;
123  float _verticalPageScroll;
124  float _horizontalLineScroll;
125  float _horizontalPageScroll;
126 
127  CPBorderType _borderType;
128 
129  CPTimer _timerScrollersHide;
130 
131  int _scrollerStyle;
132  int _scrollerKnobStyle;
133 }
134 
135 
136 #pragma mark -
137 #pragma mark Class methods
138 
139 + (void)initialize
140 {
141  if (self !== [CPScrollView class])
142  return;
143 
144  var globalValue = [[CPBundle mainBundle] objectForInfoDictionaryKey:@"CPScrollersGlobalStyle"];
145 
146  if (globalValue === nil || globalValue === -1)
147  CPScrollerStyleGlobal = _isBrowserUsingOverlayScrollers() ? CPScrollerStyleOverlay : CPScrollerStyleLegacy
148  else
149  CPScrollerStyleGlobal = globalValue;
150 }
151 
152 + (CPString)defaultThemeClass
153 {
154  return @"scrollview"
155 }
156 
157 + (CPDictionary)themeAttributes
158 {
159  return @{
160  @"bottom-corner-color": [CPColor whiteColor],
161  @"border-color": [CPColor blackColor]
162  };
163 }
164 
165 + (CGSize)contentSizeForFrameSize:(CGSize)frameSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType
166 {
167  var bounds = [self _insetBounds:CGRectMake(0.0, 0.0, frameSize.width, frameSize.height) borderType:borderType],
168  scrollerWidth = [CPScroller scrollerWidth];
169 
170  if (hFlag)
171  bounds.size.height -= scrollerWidth;
172 
173  if (vFlag)
174  bounds.size.width -= scrollerWidth;
175 
176  return bounds.size;
177 }
178 
179 + (CGSize)frameSizeForContentSize:(CGSize)contentSize hasHorizontalScroller:(BOOL)hFlag hasVerticalScroller:(BOOL)vFlag borderType:(CPBorderType)borderType
180 {
181  var bounds = [self _insetBounds:CGRectMake(0.0, 0.0, contentSize.width, contentSize.height) borderType:borderType],
182  widthInset = contentSize.width - bounds.size.width,
183  heightInset = contentSize.height - bounds.size.height,
184  frameSize = CGSizeMake(contentSize.width + widthInset, contentSize.height + heightInset),
185  scrollerWidth = [CPScroller scrollerWidth];
186 
187  if (hFlag)
188  frameSize.height += scrollerWidth;
189 
190  if (vFlag)
191  frameSize.width += scrollerWidth;
192 
193  return frameSize;
194 }
195 
196 + (CGRect)_insetBounds:(CGRect)bounds borderType:(CPBorderType)borderType
197 {
198  switch (borderType)
199  {
200  case CPLineBorder:
201  case CPBezelBorder:
202  return CGRectInset(bounds, 1.0, 1.0);
203 
204  case CPGrooveBorder:
205  bounds = CGRectInset(bounds, 2.0, 2.0);
206  ++bounds.origin.y;
207  --bounds.size.height;
208  return bounds;
209 
210  case CPNoBorder:
211  default:
212  return bounds;
213  }
214 }
215 
219 + (int)globalScrollerStyle
220 {
221  return CPScrollerStyleGlobal;
222 }
223 
229 + (void)setGlobalScrollerStyle:(int)aStyle
230 {
231  CPScrollerStyleGlobal = aStyle;
232  [[CPNotificationCenter defaultCenter] postNotificationName:CPScrollerStyleGlobalChangeNotification object:nil];
233 }
234 
235 
236 #pragma mark -
237 #pragma mark Initialization
238 
239 - (id)initWithFrame:(CGRect)aFrame
240 {
241  self = [super initWithFrame:aFrame];
242 
243  if (self)
244  {
245  _verticalLineScroll = 10.0;
246  _verticalPageScroll = 10.0;
247 
248  _horizontalLineScroll = 10.0;
249  _horizontalPageScroll = 10.0;
250 
251  _borderType = CPNoBorder;
252 
253  _contentView = [[CPClipView alloc] initWithFrame:[self _insetBounds]];
254  [self addSubview:_contentView];
255 
256  _headerClipView = [[CPClipView alloc] init];
257  [self addSubview:_headerClipView];
258 
259  _bottomCornerView = [[CPView alloc] init];
260  [self addSubview:_bottomCornerView];
261 
262  [self setHasVerticalScroller:YES];
263  [self setHasHorizontalScroller:YES];
264  _scrollerKnobStyle = CPScrollerKnobStyleDefault;
265  [self setScrollerStyle:CPScrollerStyleGlobal];
266 
267  _delegate = nil;
268  _scrollTimer = nil;
269  _implementedDelegateMethods = 0;
270  }
271 
272  return self;
273 }
274 
275 
276 #pragma mark -
277 #pragma mark Getters / Setters
278 
282 - (id)delegate
283 {
284  return _delegate;
285 }
286 
302 - (void)setDelegate:(id <CPScrollViewDelegate>)aDelegate
303 {
304  if (aDelegate === _delegate)
305  return;
306 
307  _delegate = aDelegate;
308  _implementedDelegateMethods = 0;
309 
310  if (_delegate === nil)
311  return;
312 
313  if ([_delegate respondsToSelector:@selector(scrollViewWillScroll:)])
314  _implementedDelegateMethods |= CPScrollViewDelegate_scrollViewWillScroll_;
315 
316  if ([_delegate respondsToSelector:@selector(scrollViewDidScroll:)])
317  _implementedDelegateMethods |= CPScrollViewDelegate_scrollViewDidScroll_;
318 }
319 
320 - (int)scrollerStyle
321 {
322  return _scrollerStyle;
323 }
324 
331 - (void)setScrollerStyle:(int)aStyle
332 {
333  if (_scrollerStyle === aStyle)
334  return;
335 
336  _scrollerStyle = aStyle;
337 
338  [self _updateScrollerStyle];
339 }
340 
351 - (int)scrollerKnobStyle
352 {
353  return _scrollerKnobStyle;
354 }
355 
366 - (void)setScrollerKnobStyle:(int)newScrollerKnobStyle
367 {
368  if (_scrollerKnobStyle === newScrollerKnobStyle)
369  return;
370 
371  _scrollerKnobStyle = newScrollerKnobStyle;
372 
373  [self _updateScrollerStyle];
374 }
375 
379 - (CPClipView)contentView
380 {
381  return _contentView;
382 }
383 
389 - (void)setContentView:(CPClipView)aContentView
390 {
391  if (_contentView === aContentView || !aContentView)
392  return;
393 
394  var documentView = [aContentView documentView];
395 
396  if (documentView)
397  [documentView removeFromSuperview];
398 
399  [_contentView removeFromSuperview];
400 
401  _contentView = aContentView;
402 
403  [_contentView setDocumentView:documentView];
404 
405  [self addSubview:_contentView];
406 
407  // This will size the content view appropriately, so no need to size it in this method.
408  [self reflectScrolledClipView:_contentView];
409 }
410 
414 - (CGSize)contentSize
415 {
416  return [_contentView frame].size;
417 }
418 
422 - (id)documentView
423 {
424  return [_contentView documentView];
425 }
426 
432 - (void)setDocumentView:(CPView)aView
433 {
434  [_contentView setDocumentView:aView];
435 
436  // FIXME: This should be observed.
437  [self _updateCornerAndHeaderView];
438  [self reflectScrolledClipView:_contentView];
439 }
440 
444 - (CPBorderType)borderType
445 {
446  return _borderType;
447 }
448 
459 - (void)setBorderType:(CPBorderType)borderType
460 {
461  if (_borderType == borderType)
462  return;
463 
464  _borderType = borderType;
465 
466  [self reflectScrolledClipView:_contentView];
467  [self setNeedsDisplay:YES];
468 }
469 
470 
474 - (CPScroller)horizontalScroller
475 {
476  return _horizontalScroller;
477 }
478 
484 - (void)setHorizontalScroller:(CPScroller)aScroller
485 {
486  if (_horizontalScroller === aScroller)
487  return;
488 
489  [_horizontalScroller removeFromSuperview];
490  [_horizontalScroller setTarget:nil];
491  [_horizontalScroller setAction:nil];
492 
493  _horizontalScroller = aScroller;
494 
495  [_horizontalScroller setTarget:self];
496  [_horizontalScroller setAction:@selector(_horizontalScrollerDidScroll:)];
497 
498  [self addSubview:_horizontalScroller];
499 
500  [self _updateScrollerStyle];
501 }
502 
506 - (BOOL)hasHorizontalScroller
507 {
508  return _hasHorizontalScroller;
509 }
510 
517 - (void)setHasHorizontalScroller:(BOOL)shouldHaveHorizontalScroller
518 {
519  if (_hasHorizontalScroller === shouldHaveHorizontalScroller)
520  return;
521 
522  _hasHorizontalScroller = shouldHaveHorizontalScroller;
523 
524  if (_hasHorizontalScroller && !_horizontalScroller)
525  {
526  var bounds = [self _insetBounds];
527 
528  [self setHorizontalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, MAX(CGRectGetWidth(bounds), [CPScroller scrollerWidthInStyle:_scrollerStyle] + 1), [CPScroller scrollerWidthInStyle:_scrollerStyle])]];
529  [[self horizontalScroller] setFrameSize:CGSizeMake(CGRectGetWidth(bounds), [CPScroller scrollerWidthInStyle:_scrollerStyle])];
530  }
531 
532  [self reflectScrolledClipView:_contentView];
533 }
534 
538 - (CPScroller)verticalScroller
539 {
540  return _verticalScroller;
541 }
542 
548 - (void)setVerticalScroller:(CPScroller)aScroller
549 {
550  if (_verticalScroller === aScroller)
551  return;
552 
553  [_verticalScroller removeFromSuperview];
554  [_verticalScroller setTarget:nil];
555  [_verticalScroller setAction:nil];
556 
557  _verticalScroller = aScroller;
558 
559  [_verticalScroller setTarget:self];
560  [_verticalScroller setAction:@selector(_verticalScrollerDidScroll:)];
561 
562  [self addSubview:_verticalScroller];
563 
564  [self _updateScrollerStyle];
565 }
566 
570 - (BOOL)hasVerticalScroller
571 {
572  return _hasVerticalScroller;
573 }
574 
582 - (void)setHasVerticalScroller:(BOOL)shouldHaveVerticalScroller
583 {
584  if (_hasVerticalScroller === shouldHaveVerticalScroller)
585  return;
586 
587  _hasVerticalScroller = shouldHaveVerticalScroller;
588 
589  if (_hasVerticalScroller && !_verticalScroller)
590  {
591  var bounds = [self _insetBounds];
592 
593  [self setVerticalScroller:[[CPScroller alloc] initWithFrame:CGRectMake(0.0, 0.0, [CPScroller scrollerWidthInStyle:_scrollerStyle], MAX(CGRectGetHeight(bounds), [CPScroller scrollerWidthInStyle:_scrollerStyle] + 1))]];
594  [[self verticalScroller] setFrameSize:CGSizeMake([CPScroller scrollerWidthInStyle:_scrollerStyle], CGRectGetHeight(bounds))];
595  }
596 
597  [self reflectScrolledClipView:_contentView];
598 }
599 
603 - (BOOL)autohidesScrollers
604 {
605  return _autohidesScrollers;
606 }
607 
614 - (void)setAutohidesScrollers:(BOOL)autohidesScrollers
615 {
616  if (_autohidesScrollers == autohidesScrollers)
617  return;
618 
619  _autohidesScrollers = autohidesScrollers;
620 
621  [self reflectScrolledClipView:_contentView];
622 }
623 
624 - (CPView)bottomCornerView
625 {
626  return _bottomCornerView;
627 }
628 
629 - (void)setBottomCornerView:(CPView)aBottomCornerView
630 {
631  if (_bottomCornerView === aBottomCornerView)
632  return;
633 
634  [_bottomCornerView removeFromSuperview];
635 
636  [aBottomCornerView setFrame:[self _bottomCornerViewFrame]];
637  [self addSubview:aBottomCornerView];
638 
639  _bottomCornerView = aBottomCornerView;
640 
641  [self _updateCornerAndHeaderView];
642 }
643 
647 - (float)lineScroll
648 {
649  return [self horizontalLineScroll];
650 }
651 
657 - (void)setLineScroll:(float)aLineScroll
658 {
659  [self setHorizontalLineScroll:aLineScroll];
660  [self setVerticalLineScroll:aLineScroll];
661 }
662 
666 - (float)horizontalLineScroll
667 {
668  return _horizontalLineScroll;
669 }
670 
676 - (void)setHorizontalLineScroll:(float)aLineScroll
677 {
678  _horizontalLineScroll = aLineScroll;
679 }
680 
684 - (float)verticalLineScroll
685 {
686  return _verticalLineScroll;
687 }
688 
694 - (void)setVerticalLineScroll:(float)aLineScroll
695 {
696  _verticalLineScroll = aLineScroll;
697 }
698 
702 - (float)pageScroll
703 {
704  return [self horizontalPageScroll];
705 }
706 
712 - (void)setPageScroll:(float)aPageScroll
713 {
714  [self setHorizontalPageScroll:aPageScroll];
715  [self setVerticalPageScroll:aPageScroll];
716 }
717 
721 - (float)horizontalPageScroll
722 {
723  return _horizontalPageScroll;
724 }
725 
731 - (void)setHorizontalPageScroll:(float)aPageScroll
732 {
733  _horizontalPageScroll = aPageScroll;
734 }
735 
739 - (float)verticalPageScroll
740 {
741  return _verticalPageScroll;
742 }
743 
749 - (void)setVerticalPageScroll:(float)aPageScroll
750 {
751  _verticalPageScroll = aPageScroll;
752 }
753 
754 
755 #pragma mark -
756 #pragma mark Privates
757 
758 /* @ignore */
759 - (void)_updateScrollerStyle
760 {
761  if (_hasHorizontalScroller)
762  {
763  [_horizontalScroller setStyle:_scrollerStyle];
764  [_horizontalScroller unsetThemeState:CPThemeStateSelected];
765 
766  switch (_scrollerKnobStyle)
767  {
769  [_horizontalScroller unsetThemeState:CPThemeStateScrollerKnobDark];
770  [_horizontalScroller setThemeState:CPThemeStateScrollerKnobLight];
771  break;
772 
774  [_horizontalScroller unsetThemeState:CPThemeStateScrollerKnobLight];
775  [_horizontalScroller setThemeState:CPThemeStateScrollerKnobDark];
776  break;
777 
778  default:
779  [_horizontalScroller unsetThemeState:CPThemeStateScrollerKnobLight];
780  [_horizontalScroller unsetThemeState:CPThemeStateScrollerKnobDark];
781  }
782  }
783 
784  if (_hasVerticalScroller)
785  {
786  [_verticalScroller setStyle:_scrollerStyle];
787  [_verticalScroller unsetThemeState:CPThemeStateSelected];
788 
789  switch (_scrollerKnobStyle)
790  {
792  [_verticalScroller unsetThemeState:CPThemeStateScrollerKnobDark];
793  [_verticalScroller setThemeState:CPThemeStateScrollerKnobLight];
794  break;
795 
797  [_verticalScroller unsetThemeState:CPThemeStateScrollerKnobLight];
798  [_verticalScroller setThemeState:CPThemeStateScrollerKnobDark];
799  break;
800 
801  default:
802  [_verticalScroller unsetThemeState:CPThemeStateScrollerKnobLight];
803  [_verticalScroller unsetThemeState:CPThemeStateScrollerKnobDark];
804  }
805  }
806 
807  if (_scrollerStyle == CPScrollerStyleOverlay)
808  {
809  if (_timerScrollersHide)
810  [_timerScrollersHide invalidate];
811 
812  _timerScrollersHide = [CPTimer scheduledTimerWithTimeInterval:CPScrollViewFadeOutTime target:self selector:@selector(_hideScrollers:) userInfo:nil repeats:NO];
813  [[self bottomCornerView] setHidden:YES];
814  }
815  else
816  [[self bottomCornerView] setHidden:NO];
817 
818  [self reflectScrolledClipView:_contentView];
819 }
820 
821 /* @ignore */
822 - (CGRect)_insetBounds
823 {
824  return [[self class] _insetBounds:[self bounds] borderType:_borderType];
825 }
826 
827 /* @ignore */
828 - (void)_updateCornerAndHeaderView
829 {
830  var documentView = [self documentView],
831  currentHeaderView = [self _headerView],
832  documentHeaderView = [documentView respondsToSelector:@selector(headerView)] ? [documentView headerView] : nil;
833 
834  if (currentHeaderView !== documentHeaderView)
835  {
836  [currentHeaderView removeFromSuperview];
837  [_headerClipView setDocumentView:documentHeaderView];
838  }
839 
840  var documentCornerView = [documentView respondsToSelector:@selector(cornerView)] ? [documentView cornerView] : nil;
841 
842  if (_cornerView !== documentCornerView)
843  {
844  [_cornerView removeFromSuperview];
845 
846  _cornerView = documentCornerView;
847 
848  if (_cornerView)
849  {
850  [_cornerView setHidden:!SHOULD_SHOW_CORNER_VIEW()];
851  [self addSubview:_cornerView];
852  }
853  }
854 
855  [self reflectScrolledClipView:_contentView];
856  [documentHeaderView setNeedsLayout];
857  [documentHeaderView setNeedsDisplay:YES];
858 }
859 
860 /* @ignore */
861 - (CPView)_headerView
862 {
863  return [_headerClipView documentView];
864 }
865 
866 /* @ignore */
867 - (CGRect)_cornerViewFrame
868 {
869  if (!_cornerView)
870  return CGRectMakeZero();
871 
872  var bounds = [self _insetBounds],
873  frame = [_cornerView frame];
874 
875  frame.origin.x = CGRectGetMaxX(bounds) - CGRectGetWidth(frame);
876  frame.origin.y = CGRectGetMinY(bounds);
877 
878  return frame;
879 }
880 
881 /* @ignore */
882 - (CGRect)_headerClipViewFrame
883 {
884  var headerView = [self _headerView];
885 
886  if (!headerView)
887  return CGRectMakeZero();
888 
889  var frame = [self _insetBounds];
890 
891  frame.size.height = CGRectGetHeight([headerView frame]);
892 
894  frame.size.width -= CGRectGetWidth([self _cornerViewFrame]);
895 
896  return frame;
897 }
898 
899 /* @ignore */
900 - (CGRect)_bottomCornerViewFrame
901 {
902  if ([[self horizontalScroller] isHidden] || [[self verticalScroller] isHidden])
903  return CGRectMakeZero();
904 
905  var verticalFrame = [[self verticalScroller] frame],
906  bottomCornerFrame = CGRectMakeZero();
907 
908  bottomCornerFrame.origin.x = CGRectGetMinX(verticalFrame);
909  bottomCornerFrame.origin.y = CGRectGetMaxY(verticalFrame);
910  bottomCornerFrame.size.width = [CPScroller scrollerWidthInStyle:_scrollerStyle];
911  bottomCornerFrame.size.height = [CPScroller scrollerWidthInStyle:_scrollerStyle];
912 
913  return bottomCornerFrame;
914 }
915 
916 /* @ignore */
917 - (void)_verticalScrollerDidScroll:(CPScroller)aScroller
918 {
919  var value = [aScroller floatValue],
920  documentFrame = [[_contentView documentView] frame],
921  contentBounds = [_contentView bounds];
922 
923 
924  switch ([_verticalScroller hitPart])
925  {
927  contentBounds.origin.y -= _verticalLineScroll;
928  break;
929 
931  contentBounds.origin.y += _verticalLineScroll;
932  break;
933 
935  contentBounds.origin.y -= CGRectGetHeight(contentBounds) - _verticalPageScroll;
936  break;
937 
939  contentBounds.origin.y += CGRectGetHeight(contentBounds) - _verticalPageScroll;
940  break;
941 
942  // We want integral bounds!
943  case CPScrollerKnobSlot:
944  case CPScrollerKnob:
945  default:
946  contentBounds.origin.y = ROUND(value * (CGRectGetHeight(documentFrame) - CGRectGetHeight(contentBounds)));
947  }
948 
949  [self _sendDelegateMessages];
950 
951  [_contentView scrollToPoint:contentBounds.origin];
952 }
953 
954 /* @ignore */
955 - (void)_horizontalScrollerDidScroll:(CPScroller)aScroller
956 {
957  var value = [aScroller floatValue],
958  documentFrame = [[self documentView] frame],
959  contentBounds = [_contentView bounds];
960 
961  switch ([_horizontalScroller hitPart])
962  {
964  contentBounds.origin.x -= _horizontalLineScroll;
965  break;
966 
968  contentBounds.origin.x += _horizontalLineScroll;
969  break;
970 
972  contentBounds.origin.x -= CGRectGetWidth(contentBounds) - _horizontalPageScroll;
973  break;
974 
976  contentBounds.origin.x += CGRectGetWidth(contentBounds) - _horizontalPageScroll;
977  break;
978 
979  // We want integral bounds!
980  case CPScrollerKnobSlot:
981  case CPScrollerKnob:
982  default:
983  contentBounds.origin.x = ROUND(value * (CGRectGetWidth(documentFrame) - CGRectGetWidth(contentBounds)));
984  }
985 
986  [self _sendDelegateMessages];
987 
988  [_contentView scrollToPoint:contentBounds.origin];
989  [_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0.0)];
990 }
991 
992 /* @ignore */
993 - (void)_sendDelegateMessages
994 {
995  if (_implementedDelegateMethods == 0)
996  return;
997 
998  if (!_scrollTimer)
999  {
1000  [self _scrollViewWillScroll];
1001  _scrollTimer = [CPTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL target:self selector:@selector(_scrollViewDidScroll) userInfo:nil repeats:YES];
1002  }
1003  else
1004  [_scrollTimer setFireDate:[CPDate dateWithTimeIntervalSinceNow:TIMER_INTERVAL]];
1005 }
1006 
1007 /* @ignore */
1008 - (void)_hideScrollers:(CPTimer)theTimer
1009 {
1010  if ([_verticalScroller allowFadingOut])
1011  [_verticalScroller fadeOut];
1012  if ([_horizontalScroller allowFadingOut])
1013  [_horizontalScroller fadeOut];
1014  _timerScrollersHide = nil;
1015 }
1016 
1017 /* @ignore */
1018 - (void)_respondToScrollWheelEventWithDeltaX:(float)deltaX deltaY:(float)deltaY
1019 {
1020  var documentFrame = [[self documentView] frame],
1021  contentBounds = [_contentView bounds],
1022  contentFrame = [_contentView frame],
1023  enclosingScrollView = [self enclosingScrollView];
1024 
1025  // We want integral bounds!
1026  contentBounds.origin.x = ROUND(contentBounds.origin.x + deltaX);
1027  contentBounds.origin.y = ROUND(contentBounds.origin.y + deltaY);
1028 
1029  var constrainedOrigin = [_contentView constrainScrollPoint:CGPointCreateCopy(contentBounds.origin)],
1030  extraX = contentBounds.origin.x - constrainedOrigin.x,
1031  extraY = contentBounds.origin.y - constrainedOrigin.y;
1032 
1033  [self _sendDelegateMessages];
1034 
1035  [_contentView scrollToPoint:constrainedOrigin];
1036  [_headerClipView scrollToPoint:CGPointMake(constrainedOrigin.x, 0.0)];
1037 
1038  if (extraX || extraY)
1039  [enclosingScrollView _respondToScrollWheelEventWithDeltaX:extraX deltaY:extraY];
1040 }
1041 
1042 /* @ignore */
1043 - (void)_scrollViewWillScroll
1044 {
1045  if (_implementedDelegateMethods & CPScrollViewDelegate_scrollViewWillScroll_)
1046  [_delegate scrollViewWillScroll:self];
1047 }
1048 
1049 /* @ignore */
1050 - (void)_scrollViewDidScroll
1051 {
1052  [_scrollTimer invalidate];
1053  _scrollTimer = nil;
1054 
1055  if (_implementedDelegateMethods & CPScrollViewDelegate_scrollViewDidScroll_)
1056  [_delegate scrollViewDidScroll:self];
1057 }
1058 
1060 - (void)_didReceiveDefaultStyleChange:(CPNotification)aNotification
1061 {
1062  [self setScrollerStyle:CPScrollerStyleGlobal];
1063 }
1064 
1065 
1066 
1067 #pragma mark -
1068 #pragma mark Utilities
1069 
1073 - (void)tile
1074 {
1075  // yuck.
1076  // RESIZE: tile->setHidden AND refl
1077  // Outside Change: refl->tile->setHidden AND refl
1078  // scroll: refl.
1079 }
1080 
1086 - (void)reflectScrolledClipView:(CPClipView)aClipView
1087 {
1088  if (_contentView !== aClipView)
1089  return;
1090 
1091  if (_recursionCount > 5)
1092  return;
1093 
1094  ++_recursionCount;
1095 
1096  var documentView = [self documentView];
1097 
1098  if (!documentView)
1099  {
1100  if (_autohidesScrollers)
1101  {
1102  [_verticalScroller setHidden:YES];
1103  [_horizontalScroller setHidden:YES];
1104  }
1105 
1106  [_contentView setFrame:[self _insetBounds]];
1107  [_headerClipView setFrame:CGRectMakeZero()];
1108 
1109  --_recursionCount;
1110 
1111  return;
1112  }
1113 
1114  var documentFrame = [documentView frame], // the size of the whole document
1115  contentFrame = [self _insetBounds], // assume it takes up the entire size of the scrollview (no scrollers)
1116  headerClipViewFrame = [self _headerClipViewFrame],
1117  headerClipViewHeight = CGRectGetHeight(headerClipViewFrame);
1118 
1119  contentFrame.origin.y += headerClipViewHeight;
1120  contentFrame.size.height -= headerClipViewHeight;
1121 
1122  var difference = CGSizeMake(CGRectGetWidth(documentFrame) - CGRectGetWidth(contentFrame), CGRectGetHeight(documentFrame) - CGRectGetHeight(contentFrame)),
1123  verticalScrollerWidth = [CPScroller scrollerWidthInStyle:[_verticalScroller style]],
1124  horizontalScrollerHeight = [CPScroller scrollerWidthInStyle:[_horizontalScroller style]],
1125  hasVerticalScroll = difference.height > 0.0,
1126  hasHorizontalScroll = difference.width > 0.0,
1127  shouldShowVerticalScroller = _hasVerticalScroller && (!_autohidesScrollers || hasVerticalScroll),
1128  shouldShowHorizontalScroller = _hasHorizontalScroller && (!_autohidesScrollers || hasHorizontalScroll);
1129 
1130  // Now we have to account for the shown scrollers affecting the deltas.
1131  if (shouldShowVerticalScroller)
1132  {
1133  if (_scrollerStyle === CPScrollerStyleLegacy)
1134  difference.width += verticalScrollerWidth;
1135  hasHorizontalScroll = difference.width > 0.0;
1136  shouldShowHorizontalScroller = _hasHorizontalScroller && (!_autohidesScrollers || hasHorizontalScroll);
1137  }
1138 
1139  if (shouldShowHorizontalScroller)
1140  {
1141  if (_scrollerStyle === CPScrollerStyleLegacy)
1142  difference.height += horizontalScrollerHeight;
1143  hasVerticalScroll = difference.height > 0.0;
1144  shouldShowVerticalScroller = _hasVerticalScroller && (!_autohidesScrollers || hasVerticalScroll);
1145  }
1146 
1147  // We now definitively know which scrollers are shown or not, as well as whether they are showing scroll values.
1148  [_verticalScroller setHidden:!shouldShowVerticalScroller];
1149  [_verticalScroller setEnabled:hasVerticalScroll];
1150 
1151  [_horizontalScroller setHidden:!shouldShowHorizontalScroller];
1152  [_horizontalScroller setEnabled:hasHorizontalScroll];
1153 
1154  var overlay = [CPScroller scrollerOverlay];
1155  if (_scrollerStyle === CPScrollerStyleLegacy)
1156  {
1157  // We can thus appropriately account for them changing the content size.
1158  if (shouldShowVerticalScroller)
1159  contentFrame.size.width -= verticalScrollerWidth;
1160 
1161  if (shouldShowHorizontalScroller)
1162  contentFrame.size.height -= horizontalScrollerHeight;
1163  overlay = 0;
1164  }
1165 
1166  var scrollPoint = [_contentView bounds].origin,
1167  wasShowingVerticalScroller = ![_verticalScroller isHidden],
1168  wasShowingHorizontalScroller = ![_horizontalScroller isHidden];
1169 
1170  if (shouldShowVerticalScroller)
1171  {
1172  var verticalScrollerY =
1173  MAX(CGRectGetMinY(contentFrame), MAX(CGRectGetMaxY([self _cornerViewFrame]), CGRectGetMaxY(headerClipViewFrame)));
1174 
1175  var verticalScrollerHeight = CGRectGetMaxY(contentFrame) - verticalScrollerY;
1176 
1177  // Make a gap at the bottom of the vertical scroller so that the horizontal and vertical can't overlap.
1178  if (_scrollerStyle === CPScrollerStyleOverlay && hasHorizontalScroll)
1179  verticalScrollerHeight -= horizontalScrollerHeight;
1180 
1181  var documentHeight = CGRectGetHeight(documentFrame);
1182  [_verticalScroller setFloatValue:(difference.height <= 0.0) ? 0.0 : scrollPoint.y / difference.height];
1183  [_verticalScroller setKnobProportion:documentHeight > 0 ? CGRectGetHeight(contentFrame) / documentHeight : 1.0];
1184  [_verticalScroller setFrame:CGRectMake(CGRectGetMaxX(contentFrame) - overlay, verticalScrollerY, verticalScrollerWidth, verticalScrollerHeight)];
1185  }
1186  else if (wasShowingVerticalScroller)
1187  {
1188  [_verticalScroller setFloatValue:0.0];
1189  [_verticalScroller setKnobProportion:1.0];
1190  }
1191 
1192  if (shouldShowHorizontalScroller)
1193  {
1194  var horizontalScrollerWidth = CGRectGetWidth(contentFrame);
1195  // Make a gap at the bottom of the vertical scroller so that the horizontal and vertical can't overlap.
1196  if (_scrollerStyle === CPScrollerStyleOverlay && hasVerticalScroll)
1197  horizontalScrollerWidth -= verticalScrollerWidth;
1198 
1199  var documentWidth = CGRectGetWidth(documentFrame);
1200 
1201  [_horizontalScroller setFloatValue:(difference.width <= 0.0) ? 0.0 : scrollPoint.x / difference.width];
1202  [_horizontalScroller setKnobProportion:documentWidth > 0 ? CGRectGetWidth(contentFrame) / documentWidth : 1.0];
1203  [_horizontalScroller setFrame:CGRectMake(CGRectGetMinX(contentFrame), CGRectGetMaxY(contentFrame) - overlay, horizontalScrollerWidth, horizontalScrollerHeight)];
1204  }
1205  else if (wasShowingHorizontalScroller)
1206  {
1207  [_horizontalScroller setFloatValue:0.0];
1208  [_horizontalScroller setKnobProportion:1.0];
1209  }
1210 
1211  [_contentView setFrame:contentFrame];
1212  [_headerClipView setFrame:[self _headerClipViewFrame]];
1213  [[_headerClipView documentView] setNeedsDisplay:YES];
1215  {
1216  [_cornerView setFrame:[self _cornerViewFrame]];
1217  [_cornerView setHidden:NO];
1218  }
1219  else
1220  [_cornerView setHidden:YES];
1221 
1222  if (_scrollerStyle === CPScrollerStyleLegacy)
1223  {
1224  [[self bottomCornerView] setFrame:[self _bottomCornerViewFrame]];
1225  [[self bottomCornerView] setBackgroundColor:[self currentValueForThemeAttribute:@"bottom-corner-color"]];
1226  }
1227 
1228  --_recursionCount;
1229 }
1230 
1234 - (void)flashScrollers
1235 {
1236  if (_scrollerStyle === CPScrollerStyleLegacy)
1237  return;
1238 
1239  if (_hasHorizontalScroller)
1240  {
1241  [_horizontalScroller setHidden:NO];
1242  [_horizontalScroller fadeIn];
1243  }
1244 
1245  if (_hasVerticalScroller)
1246  {
1247  [_verticalScroller setHidden:NO];
1248  [_verticalScroller fadeIn];
1249  }
1250 
1251  if (_timerScrollersHide)
1252  [_timerScrollersHide invalidate]
1253 
1254  _timerScrollersHide = [CPTimer scheduledTimerWithTimeInterval:CPScrollViewFadeOutTime target:self selector:@selector(_hideScrollers:) userInfo:nil repeats:NO];
1255 }
1256 
1257 /* @ignore */
1258 - (void)resizeSubviewsWithOldSize:(CGSize)aSize
1259 {
1260  [self reflectScrolledClipView:_contentView];
1261 }
1262 
1263 - (CGRect)documentVisibleRect
1264 {
1265  return [_contentView documentVisibleRect];
1266 }
1267 
1268 #pragma mark -
1269 #pragma mark Overrides
1270 
1271 
1272 - (void)_removeObservers
1273 {
1274  if (!_isObserving)
1275  return;
1276 
1278  name:CPScrollerStyleGlobalChangeNotification
1279  object:nil];
1280 
1281  [super _removeObservers];
1282 }
1283 
1284 - (void)_addObservers
1285 {
1286  if (_isObserving)
1287  return;
1288 
1289  //Make sure to have the last global style for the scroller
1290  [self _didReceiveDefaultStyleChange:nil];
1291 
1294  name:CPScrollerStyleGlobalChangeNotification
1295  object:nil];
1296 
1297  [super _addObservers];
1298 }
1299 
1300 
1301 
1302 - (void)drawRect:(CGRect)aRect
1303 {
1304  [super drawRect:aRect];
1305 
1306  if (_borderType == CPNoBorder)
1307  return;
1308 
1309  var strokeRect = [self bounds],
1311 
1312  CGContextSetLineWidth(context, 1);
1313 
1314  switch (_borderType)
1315  {
1316  case CPLineBorder:
1317  CGContextSetStrokeColor(context, [self currentValueForThemeAttribute:@"border-color"]);
1318  CGContextStrokeRect(context, CGRectInset(strokeRect, 0.5, 0.5));
1319  break;
1320 
1321  case CPBezelBorder:
1322  [self _drawGrayBezelInContext:context bounds:strokeRect];
1323  break;
1324 
1325  case CPGrooveBorder:
1326  [self _drawGrooveInContext:context bounds:strokeRect];
1327  break;
1328 
1329  default:
1330  break;
1331  }
1332 }
1333 
1334 - (void)_drawGrayBezelInContext:(CGContext)context bounds:(CGRect)aRect
1335 {
1336  var minX = CGRectGetMinX(aRect),
1337  maxX = CGRectGetMaxX(aRect),
1338  minY = CGRectGetMinY(aRect),
1339  maxY = CGRectGetMaxY(aRect),
1340  y = minY + 0.5;
1341 
1342  // Slightly darker line on top.
1343  CGContextSetStrokeColor(context, [CPColor colorWithWhite:142.0 / 255.0 alpha:1.0]);
1344  CGContextBeginPath(context);
1345  CGContextMoveToPoint(context, minX, y);
1346  CGContextAddLineToPoint(context, maxX, y);
1347  CGContextStrokePath(context);
1348 
1349  // The rest of the border.
1350  CGContextSetStrokeColor(context, [CPColor colorWithWhite:192.0 / 255.0 alpha:1.0]);
1351 
1352  var x = maxX - 0.5;
1353 
1354  CGContextBeginPath(context);
1355  CGContextMoveToPoint(context, x, minY + 1.0);
1356  CGContextAddLineToPoint(context, x, maxY);
1357  CGContextMoveToPoint(context, x - 0.5, maxY - 0.5);
1358  CGContextAddLineToPoint(context, minX, maxY - 0.5);
1359 
1360  x = minX + 0.5;
1361 
1362  CGContextMoveToPoint(context, x, maxY);
1363  CGContextAddLineToPoint(context, x, minY + 1.0);
1364 
1365  CGContextStrokePath(context);
1366 }
1367 
1368 - (void)_drawGrooveInContext:(CGContext)context bounds:(CGRect)aRect
1369 {
1370  var minX = CGRectGetMinX(aRect),
1371  maxX = CGRectGetMaxX(aRect),
1372  minY = CGRectGetMinY(aRect),
1373  maxY = CGRectGetMaxY(aRect);
1374 
1375  CGContextBeginPath(context);
1376  CGContextSetStrokeColor(context, [CPColor colorWithWhite:159.0 / 255.0 alpha:1.0]);
1377 
1378  var y = minY + 0.5;
1379 
1380  CGContextMoveToPoint(context, minX, y);
1381  CGContextAddLineToPoint(context, maxX, y);
1382 
1383  var x = maxX - 1.5;
1384 
1385  CGContextMoveToPoint(context, x, minY + 2.0);
1386  CGContextAddLineToPoint(context, x, maxY - 1.0);
1387 
1388  y = maxY - 1.5;
1389 
1390  CGContextMoveToPoint(context, maxX - 1.0, y);
1391  CGContextAddLineToPoint(context, minX + 2.0, y);
1392 
1393  x = minX + 0.5;
1394 
1395  CGContextMoveToPoint(context, x, maxY);
1396  CGContextAddLineToPoint(context, x, minY);
1397 
1398  CGContextStrokePath(context);
1399 
1400  CGContextBeginPath(context);
1401  CGContextSetStrokeColor(context, [CPColor whiteColor]);
1402 
1403  var rect = CGRectOffset(aRect, 1.0, 1.0);
1404 
1405  rect.size.width -= 1.0;
1406  rect.size.height -= 1.0;
1407  CGContextStrokeRect(context, CGRectInset(rect, 0.5, 0.5));
1408 
1409  CGContextBeginPath(context);
1410  CGContextSetStrokeColor(context, [CPColor colorWithWhite:192.0 / 255.0 alpha:1.0]);
1411 
1412  y = minY + 2.5;
1413 
1414  CGContextMoveToPoint(context, minX + 2.0, y);
1415  CGContextAddLineToPoint(context, maxX - 2.0, y);
1416  CGContextStrokePath(context);
1417 }
1418 
1424 - (void)scrollWheel:(CPEvent)anEvent
1425 {
1426  if (_timerScrollersHide)
1427  [_timerScrollersHide invalidate];
1428  if (![_verticalScroller isHidden])
1429  [_verticalScroller fadeIn];
1430  if (![_horizontalScroller isHidden])
1431  [_horizontalScroller fadeIn];
1432  if (![_horizontalScroller isHidden] || ![_verticalScroller isHidden])
1433  _timerScrollersHide = [CPTimer scheduledTimerWithTimeInterval:CPScrollViewFadeOutTime target:self selector:@selector(_hideScrollers:) userInfo:nil repeats:NO];
1434 
1435  var deltaX = [anEvent scrollingDeltaX],
1436  deltaY = [anEvent scrollingDeltaY];
1437 
1438  if (![anEvent hasPreciseScrollingDeltas])
1439  {
1440  deltaX *= (_horizontalLineScroll || 1.0);
1441  deltaY *= (_verticalLineScroll || 1.0);
1442  }
1443 
1444  [self _respondToScrollWheelEventWithDeltaX:deltaX deltaY:deltaY];
1445 }
1446 
1447 - (void)scrollPageUp:(id)sender
1448 {
1449  var contentBounds = [_contentView bounds];
1450  [self moveByOffset:CGSizeMake(0.0, -(CGRectGetHeight(contentBounds) - _verticalPageScroll))];
1451 }
1452 
1453 - (void)scrollPageDown:(id)sender
1454 {
1455  var contentBounds = [_contentView bounds];
1456  [self moveByOffset:CGSizeMake(0.0, CGRectGetHeight(contentBounds) - _verticalPageScroll)];
1457 }
1458 
1459 - (void)scrollToBeginningOfDocument:(id)sender
1460 {
1461  [_contentView scrollToPoint:CGPointMakeZero()];
1462  [_headerClipView scrollToPoint:CGPointMakeZero()];
1463 }
1464 
1465 - (void)scrollToEndOfDocument:(id)sender
1466 {
1467  var contentBounds = [_contentView bounds],
1468  documentFrame = [[self documentView] frame],
1469  scrollPoint = CGPointMake(0.0, CGRectGetHeight(documentFrame) - CGRectGetHeight(contentBounds));
1470 
1471  [_contentView scrollToPoint:scrollPoint];
1472  [_headerClipView scrollToPoint:CGPointMakeZero()];
1473 }
1474 
1475 - (void)moveLeft:(id)sender
1476 {
1477  [self moveByOffset:CGSizeMake(-_horizontalLineScroll, 0.0)];
1478 }
1479 
1480 - (void)moveRight:(id)sender
1481 {
1482  [self moveByOffset:CGSizeMake(_horizontalLineScroll, 0.0)];
1483 }
1484 
1485 - (void)moveUp:(id)sender
1486 {
1487  [self moveByOffset:CGSizeMake(0.0, -_verticalLineScroll)];
1488 }
1489 
1490 - (void)moveDown:(id)sender
1491 {
1492  [self moveByOffset:CGSizeMake(0.0, _verticalLineScroll)];
1493 }
1494 
1495 - (void)moveByOffset:(CGSize)aSize
1496 {
1497  var documentFrame = [[self documentView] frame],
1498  contentBounds = [_contentView bounds];
1499 
1500  contentBounds.origin.x += aSize.width;
1501  contentBounds.origin.y += aSize.height;
1502 
1503  [_contentView scrollToPoint:contentBounds.origin];
1504  [_headerClipView scrollToPoint:CGPointMake(contentBounds.origin.x, 0)];
1505 }
1506 
1507 @end
1508 
1509 
1510 var CPScrollViewContentViewKey = @"CPScrollViewContentView",
1511  CPScrollViewHeaderClipViewKey = @"CPScrollViewHeaderClipViewKey",
1512  CPScrollViewVLineScrollKey = @"CPScrollViewVLineScroll",
1513  CPScrollViewHLineScrollKey = @"CPScrollViewHLineScroll",
1514  CPScrollViewVPageScrollKey = @"CPScrollViewVPageScroll",
1515  CPScrollViewHPageScrollKey = @"CPScrollViewHPageScroll",
1516  CPScrollViewHasVScrollerKey = @"CPScrollViewHasVScroller",
1517  CPScrollViewHasHScrollerKey = @"CPScrollViewHasHScroller",
1518  CPScrollViewVScrollerKey = @"CPScrollViewVScroller",
1519  CPScrollViewHScrollerKey = @"CPScrollViewHScroller",
1520  CPScrollViewAutohidesScrollerKey = @"CPScrollViewAutohidesScroller",
1521  CPScrollViewCornerViewKey = @"CPScrollViewCornerViewKey",
1522  CPScrollViewBottomCornerViewKey = @"CPScrollViewBottomCornerViewKey",
1523  CPScrollViewBorderTypeKey = @"CPScrollViewBorderTypeKey",
1524  CPScrollViewScrollerStyleKey = @"CPScrollViewScrollerStyleKey",
1525  CPScrollViewScrollerKnobStyleKey = @"CPScrollViewScrollerKnobStyleKey";
1526 
1528 
1529 - (id)initWithCoder:(CPCoder)aCoder
1530 {
1531  if (self = [super initWithCoder:aCoder])
1532  {
1533  _verticalLineScroll = [aCoder decodeFloatForKey:CPScrollViewVLineScrollKey];
1534  _verticalPageScroll = [aCoder decodeFloatForKey:CPScrollViewVPageScrollKey];
1535 
1536  _horizontalLineScroll = [aCoder decodeFloatForKey:CPScrollViewHLineScrollKey];
1537  _horizontalPageScroll = [aCoder decodeFloatForKey:CPScrollViewHPageScrollKey];
1538 
1539  _contentView = [aCoder decodeObjectForKey:CPScrollViewContentViewKey];
1540  _headerClipView = [aCoder decodeObjectForKey:CPScrollViewHeaderClipViewKey];
1541 
1542  if (!_headerClipView)
1543  {
1544  _headerClipView = [[CPClipView alloc] init];
1545  [self addSubview:_headerClipView];
1546  }
1547 
1548  _verticalScroller = [aCoder decodeObjectForKey:CPScrollViewVScrollerKey];
1549  _horizontalScroller = [aCoder decodeObjectForKey:CPScrollViewHScrollerKey];
1550 
1551  _hasVerticalScroller = [aCoder decodeBoolForKey:CPScrollViewHasVScrollerKey];
1552  _hasHorizontalScroller = [aCoder decodeBoolForKey:CPScrollViewHasHScrollerKey];
1553  _autohidesScrollers = [aCoder decodeBoolForKey:CPScrollViewAutohidesScrollerKey];
1554 
1555  _borderType = [aCoder decodeIntForKey:CPScrollViewBorderTypeKey];
1556 
1557  _cornerView = [aCoder decodeObjectForKey:CPScrollViewCornerViewKey];
1558  _bottomCornerView = [aCoder decodeObjectForKey:CPScrollViewBottomCornerViewKey];
1559 
1560  _delegate = nil;
1561  _scrollTimer = nil;
1562  _implementedDelegateMethods = 0;
1563 
1564  _scrollerStyle = [aCoder decodeObjectForKey:CPScrollViewScrollerStyleKey] || CPScrollerStyleGlobal;
1565  _scrollerKnobStyle = [aCoder decodeObjectForKey:CPScrollViewScrollerKnobStyleKey] || CPScrollerKnobStyleDefault;
1566 
1569  name:CPScrollerStyleGlobalChangeNotification
1570  object:nil];
1571  }
1572 
1573  return self;
1574 }
1575 
1579 - (void)awakeFromCib
1580 {
1581  [self _updateScrollerStyle];
1582  [self _updateCornerAndHeaderView];
1583 }
1584 
1585 - (void)encodeWithCoder:(CPCoder)aCoder
1586 {
1587  [super encodeWithCoder:aCoder];
1588 
1589  [aCoder encodeObject:_contentView forKey:CPScrollViewContentViewKey];
1590  [aCoder encodeObject:_headerClipView forKey:CPScrollViewHeaderClipViewKey];
1591 
1592  [aCoder encodeObject:_verticalScroller forKey:CPScrollViewVScrollerKey];
1593  [aCoder encodeObject:_horizontalScroller forKey:CPScrollViewHScrollerKey];
1594 
1595  [aCoder encodeFloat:_verticalLineScroll forKey:CPScrollViewVLineScrollKey];
1596  [aCoder encodeFloat:_verticalPageScroll forKey:CPScrollViewVPageScrollKey];
1597  [aCoder encodeFloat:_horizontalLineScroll forKey:CPScrollViewHLineScrollKey];
1598  [aCoder encodeFloat:_horizontalPageScroll forKey:CPScrollViewHPageScrollKey];
1599 
1600  [aCoder encodeBool:_hasVerticalScroller forKey:CPScrollViewHasVScrollerKey];
1601  [aCoder encodeBool:_hasHorizontalScroller forKey:CPScrollViewHasHScrollerKey];
1602  [aCoder encodeBool:_autohidesScrollers forKey:CPScrollViewAutohidesScrollerKey];
1603 
1604  [aCoder encodeObject:_cornerView forKey:CPScrollViewCornerViewKey];
1605  [aCoder encodeObject:_bottomCornerView forKey:CPScrollViewBottomCornerViewKey];
1606 
1607  [aCoder encodeInt:_borderType forKey:CPScrollViewBorderTypeKey];
1608 
1609  [aCoder encodeInt:_scrollerStyle forKey:CPScrollViewScrollerStyleKey];
1610  [aCoder encodeInt:_scrollerKnobStyle forKey:CPScrollViewScrollerKnobStyleKey];
1611 }
1612 
1613 @end