![]() |
API 0.9.5
|
00001 /* 00002 * CPClipView.j 00003 * AppKit 00004 * 00005 * Created by Francisco Tolmasky. 00006 * Copyright 2008, 280 North, Inc. 00007 * 00008 * This library is free software; you can redistribute it and/or 00009 * modify it under the terms of the GNU Lesser General Public 00010 * License as published by the Free Software Foundation; either 00011 * version 2.1 of the License, or (at your option) any later version. 00012 * 00013 * This library is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 * Lesser General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License along with this library; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 */ 00022 00023 00024 00032 @implementation CPClipView : CPView 00033 { 00034 CPView _documentView; 00035 } 00036 00041 - (void)setDocumentView:(CPView)aView 00042 { 00043 if (_documentView == aView) 00044 return; 00045 00046 var defaultCenter = [CPNotificationCenter defaultCenter]; 00047 00048 if (_documentView) 00049 { 00050 [defaultCenter 00051 removeObserver:self 00052 name:CPViewFrameDidChangeNotification 00053 object:_documentView]; 00054 00055 [defaultCenter 00056 removeObserver:self 00057 name:CPViewBoundsDidChangeNotification 00058 object:_documentView]; 00059 00060 [_documentView removeFromSuperview]; 00061 } 00062 00063 _documentView = aView; 00064 00065 if (_documentView) 00066 { 00067 [self addSubview:_documentView]; 00068 00069 [_documentView setPostsFrameChangedNotifications:YES]; 00070 [_documentView setPostsBoundsChangedNotifications:YES]; 00071 00072 [defaultCenter 00073 addObserver:self 00074 selector:@selector(viewFrameChanged:) 00075 name:CPViewFrameDidChangeNotification 00076 object:_documentView]; 00077 00078 [defaultCenter 00079 addObserver:self 00080 selector:@selector(viewBoundsChanged:) 00081 name:CPViewBoundsDidChangeNotification 00082 object:_documentView]; 00083 } 00084 } 00085 00089 - (id)documentView 00090 { 00091 return _documentView; 00092 } 00093 00100 - (CGPoint)constrainScrollPoint:(CGPoint)aPoint 00101 { 00102 if (!_documentView) 00103 return _CGPointMakeZero(); 00104 00105 var documentFrame = [_documentView frame]; 00106 00107 aPoint.x = MAX(0.0, MIN(aPoint.x, MAX(_CGRectGetWidth(documentFrame) - _CGRectGetWidth(_bounds), 0.0))); 00108 aPoint.y = MAX(0.0, MIN(aPoint.y, MAX(_CGRectGetHeight(documentFrame) - _CGRectGetHeight(_bounds), 0.0))); 00109 00110 return aPoint; 00111 } 00112 00113 - (void)setBoundsOrigin:(CGPoint)aPoint 00114 { 00115 if (_CGPointEqualToPoint(_bounds.origin, aPoint)) 00116 return; 00117 00118 [super setBoundsOrigin:aPoint]; 00119 00120 var superview = [self superview], 00121 00122 // This is hack to avoid having to import CPScrollView. 00123 // FIXME: Should CPScrollView be finding out about this on its own somehow? 00124 scrollViewClass = objj_getClass("CPScrollView"); 00125 00126 if ([superview isKindOfClass:scrollViewClass]) 00127 [superview reflectScrolledClipView:self]; 00128 } 00129 00134 - (void)scrollToPoint:(CGPoint)aPoint 00135 { 00136 [self setBoundsOrigin:[self constrainScrollPoint:aPoint]]; 00137 } 00138 00143 - (void)viewBoundsChanged:(CPNotification)aNotification 00144 { 00145 [self _constrainScrollPoint]; 00146 } 00147 00152 - (void)viewFrameChanged:(CPNotification)aNotification 00153 { 00154 [self _constrainScrollPoint]; 00155 } 00156 00157 - (void)resizeSubviewsWithOldSize:(CGSize)aSize 00158 { 00159 [super resizeSubviewsWithOldSize:aSize]; 00160 [self _constrainScrollPoint]; 00161 } 00162 00163 - (void)_constrainScrollPoint 00164 { 00165 var oldScrollPoint = [self bounds].origin; 00166 00167 // Call scrollToPoint: because the current scroll point may no longer make 00168 // sense given the new frame of the document view. 00169 [self scrollToPoint:oldScrollPoint]; 00170 00171 // scrollToPoint: takes care of reflectScrollClipView: for us, so bail if 00172 // the scroll points are not equal (meaning scrollToPoint: didn't early bail). 00173 if (!CGPointEqualToPoint(oldScrollPoint, [self bounds].origin)) 00174 return; 00175 00176 // ... and we're in a scroll view of course. 00177 var superview = [self superview], 00178 00179 // This is hack to avoid having to import CPScrollView. 00180 // FIXME: Should CPScrollView be finding out about this on its own somehow? 00181 scrollViewClass = objj_getClass("CPScrollView"); 00182 00183 if ([superview isKindOfClass:scrollViewClass]) 00184 [superview reflectScrolledClipView:self]; 00185 } 00186 00187 - (BOOL)autoscroll:(CPEvent)anEvent 00188 { 00189 var bounds = [self bounds], 00190 eventLocation = [self convertPoint:[anEvent locationInWindow] fromView:nil], 00191 superview = [self superview], 00192 deltaX = 0, 00193 deltaY = 0; 00194 00195 if (CGRectContainsPoint(bounds, eventLocation)) 00196 return NO; 00197 00198 if (![superview isKindOfClass:[CPScrollView class]] || [superview hasVerticalScroller]) 00199 { 00200 if (eventLocation.y < CGRectGetMinY(bounds)) 00201 deltaY = CGRectGetMinY(bounds) - eventLocation.y; 00202 else if (eventLocation.y > CGRectGetMaxY(bounds)) 00203 deltaY = CGRectGetMaxY(bounds) - eventLocation.y; 00204 if (deltaY < -bounds.size.height) 00205 deltaY = -bounds.size.height; 00206 if (deltaY > bounds.size.height) 00207 deltaY = bounds.size.height; 00208 } 00209 00210 if (![superview isKindOfClass:[CPScrollView class]] || [superview hasHorizontalScroller]) 00211 { 00212 if (eventLocation.x < CGRectGetMinX(bounds)) 00213 deltaX = CGRectGetMinX(bounds) - eventLocation.x; 00214 else if (eventLocation.x > CGRectGetMaxX(bounds)) 00215 deltaX = CGRectGetMaxX(bounds) - eventLocation.x; 00216 if (deltaX < -bounds.size.width) 00217 deltaX = -bounds.size.width; 00218 if (deltaX > bounds.size.width) 00219 deltaX = bounds.size.width; 00220 } 00221 00222 return [self scrollToPoint:CGPointMake(bounds.origin.x - deltaX, bounds.origin.y - deltaY)]; 00223 } 00224 00225 @end 00226 00227 00228 var CPClipViewDocumentViewKey = @"CPScrollViewDocumentView"; 00229 00230 @implementation CPClipView (CPCoding) 00231 00232 - (id)initWithCoder:(CPCoder)aCoder 00233 { 00234 if (self = [super initWithCoder:aCoder]) 00235 [self setDocumentView:[aCoder decodeObjectForKey:CPClipViewDocumentViewKey]]; 00236 00237 return self; 00238 } 00239 00240 - (void)encodeWithCoder:(CPCoder)aCoder 00241 { 00242 [super encodeWithCoder:aCoder]; 00243 00244 [aCoder encodeObject:_documentView forKey:CPClipViewDocumentViewKey]; 00245 } 00246 00247 @end