API  0.9.6
 All Classes Files Functions Variables Macros Groups Pages
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 
32 @implementation CPClipView : CPView
33 {
34  CPView _documentView;
35 }
36 
41 - (void)setDocumentView:(CPView)aView
42 {
43  if (_documentView == aView)
44  return;
45 
46  var defaultCenter = [CPNotificationCenter defaultCenter];
47 
48  if (_documentView)
49  {
50  [defaultCenter
51  removeObserver:self
52  name:CPViewFrameDidChangeNotification
53  object:_documentView];
54 
55  [defaultCenter
56  removeObserver:self
57  name:CPViewBoundsDidChangeNotification
58  object:_documentView];
59 
60  [_documentView removeFromSuperview];
61  }
62 
63  _documentView = aView;
64 
65  if (_documentView)
66  {
67  [self addSubview:_documentView];
68 
69  [_documentView setPostsFrameChangedNotifications:YES];
70  [_documentView setPostsBoundsChangedNotifications:YES];
71 
72  [defaultCenter
73  addObserver:self
74  selector:@selector(viewFrameChanged:)
75  name:CPViewFrameDidChangeNotification
76  object:_documentView];
77 
78  [defaultCenter
79  addObserver:self
80  selector:@selector(viewBoundsChanged:)
81  name:CPViewBoundsDidChangeNotification
82  object:_documentView];
83  }
84 }
85 
89 - (id)documentView
90 {
91  return _documentView;
92 }
93 
100 - (CGPoint)constrainScrollPoint:(CGPoint)aPoint
101 {
102  if (!_documentView)
103  return _CGPointMakeZero();
104 
105  var documentFrame = [_documentView frame];
106 
107  aPoint.x = MAX(0.0, MIN(aPoint.x, MAX(_CGRectGetWidth(documentFrame) - _CGRectGetWidth(_bounds), 0.0)));
108  aPoint.y = MAX(0.0, MIN(aPoint.y, MAX(_CGRectGetHeight(documentFrame) - _CGRectGetHeight(_bounds), 0.0)));
109 
110  return aPoint;
111 }
112 
113 - (void)setBoundsOrigin:(CGPoint)aPoint
114 {
115  if (_CGPointEqualToPoint(_bounds.origin, aPoint))
116  return;
117 
118  [super setBoundsOrigin:aPoint];
119 
120  var superview = [self superview],
121 
122  // This is hack to avoid having to import CPScrollView.
123  // FIXME: Should CPScrollView be finding out about this on its own somehow?
124  scrollViewClass = objj_getClass("CPScrollView");
125 
126  if ([superview isKindOfClass:scrollViewClass])
128 }
129 
134 - (void)scrollToPoint:(CGPoint)aPoint
135 {
136  [self setBoundsOrigin:[self constrainScrollPoint:aPoint]];
137 }
138 
143 - (void)viewBoundsChanged:(CPNotification)aNotification
144 {
145  [self _constrainScrollPoint];
146 }
147 
152 - (void)viewFrameChanged:(CPNotification)aNotification
153 {
154  [self _constrainScrollPoint];
155 }
156 
157 - (void)resizeSubviewsWithOldSize:(CGSize)aSize
158 {
159  [super resizeSubviewsWithOldSize:aSize];
160  [self _constrainScrollPoint];
161 }
162 
163 - (void)_constrainScrollPoint
164 {
165  var oldScrollPoint = [self bounds].origin;
166 
167  // Call scrollToPoint: because the current scroll point may no longer make
168  // sense given the new frame of the document view.
169  [self scrollToPoint:oldScrollPoint];
170 
171  // scrollToPoint: takes care of reflectScrollClipView: for us, so bail if
172  // the scroll points are not equal (meaning scrollToPoint: didn't early bail).
173  if (!CGPointEqualToPoint(oldScrollPoint, [self bounds].origin))
174  return;
175 
176  // ... and we're in a scroll view of course.
177  var superview = [self superview],
178 
179  // This is hack to avoid having to import CPScrollView.
180  // FIXME: Should CPScrollView be finding out about this on its own somehow?
181  scrollViewClass = objj_getClass("CPScrollView");
182 
183  if ([superview isKindOfClass:scrollViewClass])
184  [superview reflectScrolledClipView:self];
185 }
186 
187 - (BOOL)autoscroll:(CPEvent)anEvent
188 {
189  var bounds = [self bounds],
190  eventLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil],
191  superview = [self superview],
192  deltaX = 0,
193  deltaY = 0;
194 
195  if (CGRectContainsPoint(bounds, eventLocation))
196  return NO;
197 
198  if (![superview isKindOfClass:[CPScrollView class]] || [superview hasVerticalScroller])
199  {
200  if (eventLocation.y < CGRectGetMinY(bounds))
201  deltaY = CGRectGetMinY(bounds) - eventLocation.y;
202  else if (eventLocation.y > CGRectGetMaxY(bounds))
203  deltaY = CGRectGetMaxY(bounds) - eventLocation.y;
204  if (deltaY < -bounds.size.height)
205  deltaY = -bounds.size.height;
206  if (deltaY > bounds.size.height)
207  deltaY = bounds.size.height;
208  }
209 
210  if (![superview isKindOfClass:[CPScrollView class]] || [superview hasHorizontalScroller])
211  {
212  if (eventLocation.x < CGRectGetMinX(bounds))
213  deltaX = CGRectGetMinX(bounds) - eventLocation.x;
214  else if (eventLocation.x > CGRectGetMaxX(bounds))
215  deltaX = CGRectGetMaxX(bounds) - eventLocation.x;
216  if (deltaX < -bounds.size.width)
217  deltaX = -bounds.size.width;
218  if (deltaX > bounds.size.width)
219  deltaX = bounds.size.width;
220  }
221 
222  return [self scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)];
223 }
224 
225 @end
226 
227 
228 var CPClipViewDocumentViewKey = @"CPScrollViewDocumentView";
229 
230 @implementation CPClipView (CPCoding)
231 
232 - (id)initWithCoder:(CPCoder)aCoder
233 {
234  if (self = [super initWithCoder:aCoder])
235  [self setDocumentView:[aCoder decodeObjectForKey:CPClipViewDocumentViewKey]];
236 
237  return self;
238 }
239 
240 - (void)encodeWithCoder:(CPCoder)aCoder
241 {
242  [super encodeWithCoder:aCoder];
243 
244  [aCoder encodeObject:_documentView forKey:CPClipViewDocumentViewKey];
245 }
246 
247 @end