API  1.0.0
CPClipView.j
Go to the documentation of this file.
1 /*
2  * CPClipView.j
3  * AppKit
4  *
5  * Created by Francisco Tolmasky.
6  * Copyright 2008, 280 North, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21  */
22 
23 
24 
31 @implementation CPClipView : CPView
32 {
33  CPView _documentView;
34 }
35 
40 - (void)setDocumentView:(CPView)aView
41 {
42  if (_documentView == aView)
43  return;
44 
45  if (_documentView)
46  [_documentView removeFromSuperview];
47 
48  _documentView = aView;
49 
50  if (_documentView)
51  [self addSubview:_documentView];
52 }
53 
57 - (id)documentView
58 {
59  return _documentView;
60 }
61 
68 - (CGPoint)constrainScrollPoint:(CGPoint)aPoint
69 {
70  if (!_documentView)
71  return CGPointMakeZero();
72 
73  var documentFrame = [_documentView frame];
74 
75  aPoint.x = MAX(0.0, MIN(aPoint.x, MAX(CGRectGetWidth(documentFrame) - CGRectGetWidth(_bounds), 0.0)));
76  aPoint.y = MAX(0.0, MIN(aPoint.y, MAX(CGRectGetHeight(documentFrame) - CGRectGetHeight(_bounds), 0.0)));
77 
78  return aPoint;
79 }
80 
81 - (void)setBoundsOrigin:(CGPoint)aPoint
82 {
83  if (CGPointEqualToPoint(_bounds.origin, aPoint))
84  return;
85 
86  [super setBoundsOrigin:aPoint];
87 
88  var superview = [self superview],
89 
90  // This is hack to avoid having to import CPScrollView.
91  // FIXME: Should CPScrollView be finding out about this on its own somehow?
92  scrollViewClass = objj_getClass("CPScrollView");
93 
94  if ([superview isKindOfClass:scrollViewClass])
96 }
97 
102 - (void)scrollToPoint:(CGPoint)aPoint
103 {
104  [self setBoundsOrigin:[self constrainScrollPoint:aPoint]];
105 }
106 
111 - (void)viewBoundsChanged:(CPNotification)aNotification
112 {
113  [self _constrainScrollPoint];
114 }
115 
120 - (void)viewFrameChanged:(CPNotification)aNotification
121 {
122  [self _constrainScrollPoint];
123 }
124 
125 - (void)resizeSubviewsWithOldSize:(CGSize)aSize
126 {
127  [super resizeSubviewsWithOldSize:aSize];
128  [self _constrainScrollPoint];
129 }
130 
131 - (void)_constrainScrollPoint
132 {
133  var oldScrollPoint = [self bounds].origin;
134 
135  // Call scrollToPoint: because the current scroll point may no longer make
136  // sense given the new frame of the document view.
137  [self scrollToPoint:oldScrollPoint];
138 
139  // scrollToPoint: takes care of reflectScrollClipView: for us, so bail if
140  // the scroll points are not equal (meaning scrollToPoint: didn't early bail).
141  if (!CGPointEqualToPoint(oldScrollPoint, [self bounds].origin))
142  return;
143 
144  // ... and we're in a scroll view of course.
145  var superview = [self superview],
146 
147  // This is hack to avoid having to import CPScrollView.
148  // FIXME: Should CPScrollView be finding out about this on its own somehow?
149  scrollViewClass = objj_getClass("CPScrollView");
150 
151  if ([superview isKindOfClass:scrollViewClass])
152  [superview reflectScrolledClipView:self];
153 }
154 
155 - (BOOL)autoscroll:(CPEvent)anEvent
156 {
157  var bounds = [self bounds],
158  eventLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil],
159  superview = [self superview],
160  deltaX = 0,
161  deltaY = 0;
162 
163  if (CGRectContainsPoint(bounds, eventLocation))
164  return NO;
165 
166  if (![superview isKindOfClass:[CPScrollView class]] || [superview hasVerticalScroller])
167  {
168  if (eventLocation.y < CGRectGetMinY(bounds))
169  deltaY = CGRectGetMinY(bounds) - eventLocation.y;
170  else if (eventLocation.y > CGRectGetMaxY(bounds))
171  deltaY = CGRectGetMaxY(bounds) - eventLocation.y;
172  if (deltaY < -bounds.size.height)
173  deltaY = -bounds.size.height;
174  if (deltaY > bounds.size.height)
175  deltaY = bounds.size.height;
176  }
177 
178  if (![superview isKindOfClass:[CPScrollView class]] || [superview hasHorizontalScroller])
179  {
180  if (eventLocation.x < CGRectGetMinX(bounds))
181  deltaX = CGRectGetMinX(bounds) - eventLocation.x;
182  else if (eventLocation.x > CGRectGetMaxX(bounds))
183  deltaX = CGRectGetMaxX(bounds) - eventLocation.x;
184  if (deltaX < -bounds.size.width)
185  deltaX = -bounds.size.width;
186  if (deltaX > bounds.size.width)
187  deltaX = bounds.size.width;
188  }
189 
190  return [self scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)];
191 }
192 
193 - (CGRect)documentVisibleRect
194 {
195  return [_documentView visibleRect];
196 }
197 
198 @end
199 
200 
201 var CPClipViewDocumentViewKey = @"CPScrollViewDocumentView";
202 
203 @implementation CPClipView (CPCoding)
204 
205 - (id)initWithCoder:(CPCoder)aCoder
206 {
207  if (self = [super initWithCoder:aCoder])
208  {
209  // Don't call setDocumentView: here. It calls addSubview:, but it's A) not necessary since the
210  // view hierarchy is fully encoded and B) dangerous if the subview is not fully decoded.
211  _documentView = [aCoder decodeObjectForKey:CPClipViewDocumentViewKey];
212  }
213 
214  return self;
215 }
216 
217 - (void)encodeWithCoder:(CPCoder)aCoder
218 {
219  [super encodeWithCoder:aCoder];
220 
221  [aCoder encodeObject:_documentView forKey:CPClipViewDocumentViewKey];
222 }
223 
224 @end
void addSubview:(CPView aSubview)
Definition: CPView.j:536
void scrollToPoint:(CGPoint aPoint)
Definition: CPClipView.j:102
CGPoint locationInWindow()
Definition: CPEvent.j:290
CGRect bounds()
Definition: CPView.j:1326
void setBoundsOrigin:(CGPoint aPoint)
Definition: CPView.j:1347
CGRect bounds()
Definition: CALayer.j:203
CGPoint convertPoint:fromView:(CGPoint aPoint, [fromView] CPView aView)
Definition: CPView.j:2249
void encodeWithCoder:(CPCoder aCoder)
Definition: CPView.j:3806
A notification that can be posted to a CPNotificationCenter.
Definition: CPNotification.h:2
void setBoundsOrigin:(CGPoint aPoint)
Definition: CPClipView.j:81
Defines methods for use when archiving & restoring (enc/decoding).
Definition: CPCoder.h:2
var CPClipViewDocumentViewKey
Definition: CPClipView.j:201
Definition: CPEvent.h:2
CPView superview()
Definition: CPView.j:510
CGPoint constrainScrollPoint:(CGPoint aPoint)
Definition: CPClipView.j:68
void resizeSubviewsWithOldSize:(CGSize aSize)
Definition: CPView.j:1478
Definition: CPView.j:137
void reflectScrolledClipView:(CPClipView aClipView)
Definition: CPView.j:2995