API 0.9.5
AppKit/CPImage.j
Go to the documentation of this file.
00001 /*
00002  * CPImage.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 
00025 
00026 CPImageLoadStatusInitialized    = 0;
00027 CPImageLoadStatusLoading        = 1;
00028 CPImageLoadStatusCompleted      = 2;
00029 CPImageLoadStatusCancelled      = 3;
00030 CPImageLoadStatusInvalidData    = 4;
00031 CPImageLoadStatusUnexpectedEOF  = 5;
00032 CPImageLoadStatusReadError      = 6;
00033 
00034 CPImageDidLoadNotification      = @"CPImageDidLoadNotification";
00035 
00036 // Image Names
00037 CPImageNameColorPanel               = @"CPImageNameColorPanel";
00038 CPImageNameColorPanelHighlighted    = @"CPImageNameColorPanelHighlighted";
00039 
00040 var imagesForNames = { },
00041     AppKitImageForNames = { },
00042     ImageDescriptionFormat = "%s {\n   filename: \"%s\",\n   size: { width:%f, height:%f }\n}";
00043 
00044 AppKitImageForNames[CPImageNameColorPanel]              = CGSizeMake(26.0, 29.0);
00045 AppKitImageForNames[CPImageNameColorPanelHighlighted]   = CGSizeMake(26.0, 29.0);
00046 
00047 function CPImageInBundle(aFilename, aSize, aBundle)
00048 {
00049     if (!aBundle)
00050         aBundle = [CPBundle mainBundle];
00051 
00052     if (aSize)
00053         return [[CPImage alloc] initWithContentsOfFile:[aBundle pathForResource:aFilename] size:aSize];
00054 
00055     return [[CPImage alloc] initWithContentsOfFile:[aBundle pathForResource:aFilename]];
00056 }
00057 
00058 function CPAppKitImage(aFilename, aSize)
00059 {
00060     return CPImageInBundle(aFilename, aSize, [CPBundle bundleForClass:[CPView class]]);
00061 }
00062 
00084 @implementation CPImage : CPObject
00085 {
00086     CGSize      _size;
00087     CPString    _filename;
00088     CPString    _name;
00089 
00090     id          _delegate;
00091     unsigned    _loadStatus;
00092 
00093     Image       _image;
00094 }
00095 
00096 - (id)init
00097 {
00098     return [self initByReferencingFile:@"" size:CGSizeMake(-1, -1)];
00099 }
00100 
00109 - (id)initByReferencingFile:(CPString)aFilename size:(CGSize)aSize
00110 {
00111     self = [super init];
00112 
00113     if (self)
00114     {
00115         _size = CPSizeCreateCopy(aSize);
00116         _filename = aFilename;
00117         _loadStatus = CPImageLoadStatusInitialized;
00118     }
00119 
00120     return self;
00121 }
00122 
00129 - (id)initWithContentsOfFile:(CPString)aFilename size:(CGSize)aSize
00130 {
00131     self = [self initByReferencingFile:aFilename size:aSize];
00132 
00133     if (self)
00134         [self load];
00135 
00136     return self;
00137 }
00138 
00145 - (id)initWithContentsOfFile:(CPString)aFilename
00146 {
00147     self = [self initByReferencingFile:aFilename size:CGSizeMake(-1, -1)];
00148 
00149     if (self)
00150         [self load];
00151 
00152     return self;
00153 }
00154 
00158 - (CPString)filename
00159 {
00160     return _filename;
00161 }
00162 
00167 - (void)setSize:(CGSize)aSize
00168 {
00169     _size = CGSizeMakeCopy(aSize);
00170 }
00171 
00175 - (CGSize)size
00176 {
00177     return _size;
00178 }
00179 
00180 + (id)imageNamed:(CPString)aName
00181 {
00182     var image = imagesForNames[aName];
00183 
00184     if (image)
00185         return image;
00186 
00187     var imageOrSize = AppKitImageForNames[aName];
00188 
00189     if (!imageOrSize)
00190         return nil;
00191 
00192     if (!imageOrSize.isa)
00193     {
00194         imageOrSize = CPAppKitImage("CPImage/" + aName + ".png", imageOrSize);
00195 
00196         [imageOrSize setName:aName];
00197 
00198         AppKitImageForNames[aName] = imageOrSize;
00199     }
00200 
00201     return imageOrSize;
00202 }
00203 
00204 - (BOOL)setName:(CPString)aName
00205 {
00206     if (_name === aName)
00207         return YES;
00208 
00209     if (imagesForNames[aName])
00210         return NO;
00211 
00212     _name = aName;
00213 
00214     imagesForNames[aName] = self;
00215 
00216     return YES;
00217 }
00218 
00219 - (CPString)name
00220 {
00221     return _name;
00222 }
00223 
00228 - (void)setDelegate:(id)aDelegate
00229 {
00230     _delegate = aDelegate;
00231 }
00232 
00236 - (id)delegate
00237 {
00238     return _delegate;
00239 }
00240 
00244 - (unsigned)loadStatus
00245 {
00246     return _loadStatus;
00247 }
00248 
00255 - (void)load
00256 {
00257     if (_loadStatus == CPImageLoadStatusLoading || _loadStatus == CPImageLoadStatusCompleted)
00258         return;
00259 
00260     _loadStatus = CPImageLoadStatusLoading;
00261 
00262 #if PLATFORM(DOM)
00263     _image = new Image();
00264 
00265     var isSynchronous = YES;
00266 
00267     // FIXME: We need a better/performance way of doing this.
00268     _image.onload = function ()
00269         {
00270             if (isSynchronous)
00271                 window.setTimeout(function() { [self _imageDidLoad]; }, 0);
00272             else
00273             {
00274                 [self _imageDidLoad];
00275                 [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
00276             }
00277             [self _derefFromImage];
00278         }
00279 
00280     _image.onerror = function ()
00281         {
00282             if (isSynchronous)
00283                 window.setTimeout(function() { [self _imageDidError]; }, 0);
00284             else
00285             {
00286                 [self _imageDidError];
00287                 [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
00288             }
00289             [self _derefFromImage];
00290         }
00291 
00292     _image.onabort = function ()
00293         {
00294             if (isSynchronous)
00295                 window.setTimeout(function() { [self _imageDidAbort]; }, 0);
00296             else
00297             {
00298                 [self _imageDidAbort];
00299                 [[CPRunLoop currentRunLoop] limitDateForMode:CPDefaultRunLoopMode];
00300             }
00301             [self _derefFromImage];
00302         }
00303 
00304     _image.src = _filename;
00305 
00306     // onload and friends may fire after this point but BEFORE the end of the run loop,
00307     // crazy, I know. So don't set isSynchronous here, rather wait a bit longer.
00308     window.setTimeout(function() { isSynchronous = NO; }, 0);
00309 #endif
00310 }
00311 
00312 - (BOOL)isThreePartImage
00313 {
00314     return NO;
00315 }
00316 
00317 - (BOOL)isNinePartImage
00318 {
00319     return NO;
00320 }
00321 
00322 - (CPString)description
00323 {
00324     var filename = [self filename],
00325         size = [self size];
00326 
00327     if (filename.indexOf("data:") === 0)
00328     {
00329         var index = filename.indexOf(",");
00330 
00331         if (index > 0)
00332             filename = [CPString stringWithFormat:@"%s,%s...%s", filename.substr(0, index), filename.substr(index + 1, 10), filename.substr(filename.length - 10)];
00333         else
00334             filename = "data:<unknown type>";
00335     }
00336 
00337     return [CPString stringWithFormat:ImageDescriptionFormat, [super description], filename, size.width, size.height];
00338 }
00339 
00340 /* @ignore */
00341 - (void)_derefFromImage
00342 {
00343     _image.onload = null;
00344     _image.onerror = null;
00345     _image.onabort = null;
00346 }
00347 
00348 /* @ignore */
00349 - (void)_imageDidLoad
00350 {
00351     _loadStatus = CPImageLoadStatusCompleted;
00352 
00353     // FIXME: IE is wrong on image sizes????
00354     if (!_size || (_size.width == -1 && _size.height == -1))
00355         _size = CGSizeMake(_image.width, _image.height);
00356 
00357     [[CPNotificationCenter defaultCenter]
00358         postNotificationName:CPImageDidLoadNotification
00359         object:self];
00360 
00361     if ([_delegate respondsToSelector:@selector(imageDidLoad:)])
00362         [_delegate imageDidLoad:self];
00363 }
00364 
00365 /* @ignore */
00366 - (void)_imageDidError
00367 {
00368     _loadStatus = CPImageLoadStatusReadError;
00369 
00370     if ([_delegate respondsToSelector:@selector(imageDidError:)])
00371         [_delegate imageDidError:self];
00372 }
00373 
00374 /* @ignore */
00375 - (void)_imageDidAbort
00376 {
00377     _loadStatus = CPImageLoadStatusCancelled;
00378 
00379     if ([_delegate respondsToSelector:@selector(imageDidAbort:)])
00380         [_delegate imageDidAbort:self];
00381 }
00382 
00383 @end
00384 
00385 @implementation CPImage (CPCoding)
00386 
00392 - (id)initWithCoder:(CPCoder)aCoder
00393 {
00394     return [self initWithContentsOfFile:[aCoder decodeObjectForKey:@"CPFilename"] size:[aCoder decodeSizeForKey:@"CPSize"]];
00395 }
00396 
00401 - (void)encodeWithCoder:(CPCoder)aCoder
00402 {
00403     [aCoder encodeObject:_filename forKey:@"CPFilename"];
00404     [aCoder encodeSize:_size forKey:@"CPSize"];
00405 }
00406 
00407 @end
00408 
00409 @implementation CPThreePartImage : CPObject
00410 {
00411     CPArray _imageSlices;
00412     BOOL    _isVertical;
00413 }
00414 
00415 - (id)initWithImageSlices:(CPArray)imageSlices isVertical:(BOOL)isVertical
00416 {
00417     self = [super init];
00418 
00419     if (self)
00420     {
00421         _imageSlices = imageSlices;
00422         _isVertical = isVertical;
00423     }
00424 
00425     return self;
00426 }
00427 
00428 - (CPString)filename
00429 {
00430     return @"";
00431 }
00432 
00433 - (CPArray)imageSlices
00434 {
00435     return _imageSlices;
00436 }
00437 
00438 - (BOOL)isVertical
00439 {
00440     return _isVertical;
00441 }
00442 
00443 - (BOOL)isThreePartImage
00444 {
00445     return YES;
00446 }
00447 
00448 - (BOOL)isNinePartImage
00449 {
00450     return NO;
00451 }
00452 
00453 @end
00454 
00455 var CPThreePartImageImageSlicesKey  = @"CPThreePartImageImageSlicesKey",
00456     CPThreePartImageIsVerticalKey   = @"CPThreePartImageIsVerticalKey";
00457 
00458 @implementation CPThreePartImage (CPCoding)
00459 
00460 - (id)initWithCoder:(CPCoder)aCoder
00461 {
00462     self = [super init];
00463 
00464     if (self)
00465     {
00466         _imageSlices = [aCoder decodeObjectForKey:CPThreePartImageImageSlicesKey];
00467         _isVertical = [aCoder decodeBoolForKey:CPThreePartImageIsVerticalKey];
00468     }
00469 
00470     return self;
00471 }
00472 
00473 - (void)encodeWithCoder:(CPCoder)aCoder
00474 {
00475     [aCoder encodeObject:_imageSlices forKey:CPThreePartImageImageSlicesKey];
00476     [aCoder encodeBool:_isVertical forKey:CPThreePartImageIsVerticalKey];
00477 }
00478 
00479 @end
00480 
00481 
00482 @implementation CPNinePartImage : CPObject
00483 {
00484     CPArray _imageSlices;
00485 }
00486 
00487 - (id)initWithImageSlices:(CPArray)imageSlices
00488 {
00489     self = [super init];
00490 
00491     if (self)
00492         _imageSlices = imageSlices;
00493 
00494     return self;
00495 }
00496 
00497 - (CPString)filename
00498 {
00499     return @"";
00500 }
00501 
00502 - (CPArray)imageSlices
00503 {
00504     return _imageSlices;
00505 }
00506 
00507 - (BOOL)isThreePartImage
00508 {
00509     return NO;
00510 }
00511 
00512 - (BOOL)isNinePartImage
00513 {
00514     return YES;
00515 }
00516 
00517 @end
00518 
00519 var CPNinePartImageImageSlicesKey   = @"CPNinePartImageImageSlicesKey";
00520 
00521 @implementation CPNinePartImage (CPCoding)
00522 
00523 - (id)initWithCoder:(CPCoder)aCoder
00524 {
00525     self = [super init];
00526 
00527     if (self)
00528         _imageSlices = [aCoder decodeObjectForKey:CPNinePartImageImageSlicesKey];
00529 
00530     return self;
00531 }
00532 
00533 - (void)encodeWithCoder:(CPCoder)aCoder
00534 {
00535     [aCoder encodeObject:_imageSlices forKey:CPNinePartImageImageSlicesKey];
00536 }
00537 
00538 @end
 All Classes Files Functions Variables Defines