![]() |
API 0.9.5
|
00001 /* 00002 * CPBox.j 00003 * AppKit 00004 * 00005 * Created by Ross Boucher. 00006 * Copyright 2009, 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 // CPBoxType 00025 CPBoxPrimary = 0; 00026 CPBoxSecondary = 1; 00027 CPBoxSeparator = 2; 00028 CPBoxOldStyle = 3; 00029 CPBoxCustom = 4; 00030 00031 // CPBorderType 00032 CPNoBorder = 0; 00033 CPLineBorder = 1; 00034 CPBezelBorder = 2; 00035 CPGrooveBorder = 3; 00036 00043 @implementation CPBox : CPView 00044 { 00045 CPBoxType _boxType; 00046 CPBorderType _borderType; 00047 00048 CPColor _borderColor; 00049 CPColor _fillColor; 00050 00051 float _cornerRadius; 00052 float _borderWidth; 00053 00054 CPSize _contentMargin; 00055 CPView _contentView; 00056 } 00057 00058 + (id)boxEnclosingView:(CPView)aView 00059 { 00060 var box = [[self alloc] initWithFrame:CGRectMakeZero()], 00061 enclosingView = [aView superview]; 00062 00063 [box setAutoresizingMask:[aView autoresizingMask]]; 00064 [box setFrameFromContentFrame:[aView frame]]; 00065 00066 [enclosingView replaceSubview:aView with:box]; 00067 00068 [box setContentView:aView]; 00069 00070 return box; 00071 } 00072 00073 - (id)initWithFrame:(CPRect)frameRect 00074 { 00075 self = [super initWithFrame:frameRect]; 00076 00077 if (self) 00078 { 00079 _borderType = CPBezelBorder; 00080 _fillColor = [CPColor clearColor]; 00081 _borderColor = [CPColor blackColor]; 00082 00083 _borderWidth = 1.0; 00084 _contentMargin = CGSizeMake(0.0, 0.0); 00085 00086 _contentView = [[CPView alloc] initWithFrame:[self bounds]]; 00087 [_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; 00088 00089 [self setAutoresizesSubviews:YES]; 00090 [self addSubview:_contentView]; 00091 } 00092 00093 return self; 00094 } 00095 00096 // Configuring Boxes 00097 00103 - (CPRect)borderRect 00104 { 00105 return [self bounds]; 00106 } 00107 00120 - (CPBorderType)borderType 00121 { 00122 return _borderType; 00123 } 00124 00125 00138 - (void)setBorderType:(CPBorderType)aBorderType 00139 { 00140 if (_borderType === aBorderType) 00141 return; 00142 00143 _borderType = aBorderType; 00144 [self setNeedsDisplay:YES]; 00145 } 00146 00162 - (CPBoxType)boxType 00163 { 00164 return _boxType; 00165 } 00166 00182 - (void)setBoxType:(CPBoxType)aBoxType 00183 { 00184 if (_boxType === aBoxType) 00185 return; 00186 00187 _boxType = aBoxType; 00188 [self setNeedsDisplay:YES]; 00189 } 00190 00191 - (CPColor)borderColor 00192 { 00193 return _borderColor; 00194 } 00195 00196 - (void)setBorderColor:(CPColor)color 00197 { 00198 if ([color isEqual:_borderColor]) 00199 return; 00200 00201 _borderColor = color; 00202 [self setNeedsDisplay:YES]; 00203 } 00204 00205 - (float)borderWidth 00206 { 00207 return _borderWidth; 00208 } 00209 00210 - (void)setBorderWidth:(float)width 00211 { 00212 if (width === _borderWidth) 00213 return; 00214 00215 _borderWidth = width; 00216 [self setNeedsDisplay:YES]; 00217 } 00218 00219 - (float)cornerRadius 00220 { 00221 return _cornerRadius; 00222 } 00223 00224 - (void)setCornerRadius:(float)radius 00225 { 00226 if (radius === _cornerRadius) 00227 return; 00228 00229 _cornerRadius = radius; 00230 [self setNeedsDisplay:YES]; 00231 } 00232 00233 - (CPColor)fillColor 00234 { 00235 return _fillColor; 00236 } 00237 00238 - (void)setFillColor:(CPColor)color 00239 { 00240 if ([color isEqual:_fillColor]) 00241 return; 00242 00243 _fillColor = color; 00244 [self setNeedsDisplay:YES]; 00245 } 00246 00247 - (CPView)contentView 00248 { 00249 return _contentView; 00250 } 00251 00252 - (void)setContentView:(CPView)aView 00253 { 00254 if (aView === _contentView) 00255 return; 00256 00257 [aView setFrame:CGRectInset([self bounds], _contentMargin.width + _borderWidth, _contentMargin.height + _borderWidth)]; 00258 [aView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; 00259 [self replaceSubview:_contentView with:aView]; 00260 00261 _contentView = aView; 00262 } 00263 00264 - (CPSize)contentViewMargins 00265 { 00266 return _contentMargin; 00267 } 00268 00269 - (void)setContentViewMargins:(CPSize)size 00270 { 00271 if (size.width < 0 || size.height < 0) 00272 [CPException raise:CPGenericException reason:@"Margins must be positive"]; 00273 00274 _contentMargin = CGSizeMakeCopy(size); 00275 [self setNeedsDisplay:YES]; 00276 } 00277 00278 - (void)setFrameFromContentFrame:(CPRect)aRect 00279 { 00280 [self setFrame:CGRectInset(aRect, -(_contentMargin.width + _borderWidth), -(_contentMargin.height + _borderWidth))]; 00281 [self setNeedsDisplay:YES]; 00282 } 00283 00284 - (void)sizeToFit 00285 { 00286 var contentFrame = [_contentView frame]; 00287 00288 [self setFrameSize:CGSizeMake(contentFrame.size.width + _contentMargin.width * 2, 00289 contentFrame.size.height + _contentMargin.height * 2)]; 00290 00291 [_contentView setFrameOrigin:CGPointMake(_contentMargin.width, _contentMargin.height)]; 00292 } 00293 00294 - (void)drawRect:(CPRect)rect 00295 { 00296 if (_borderType === CPNoBorder) 00297 return; 00298 00299 var bounds = [self bounds]; 00300 00301 switch (_boxType) 00302 { 00303 case CPBoxSeparator: 00304 // NSBox does not include a horizontal flag for the separator type. We have to determine 00305 // the type of separator to draw by the width and height of the frame. 00306 if (CGRectGetWidth(bounds) === 5.0) 00307 return [self _drawVerticalSeperatorInRect:bounds]; 00308 else if (CGRectGetHeight(bounds) === 5.0) 00309 return [self _drawHorizontalSeperatorInRect:bounds]; 00310 00311 break; 00312 } 00313 00314 switch (_borderType) 00315 { 00316 case CPBezelBorder: 00317 [self _drawBezelBorderInRect:bounds]; 00318 break; 00319 00320 default: 00321 case CPLineBorder: 00322 [self _drawLineBorderInRect:bounds]; 00323 break; 00324 } 00325 } 00326 00327 - (void)_drawHorizontalSeperatorInRect:(CGRect)aRect 00328 { 00329 var context = [[CPGraphicsContext currentContext] graphicsPort]; 00330 00331 CGContextSetStrokeColor(context, [self borderColor]); 00332 CGContextSetLineWidth(context, 1.0); 00333 00334 CGContextMoveToPoint(context, CGRectGetMinX(aRect), CGRectGetMinY(aRect) + 0.5); 00335 CGContextAddLineToPoint(context, CGRectGetWidth(aRect), CGRectGetMinY(aRect) + 0.5); 00336 CGContextStrokePath(context); 00337 } 00338 00339 - (void)_drawVerticalSeperatorInRect:(CGRect)aRect 00340 { 00341 var context = [[CPGraphicsContext currentContext] graphicsPort]; 00342 00343 CGContextSetStrokeColor(context, [self borderColor]); 00344 CGContextSetLineWidth(context, 1.0); 00345 00346 CGContextMoveToPoint(context, CGRectGetMinX(aRect) + 0.5, CGRectGetMinY(aRect)); 00347 CGContextAddLineToPoint(context, CGRectGetMinX(aRect) + 0.5, CGRectGetHeight(aRect)); 00348 CGContextStrokePath(context); 00349 } 00350 00351 - (void)_drawBezelBorderInRect:(CGRect)aRect 00352 { 00353 var context = [[CPGraphicsContext currentContext] graphicsPort], 00354 sides = [CPMinYEdge, CPMaxXEdge, CPMaxYEdge, CPMinXEdge], 00355 sideGray = 190.0 / 255.0, 00356 grays = [142.0 / 255.0, sideGray, sideGray, sideGray], 00357 borderWidth = _borderWidth; 00358 00359 while (borderWidth--) 00360 aRect = CPDrawTiledRects(aRect, aRect, sides, grays); 00361 00362 CGContextSetFillColor(context, [self fillColor]); 00363 CGContextFillRect(context, aRect); 00364 } 00365 00366 - (void)_drawLineBorderInRect:(CGRect)aRect 00367 { 00368 var context = [[CPGraphicsContext currentContext] graphicsPort]; 00369 00370 aRect = CGRectInset(aRect, _borderWidth / 2.0, _borderWidth / 2.0); 00371 00372 CGContextSetFillColor(context, [self fillColor]); 00373 CGContextSetStrokeColor(context, [self borderColor]); 00374 00375 CGContextSetLineWidth(context, _borderWidth); 00376 CGContextFillRoundedRectangleInRect(context, aRect, _cornerRadius, YES, YES, YES, YES); 00377 CGContextStrokeRoundedRectangleInRect(context, aRect, _cornerRadius, YES, YES, YES, YES); 00378 } 00379 00380 @end 00381 00382 var CPBoxTypeKey = @"CPBoxTypeKey", 00383 CPBoxBorderTypeKey = @"CPBoxBorderTypeKey", 00384 CPBoxBorderColorKey = @"CPBoxBorderColorKey", 00385 CPBoxFillColorKey = @"CPBoxFillColorKey", 00386 CPBoxCornerRadiusKey = @"CPBoxCornerRadiusKey", 00387 CPBoxBorderWidthKey = @"CPBoxBorderWidthKey", 00388 CPBoxContentMarginKey = @"CPBoxContentMarginKey"; 00389 00390 @implementation CPBox (CPCoding) 00391 00392 - (id)initWithCoder:(CPCoder)aCoder 00393 { 00394 self = [super initWithCoder:aCoder]; 00395 00396 if (self) 00397 { 00398 _boxType = [aCoder decodeIntForKey:CPBoxTypeKey]; 00399 _borderType = [aCoder decodeIntForKey:CPBoxBorderTypeKey]; 00400 00401 _borderColor = [aCoder decodeObjectForKey:CPBoxBorderColorKey]; 00402 _fillColor = [aCoder decodeObjectForKey:CPBoxFillColorKey]; 00403 00404 _cornerRadius = [aCoder decodeFloatForKey:CPBoxCornerRadiusKey]; 00405 _borderWidth = [aCoder decodeFloatForKey:CPBoxBorderWidthKey]; 00406 00407 _contentMargin = [aCoder decodeSizeForKey:CPBoxContentMarginKey]; 00408 00409 _contentView = [self subviews][0]; 00410 00411 [self setAutoresizesSubviews:YES]; 00412 [_contentView setAutoresizingMask:CPViewWidthSizable | CPViewHeightSizable]; 00413 } 00414 00415 return self; 00416 } 00417 00418 - (void)encodeWithCoder:(CPCoder)aCoder 00419 { 00420 [super encodeWithCoder:aCoder]; 00421 00422 [aCoder encodeInt:_boxType forKey:CPBoxTypeKey]; 00423 [aCoder encodeInt:_borderType forKey:CPBoxBorderTypeKey]; 00424 00425 [aCoder encodeObject:_borderColor forKey:CPBoxBorderColorKey]; 00426 [aCoder encodeObject:_fillColor forKey:CPBoxFillColorKey]; 00427 00428 [aCoder encodeFloat:_cornerRadius forKey:CPBoxCornerRadiusKey]; 00429 [aCoder encodeFloat:_borderWidth forKey:CPBoxBorderWidthKey]; 00430 00431 [aCoder encodeSize:_contentMargin forKey:CPBoxContentMarginKey]; 00432 } 00433 00434 @end