00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 @import <Foundation/CPNotificationCenter.j>
00024
00025 @import "CPControl.j"
00026 @import "CPImage.j"
00027 @import "CPShadowView.j"
00028
00029 #include "Platform/Platform.h"
00030 #include "Platform/DOM/CPDOMDisplayServer.h"
00031
00032 #include "CoreGraphics/CGGeometry.h"
00033
00034
00035
00036
00037
00038
00039 CPScaleProportionally = 0;
00040
00041
00042
00043
00044 CPScaleToFit = 1;
00045
00046
00047
00048
00049 CPScaleNone = 2;
00050
00051
00052 var CPImageViewShadowBackgroundColor = nil;
00053
00054 var LEFT_SHADOW_INSET = 3.0,
00055 RIGHT_SHADOW_INSET = 3.0,
00056 TOP_SHADOW_INSET = 3.0,
00057 BOTTOM_SHADOW_INSET = 5.0,
00058 VERTICAL_SHADOW_INSET = TOP_SHADOW_INSET + BOTTOM_SHADOW_INSET,
00059 HORIZONTAL_SHADOW_INSET = LEFT_SHADOW_INSET + RIGHT_SHADOW_INSET;
00060
00067 @implementation CPImageView : CPControl
00068 {
00069 DOMElement _DOMImageElement;
00070
00071 BOOL _hasShadow;
00072 CPView _shadowView;
00073
00074 BOOL _isEditable;
00075
00076 CGRect _imageRect;
00077 }
00078
00079 - (id)initWithFrame:(CGRect)aFrame
00080 {
00081 self = [super initWithFrame:aFrame];
00082
00083 if (self)
00084 {
00085 #if PLATFORM(DOM)
00086 _DOMImageElement = document.createElement("img");
00087 _DOMImageElement.style.position = "absolute";
00088 _DOMImageElement.style.left = "0px";
00089 _DOMImageElement.style.top = "0px";
00090
00091 CPDOMDisplayServerAppendChild(_DOMElement, _DOMImageElement);
00092
00093 _DOMImageElement.style.visibility = "hidden";
00094 #endif
00095 }
00096
00097 return self;
00098 }
00099
00103 - (CPImage)image
00104 {
00105 return [self objectValue];
00106 }
00107
00108 - (void)setImage:(CPImage)anImage
00109 {
00110 [self setObjectValue:anImage];
00111 }
00112
00114 - (void)setObjectValue:(CPImage)anImage
00115 {
00116 var oldImage = [self objectValue];
00117
00118 if (oldImage === anImage)
00119 return;
00120
00121 [super setObjectValue:anImage];
00122
00123 var defaultCenter = [CPNotificationCenter defaultCenter];
00124
00125 if (oldImage)
00126 [defaultCenter removeObserver:self name:CPImageDidLoadNotification object:oldImage];
00127
00128 var newImage = [self objectValue];
00129
00130 #if PLATFORM(DOM)
00131 _DOMImageElement.src = newImage ? [newImage filename] : "";
00132 #endif
00133
00134 var size = [newImage size];
00135
00136 if (size && size.width === -1 && size.height === -1)
00137 {
00138 [defaultCenter addObserver:self selector:@selector(imageDidLoad:) name:CPImageDidLoadNotification object:newImage];
00139
00140 #if PLATFORM(DOM)
00141 _DOMImageElement.width = 0;
00142 _DOMImageElement.height = 0;
00143 #endif
00144
00145 [_shadowView setHidden:YES];
00146 }
00147 else
00148 {
00149 [self hideOrDisplayContents];
00150 [self setNeedsLayout];
00151 [self setNeedsDisplay:YES];
00152 }
00153 }
00154
00155 - (void)imageDidLoad:(CPNotification)aNotification
00156 {
00157 [self hideOrDisplayContents];
00158
00159 [self setNeedsLayout];
00160 [self setNeedsDisplay:YES];
00161 }
00162
00167 - (BOOL)hasShadow
00168 {
00169 return _hasShadow;
00170 }
00171
00176 - (void)setHasShadow:(BOOL)shouldHaveShadow
00177 {
00178 if (_hasShadow == shouldHaveShadow)
00179 return;
00180
00181 _hasShadow = shouldHaveShadow;
00182
00183 if (_hasShadow)
00184 {
00185 _shadowView = [[CPShadowView alloc] initWithFrame:[self bounds]];
00186
00187 [self addSubview:_shadowView];
00188
00189 [self setNeedsLayout];
00190 [self setNeedsDisplay:YES];
00191 }
00192 else
00193 {
00194 [_shadowView removeFromSuperview];
00195
00196 _shadowView = nil;
00197 }
00198
00199 [self hideOrDisplayContents];
00200 }
00201
00207 - (void)setImageScaling:(CPImageScaling)anImageScaling
00208 {
00209 [super setImageScaling:anImageScaling];
00210
00211 #if PLATFORM(DOM)
00212 if ([self currentValueForThemeAttribute:@"image-scaling"] === CPScaleToFit)
00213 {
00214 CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, 0.0, 0.0);
00215 }
00216 #endif
00217
00218 [self setNeedsLayout];
00219 [self setNeedsDisplay:YES];
00220 }
00221
00225 - (void)hideOrDisplayContents
00226 {
00227 if (![self image])
00228 {
00229 #if PLATFORM(DOM)
00230 _DOMImageElement.style.visibility = "hidden";
00231 #endif
00232 [_shadowView setHidden:YES];
00233 }
00234 else
00235 {
00236 #if PLATFORM(DOM)
00237 _DOMImageElement.style.visibility = "visible";
00238 #endif
00239 [_shadowView setHidden:NO];
00240 }
00241 }
00242
00246 - (CGRect)imageRect
00247 {
00248 return _imageRect;
00249 }
00250
00254 - (void)layoutSubviews
00255 {
00256 if (![self image])
00257 return;
00258
00259 var bounds = [self bounds],
00260 image = [self image],
00261 imageScaling = [self currentValueForThemeAttribute:@"image-scaling"],
00262 x = 0.0,
00263 y = 0.0,
00264 insetWidth = (_hasShadow ? HORIZONTAL_SHADOW_INSET : 0.0),
00265 insetHeight = (_hasShadow ? VERTICAL_SHADOW_INSET : 0.0),
00266 boundsWidth = _CGRectGetWidth(bounds),
00267 boundsHeight = _CGRectGetHeight(bounds),
00268 width = boundsWidth - insetWidth,
00269 height = boundsHeight - insetHeight;
00270
00271 if (imageScaling === CPScaleToFit)
00272 {
00273 #if PLATFORM(DOM)
00274 _DOMImageElement.width = ROUND(width);
00275 _DOMImageElement.height = ROUND(height);
00276 #endif
00277 }
00278 else
00279 {
00280 var size = [image size];
00281
00282 if (size.width == -1 && size.height == -1)
00283 return;
00284
00285 if (imageScaling === CPScaleProportionally)
00286 {
00287
00288
00289 if (width >= size.width && height >= size.height)
00290 {
00291 width = size.width;
00292 height = size.height;
00293 }
00294 else
00295 {
00296 var imageRatio = size.width / size.height,
00297 viewRatio = width / height;
00298
00299 if (viewRatio > imageRatio)
00300 width = height * imageRatio;
00301 else
00302 height = width / imageRatio;
00303 }
00304
00305 #if PLATFORM(DOM)
00306 _DOMImageElement.width = ROUND(width);
00307 _DOMImageElement.height = ROUND(height);
00308 #endif
00309 }
00310 else
00311 {
00312 width = size.width;
00313 height = size.height;
00314 }
00315
00316 if (imageScaling == CPScaleNone)
00317 {
00318 #if PLATFORM(DOM)
00319 _DOMImageElement.width = ROUND(size.width);
00320 _DOMImageElement.height = ROUND(size.height);
00321 #endif
00322 }
00323
00324 var x = (boundsWidth - width) / 2.0,
00325 y = (boundsHeight - height) / 2.0;
00326
00327 #if PLATFORM(DOM)
00328 CPDOMDisplayServerSetStyleLeftTop(_DOMImageElement, NULL, x, y);
00329 #endif
00330 }
00331
00332 _imageRect = _CGRectMake(x, y, width, height);
00333
00334 if (_hasShadow)
00335 [_shadowView setFrame:_CGRectMake(x - LEFT_SHADOW_INSET, y - TOP_SHADOW_INSET, width + insetWidth, height + insetHeight)];
00336 }
00337
00338 - (void)mouseDown:(CPEvent)anEvent
00339 {
00340
00341 [[self nextResponder] mouseDown:anEvent];
00342 }
00343
00344 - (void)setEditable:(BOOL)shouldBeEditable
00345 {
00346 if (_isEditable === shouldBeEditable)
00347 return;
00348
00349 _isEditable = shouldBeEditable;
00350
00351 if (_isEditable)
00352 [self registerForDraggedTypes:[CPImagesPboardType]];
00353
00354 else
00355 {
00356 var draggedTypes = [self registeredDraggedTypes];
00357
00358 [self unregisterDraggedTypes];
00359
00360 [draggedTypes removeObjectIdenticalTo:CPImagesPboardType];
00361
00362 [self registerForDraggedTypes:draggedTypes];
00363 }
00364 }
00365
00366 - (BOOL)isEditable
00367 {
00368 return _isEditable;
00369 }
00370
00371 - (void)performDragOperation:(CPDraggingInfo)aSender
00372 {
00373 var images = [CPKeyedUnarchiver unarchiveObjectWithData:[[aSender draggingPasteboard] dataForType:CPImagesPboardType]];
00374
00375 if ([images count])
00376 [self setImage:images[0]];
00377 }
00378
00379 @end
00380
00381 var CPImageViewImageKey = @"CPImageViewImageKey",
00382 CPImageViewImageScalingKey = @"CPImageViewImageScalingKey",
00383 CPImageViewHasShadowKey = @"CPImageViewHasShadowKey",
00384 CPImageViewIsEditableKey = @"CPImageViewIsEditableKey";
00385
00386 @implementation CPImageView (CPCoding)
00387
00393 - (id)initWithCoder:(CPCoder)aCoder
00394 {
00395 #if PLATFORM(DOM)
00396 _DOMImageElement = document.createElement("img");
00397 _DOMImageElement.style.position = "absolute";
00398 _DOMImageElement.style.left = "0px";
00399 _DOMImageElement.style.top = "0px";
00400 _DOMImageElement.style.visibility = "hidden";
00401 #endif
00402
00403 self = [super initWithCoder:aCoder];
00404
00405 if (self)
00406 {
00407 #if PLATFORM(DOM)
00408 _DOMElement.appendChild(_DOMImageElement);
00409 #endif
00410
00411 [self setHasShadow:[aCoder decodeBoolForKey:CPImageViewHasShadowKey]];
00412
00413 if ([aCoder decodeBoolForKey:CPImageViewIsEditableKey] || NO)
00414 [self setEditable:YES];
00415
00416 [self setNeedsLayout];
00417 [self setNeedsDisplay:YES];
00418 }
00419
00420 return self;
00421 }
00422
00428 - (void)encodeWithCoder:(CPCoder)aCoder
00429 {
00430
00431
00432 if (_shadowView)
00433 {
00434 var actualSubviews = _subviews;
00435
00436 _subviews = [_subviews copy];
00437 [_subviews removeObjectIdenticalTo:_shadowView];
00438 }
00439
00440 [super encodeWithCoder:aCoder];
00441
00442 if (_shadowView)
00443 _subviews = actualSubviews;
00444
00445 [aCoder encodeBool:_hasShadow forKey:CPImageViewHasShadowKey];
00446
00447 if (_isEditable)
00448 [aCoder encodeBool:_isEditable forKey:CPImageViewIsEditableKey];
00449 }
00450
00451 @end