bzr branch
/browse/iphone/common
| Line | Revision | Contents |
| 1 | 64 | // |
| 2 | // ImageWell.m |
|
| 3 | // Jigs |
|
| 4 | // |
|
| 5 | // Created by döme on 11.08.2009. |
|
| 6 | // Copyright 2009 __MyCompanyName__. All rights reserved. |
|
| 7 | // |
|
| 8 | ||
| 9 | #import "ImageWell.h" |
|
| 10 | #import "ElAnimation.h" |
|
| 11 | 85 | #import "NSObject_DeviceDetection.h" |
| 12 | 64 | |
| 13 | #import <QuartzCore/QuartzCore.h> |
|
| 14 | ||
| 15 | @class UIPopoverController; |
|
| 16 | ||
| 17 | 84 | void createPathInRoundedRect(CGContextRef c, CGRect rect, float radius, unsigned cornerMask) |
| 18 | 64 | { |
| 19 | CGContextBeginPath(c); |
|
| 20 | 84 | if (cornerMask & ElImageCornerTopLeft) |
| 21 | CGContextMoveToPoint(c, CGRectGetMinX(rect) + radius, CGRectGetMinY(rect) ); |
|
| 22 | else |
|
| 23 | CGContextMoveToPoint(c, CGRectGetMinX(rect), CGRectGetMinY(rect) ); |
|
| 24 | if (cornerMask & ElImageCornerTopRight) |
|
| 25 | { |
|
| 26 | CGContextAddLineToPoint(c, CGRectGetMaxX(rect) - radius, CGRectGetMinY(rect)); |
|
| 27 | CGContextAddArcToPoint(c, CGRectGetMaxX(rect), CGRectGetMinY(rect), CGRectGetMaxX(rect), CGRectGetMinY(rect) + radius, radius); |
|
| 28 | } |
|
| 29 | else |
|
| 30 | CGContextAddLineToPoint(c, CGRectGetMaxX(rect), CGRectGetMinY(rect)); |
|
| 31 | |
|
| 32 | if (cornerMask & ElImageCornerBottomRight) |
|
| 33 | { |
|
| 34 | CGContextAddLineToPoint(c, CGRectGetMaxX(rect), CGRectGetMaxY(rect) - radius); |
|
| 35 | CGContextAddArcToPoint(c, CGRectGetMaxX(rect), CGRectGetMaxY(rect), CGRectGetMaxX(rect) - radius, CGRectGetMaxY(rect), radius); |
|
| 36 | } |
|
| 37 | else |
|
| 38 | CGContextAddLineToPoint(c, CGRectGetMaxX(rect), CGRectGetMaxY(rect)); |
|
| 39 | |
|
| 40 | if (cornerMask & ElImageCornerBottomLeft) |
|
| 41 | { |
|
| 42 | CGContextAddLineToPoint(c, CGRectGetMinX(rect) + radius, CGRectGetMaxY(rect)); |
|
| 43 | CGContextAddArcToPoint(c, CGRectGetMinX(rect), CGRectGetMaxY(rect), CGRectGetMinX(rect), CGRectGetMaxY(rect) - radius, radius); |
|
| 44 | } |
|
| 45 | else |
|
| 46 | CGContextAddLineToPoint(c, CGRectGetMinX(rect), CGRectGetMaxY(rect)); |
|
| 47 | |
|
| 48 | if (cornerMask & ElImageCornerTopLeft) |
|
| 49 | { |
|
| 50 | CGContextAddLineToPoint(c, CGRectGetMinX(rect), CGRectGetMinY(rect) + radius ); |
|
| 51 | CGContextAddArcToPoint(c, CGRectGetMinX(rect), CGRectGetMinY(rect), CGRectGetMinX(rect) + radius, CGRectGetMinY(rect), radius); |
|
| 52 | } |
|
| 53 | ||
| 54 | 64 | CGContextClosePath(c); |
| 55 | |
|
| 56 | ||
| 57 | } |
|
| 58 | ||
| 59 | @implementation UIImage (ElImageView) |
|
| 60 | ||
| 61 | CGImageRef CreateScaledCGImageFromCGImage(CGImageRef image, CGSize size, UIImageOrientation orientation) |
|
| 62 | { |
|
| 63 | int srcWidth = size.width; |
|
| 64 | int srcHeight = size.height; |
|
| 65 | int dstWidth = size.width; |
|
| 66 | int dstHeight = size.height; |
|
| 67 | |
|
| 68 | switch (orientation) |
|
| 69 | { |
|
| 70 | case UIImageOrientationLeft: |
|
| 71 | case UIImageOrientationLeftMirrored: |
|
| 72 | case UIImageOrientationRight: |
|
| 73 | case UIImageOrientationRightMirrored: |
|
| 74 | { |
|
| 75 | srcWidth = dstHeight; |
|
| 76 | srcHeight = dstWidth; |
|
| 77 | break; |
|
| 78 | } |
|
| 79 | 83 | default: |
| 80 | break; |
|
| 81 | 64 | } |
| 82 | |
|
| 83 | ||
| 84 | //UIGraphicsPushContext(UIGraphicsGetCurrentContext()); |
|
| 85 | |
|
| 86 | // Declare the number of bytes per row. Each pixel in the bitmap in this |
|
| 87 | // example is represented by 4 bytes; 8 bits each of red, green, blue, and |
|
| 88 | // alpha. |
|
| 89 | size_t bitmapBytesPerRow = (dstWidth * 4); |
|
| 90 | size_t bitmapByteCount = (bitmapBytesPerRow * dstHeight); |
|
| 91 | |
|
| 92 | // Allocate memory for image data. This is the destination in memory |
|
| 93 | // where any drawing to the bitmap context will be rendered. |
|
| 94 | void* bitmapData = malloc( bitmapByteCount ); |
|
| 95 | if (bitmapData == NULL) |
|
| 96 | { |
|
| 97 | return nil; |
|
| 98 | } |
|
| 99 | |
|
| 100 | // Create the bitmap context. We want pre-multiplied ARGB, 8-bits |
|
| 101 | // per component. Regardless of what the source image format is |
|
| 102 | // (CMYK, Grayscale, and so on) it will be converted over to the format |
|
| 103 | // specified here by CGBitmapContextCreate. |
|
| 104 | 67 | //CGColorSpaceRef colorspace = CGImageGetColorSpace(image); |
| 105 | CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); |
|
| 106 | 64 | CGContextRef context = CGBitmapContextCreate(bitmapData,dstWidth,dstHeight,8,bitmapBytesPerRow, |
| 107 | colorspace,kCGImageAlphaPremultipliedFirst); |
|
| 108 | CGColorSpaceRelease(colorspace); |
|
| 109 | |
|
| 110 | if (context == NULL) |
|
| 111 | // error creating context |
|
| 112 | { |
|
| 113 | free(bitmapData); |
|
| 114 | return nil; |
|
| 115 | } |
|
| 116 | |
|
| 117 | CGFloat angle = 0.0; |
|
| 118 | switch (orientation) |
|
| 119 | { |
|
| 120 | case UIImageOrientationLeft: |
|
| 121 | case UIImageOrientationLeftMirrored: |
|
| 122 | angle = M_PI_2; |
|
| 123 | break; |
|
| 124 | case UIImageOrientationRight: |
|
| 125 | case UIImageOrientationRightMirrored: |
|
| 126 | angle = -M_PI_2; |
|
| 127 | break; |
|
| 128 | case UIImageOrientationDown: |
|
| 129 | case UIImageOrientationDownMirrored: |
|
| 130 | angle = M_PI; |
|
| 131 | break; |
|
| 132 | 83 | default: |
| 133 | angle = 0.0f; |
|
| 134 | break; |
|
| 135 | 64 | } |
| 136 | |
|
| 137 | CGContextTranslateCTM(context, 0.5f*(float)dstWidth, 0.5*(float)dstHeight); |
|
| 138 | CGContextRotateCTM(context, angle); |
|
| 139 | CGContextTranslateCTM(context, -0.5f*(float)srcWidth, -0.5*(float)srcHeight); |
|
| 140 | // Draw the image to the bitmap context. Once we draw, the memory |
|
| 141 | // allocated for the context for rendering will then contain the |
|
| 142 | // raw image data in the specified color space. |
|
| 143 | |
|
| 144 | |
|
| 145 | |
|
| 146 | CGContextDrawImage(context, CGRectMake(0,0,srcWidth, srcHeight), image); |
|
| 147 | |
|
| 148 | CGImageRef imgRef = CGBitmapContextCreateImage(context); |
|
| 149 | CGContextRelease(context); |
|
| 150 | free(bitmapData); |
|
| 151 | |
|
| 152 | //UIGraphicsPopContext(); |
|
| 153 | |
|
| 154 | return imgRef; |
|
| 155 | } |
|
| 156 | ||
| 157 | ||
| 158 | - (UIImage*) scaledToSize: (CGSize) size |
|
| 159 | { |
|
| 160 | CGImageRef imgref = CreateScaledCGImageFromCGImage([self CGImage], size, [self imageOrientation]); |
|
| 161 | if (!imgref) |
|
| 162 | return nil; |
|
| 163 | |
|
| 164 | UIImage* img = [UIImage imageWithCGImage: imgref]; |
|
| 165 | |
|
| 166 | CGImageRelease(imgref); |
|
| 167 | |
|
| 168 | return img; |
|
| 169 | } |
|
| 170 | ||
| 171 | @end |
|
| 172 | ||
| 173 | @implementation ElImageView |
|
| 174 | ||
| 175 | - (id) initWithFrame: (CGRect) frame |
|
| 176 | { |
|
| 177 | if (!(self = [super initWithFrame: frame])) |
|
| 178 | return nil; |
|
| 179 | ||
| 180 | 94 | borderColor = [UIColor grayColor]; |
| 181 | 64 | cornerRadius = 5.0f; |
| 182 | borderWidth = 1.0f; |
|
| 183 | imageAlpha = 1.0f; |
|
| 184 | 84 | cornerMask = ElImageAllCorners; |
| 185 | 64 | |
| 186 | [self setBackgroundColor: [UIColor redColor]]; |
|
| 187 | 65 | [self setContentMode: UIViewContentModeRedraw]; |
| 188 | 64 | |
| 189 | return self; |
|
| 190 | } |
|
| 191 | ||
| 192 | ||
| 193 | - (id) initWithCoder: (NSCoder*) coder |
|
| 194 | { |
|
| 195 | if (!(self = [super initWithCoder: coder])) |
|
| 196 | return nil; |
|
| 197 | |
|
| 198 | 94 | borderColor = [UIColor grayColor]; |
| 199 | 64 | cornerRadius = 5.0f; |
| 200 | borderWidth = 1.0f; |
|
| 201 | imageAlpha = 1.0f; |
|
| 202 | 84 | cornerMask = ElImageAllCorners; |
| 203 | 64 | |
| 204 | fillView = NO; |
|
| 205 | |
|
| 206 | [self setBackgroundColor: [UIColor clearColor]]; |
|
| 207 | 65 | [self setContentMode: UIViewContentModeRedraw]; |
| 208 | 64 | |
| 209 | return self; |
|
| 210 | } |
|
| 211 | ||
| 212 | ||
| 213 | /* |
|
| 214 | - (void) setFrame: (CGRect) frame |
|
| 215 | { |
|
| 216 | [super setFrame: frame]; |
|
| 217 | if (!CGRectEqualToRect(frame, [self frame])) |
|
| 218 | { |
|
| 219 | [_cachedImageForDrawing release]; |
|
| 220 | _cachedImageForDrawing = nil; |
|
| 221 | } |
|
| 222 | } |
|
| 223 | */ |
|
| 224 | 100 | |
| 225 | - (void) imageWasLoaded |
|
| 226 | { |
|
| 227 | |
|
| 228 | } |
|
| 229 | ||
| 230 | - (void) prepareCachedImageAsync: (UIImage*) img |
|
| 231 | { |
|
| 232 | __block UIImage* theImage = img; |
|
| 233 | CGRect bounds = self.bounds; |
|
| 234 | float scale = [[UIScreen mainScreen] scale]; |
|
| 235 | |
|
| 236 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ |
|
| 237 | ||
| 238 | if (!theImage) |
|
| 239 | theImage = [UIImage imageNamed: @"image-not-found-icon.png"]; |
|
| 240 | ||
| 241 | CGSize imgSize = [theImage size]; |
|
| 242 | ||
| 243 | float drawHeight = imgSize.height; |
|
| 244 | float drawWidth = imgSize.width; |
|
| 245 | |
|
| 246 | float heightR = imgSize.height/bounds.size.height; |
|
| 247 | float widthR = imgSize.width/bounds.size.width; |
|
| 248 | |
|
| 249 | if (heightR > 1.0f) |
|
| 250 | { |
|
| 251 | drawHeight = bounds.size.height; |
|
| 252 | drawWidth *= 1.0f/heightR; |
|
| 253 | widthR = drawWidth/bounds.size.width; |
|
| 254 | } |
|
| 255 | |
|
| 256 | if (widthR > 1.0f) |
|
| 257 | { |
|
| 258 | drawWidth = bounds.size.width; |
|
| 259 | drawHeight *= 1.0f/widthR; |
|
| 260 | } |
|
| 261 | |
|
| 262 | CGRect drawRect = CGRectMake(bounds.origin.x + 0.5f*(bounds.size.width - drawWidth), bounds.origin.y + 0.5f*(bounds.size.height - drawHeight), drawWidth, drawHeight); |
|
| 263 | |
|
| 264 | if (fillView) |
|
| 265 | drawRect = bounds; |
|
| 266 | ||
| 267 | UIImage* drawableImage = nil; |
|
| 268 | |
|
| 269 | CGSize targetSize = CGSizeScale(drawRect.size, scale); |
|
| 270 | //if ((targetSize.width > 1.0*drawRect.size.width) || (targetSize.height > 1.0*drawRect.size.height)) |
|
| 271 | drawableImage = [theImage scaledToSize: targetSize]; |
|
| 272 | //else |
|
| 273 | // drawableImage = theImage; |
|
| 274 | ||
| 275 | dispatch_async(dispatch_get_main_queue(), ^{ |
|
| 276 | image = img; |
|
| 277 | _drawableImage = drawableImage; |
|
| 278 | |
|
| 279 | [self imageWasLoaded]; |
|
| 280 | [self setNeedsDisplay]; |
|
| 281 | }); |
|
| 282 | }); |
|
| 283 | } |
|
| 284 | ||
| 285 | 64 | - (void) drawRect: (CGRect) rect |
| 286 | { |
|
| 287 | CGContextRef c = UIGraphicsGetCurrentContext(); |
|
| 288 | //[[UIColor blueColor] set]; |
|
| 289 | //CGContextFillRect(c, rect); |
|
| 290 | ||
| 291 | CGContextSaveGState(c); |
|
| 292 | ||
| 293 | UIImage* img = nil; |
|
| 294 | |
|
| 295 | @synchronized(self) |
|
| 296 | { |
|
| 297 | img = image; |
|
| 298 | } |
|
| 299 | 100 | if (!img && showMissingImage) |
| 300 | 64 | img = [UIImage imageNamed: @"image-not-found-icon.png"]; |
| 301 | |
|
| 302 | CGRect bounds = CGRectInset([self bounds], 0.5*borderWidth,0.5*borderWidth); |
|
| 303 | CGSize imgSize = [img size]; |
|
| 304 | |
|
| 305 | 100 | if (!img) |
| 306 | return; |
|
| 307 | 64 | |
| 308 | |
|
| 309 | float drawHeight = imgSize.height; |
|
| 310 | float drawWidth = imgSize.width; |
|
| 311 | |
|
| 312 | float heightR = imgSize.height/bounds.size.height; |
|
| 313 | float widthR = imgSize.width/bounds.size.width; |
|
| 314 | |
|
| 315 | if (heightR > 1.0f) |
|
| 316 | { |
|
| 317 | drawHeight = bounds.size.height; |
|
| 318 | drawWidth *= 1.0f/heightR; |
|
| 319 | widthR = drawWidth/bounds.size.width; |
|
| 320 | } |
|
| 321 | ||
| 322 | if (widthR > 1.0f) |
|
| 323 | { |
|
| 324 | drawWidth = bounds.size.width; |
|
| 325 | drawHeight *= 1.0f/widthR; |
|
| 326 | } |
|
| 327 | |
|
| 328 | CGRect drawRect = CGRectMake(bounds.origin.x + 0.5f*(bounds.size.width - drawWidth), bounds.origin.y + 0.5f*(bounds.size.height - drawHeight), drawWidth, drawHeight); |
|
| 329 | ||
| 330 | if (fillView) |
|
| 331 | drawRect = bounds; |
|
| 332 | |
|
| 333 | 100 | |
| 334 | ||
| 335 | if (!_drawableImage && !asyncImageProcessing) |
|
| 336 | 64 | { |
| 337 | //bounds.size.width = ceilf(bounds.origin.x + bounds.size.width) - bounds.origin.x; |
|
| 338 | //bounds.origin.x = ceilf(bounds.origin.x); |
|
| 339 | //bounds.origin.y = ceilf(bounds.origin.y); |
|
| 340 | 100 | CGSize targetSize = CGSizeScale(drawRect.size, [[UIScreen mainScreen] scale]); |
| 341 | if ((targetSize.width > 1.0*drawRect.size.width) || (targetSize.height > 1.0*drawRect.size.height)) |
|
| 342 | _drawableImage = [img scaledToSize: targetSize]; |
|
| 343 | else |
|
| 344 | _drawableImage = img; |
|
| 345 | 64 | } |
| 346 | 100 | |
| 347 | 84 | createPathInRoundedRect(c, drawRect, cornerRadius, cornerMask); |
| 348 | 64 | |
| 349 | CGContextClip(c); |
|
| 350 | ||
| 351 | 100 | [_drawableImage drawInRect: drawRect blendMode: kCGBlendModeNormal alpha: imageAlpha*self.alpha]; |
| 352 | 64 | |
| 353 | CGContextRestoreGState(c); |
|
| 354 | if (borderWidth) |
|
| 355 | { |
|
| 356 | 84 | [[borderColor colorWithAlphaComponent: imageAlpha*self.alpha] set]; |
| 357 | createPathInRoundedRect(c, CGRectInset(drawRect, borderInset, borderInset), cornerRadius, cornerMask); |
|
| 358 | 64 | CGContextSetLineWidth(c, borderWidth); |
| 359 | CGContextStrokePath(c); |
|
| 360 | } |
|
| 361 | } |
|
| 362 | ||
| 363 | 84 | - (void) setCornerMask: (unsigned) a |
| 364 | { |
|
| 365 | cornerMask = a; |
|
| 366 | [self setNeedsDisplay]; |
|
| 367 | } |
|
| 368 | ||
| 369 | 64 | - (void) setImageAlpha: (float) a |
| 370 | { |
|
| 371 | imageAlpha = a; |
|
| 372 | [self setNeedsDisplay]; |
|
| 373 | } |
|
| 374 | ||
| 375 | - (void) setImage: (UIImage*) img |
|
| 376 | { |
|
| 377 | 100 | if (!asyncImageProcessing) |
| 378 | 64 | { |
| 379 | image = img; |
|
| 380 | 100 | _drawableImage = nil; |
| 381 | [self setNeedsDisplay]; |
|
| 382 | [self imageWasLoaded]; |
|
| 383 | 64 | } |
| 384 | 100 | else |
| 385 | [self prepareCachedImageAsync: img]; |
|
| 386 | // [self performSelectorOnMainThread: @selector(prepareCachedImageAsync:) withObject: img waitUntilDone: NO]; |
|
| 387 | ||
| 388 | // [self performSelectorOnMainThread: @selector(setNeedsDisplay) withObject: nil waitUntilDone: NO]; |
|
| 389 | 64 | } |
| 390 | ||
| 391 | 100 | @synthesize image, cornerRadius, borderColor, borderWidth, borderInset, fillView, imageAlpha, cornerMask, asyncImageProcessing, showMissingImage; |
| 392 | 64 | |
| 393 | @end |
|
| 394 | ||
| 395 | ||
| 396 | 67 | @interface ImageWell (Private) |
| 397 | - (void) showImagePicker; |
|
| 398 | - (void) pasteAction: (id) info; |
|
| 399 | ||
| 400 | @end |
|
| 401 | 64 | |
| 402 | @implementation ImageWell |
|
| 403 | ||
| 404 | ||
| 405 | - (id) initWithFrame: (CGRect) frame |
|
| 406 | { |
|
| 407 | if (!(self = [super initWithFrame: frame])) |
|
| 408 | return nil; |
|
| 409 | ||
| 410 | return self; |
|
| 411 | } |
|
| 412 | ||
| 413 | - (id) initWithCoder: (NSCoder*) coder |
|
| 414 | { |
|
| 415 | if (!(self = [super initWithCoder: coder])) |
|
| 416 | return nil; |
|
| 417 | |
|
| 418 | 78 | instructionsView = [[UITextView alloc] initWithFrame: CGRectInset([self bounds], 0.0f, 0.0f)]; |
| 419 | 64 | [instructionsView setText: NSLocalizedString(@"ImageWell instruction text", @"\n\n\nTap and hold to paste image,\n\nor\n\nDouble-tap to select image from gallery.")]; |
| 420 | //[instructionsView setBackgroundColor: [UIColor yellowColor]]; |
|
| 421 | [instructionsView setTextColor: [UIColor whiteColor]]; |
|
| 422 | [instructionsView setBackgroundColor: [UIColor clearColor]]; |
|
| 423 | 67 | [instructionsView setFont: [UIFont systemFontOfSize: [UIFont labelFontSize]*2.0f]]; |
| 424 | 64 | [instructionsView setEditable: NO]; |
| 425 | [instructionsView setUserInteractionEnabled: NO]; |
|
| 426 | [instructionsView setTextAlignment: UITextAlignmentCenter]; |
|
| 427 | [self addSubview: instructionsView]; |
|
| 428 | ||
| 429 | [instructionsView layer].opacity = 0.0f; |
|
| 430 | 67 | |
| 431 | 78 | |
| 432 | 94 | activityIndicatorView = [[UIActivityIndicatorView alloc] initWithFrame: [self bounds]]; |
| 433 | 67 | activityIndicatorView.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray; |
| 434 | activityIndicatorView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | |
|
| 435 | UIViewAutoresizingFlexibleRightMargin | |
|
| 436 | UIViewAutoresizingFlexibleTopMargin | |
|
| 437 | UIViewAutoresizingFlexibleBottomMargin); |
|
| 438 | [activityIndicatorView sizeToFit]; |
|
| 439 | ||
| 440 | [activityIndicatorView layer].opacity = 0.0f; |
|
| 441 | [self addSubview: activityIndicatorView]; |
|
| 442 | |
|
| 443 | CGRect bounds = [self bounds]; |
|
| 444 | CGSize a = [activityIndicatorView frame].size; |
|
| 445 | [activityIndicatorView setFrame: CGRectMake((bounds.size.width-a.width)*0.5f, (bounds.size.height-a.height)*0.5f, a.width, a.height)]; |
|
| 446 | 64 | |
| 447 | ||
| 448 | return self; |
|
| 449 | } |
|
| 450 | ||
| 451 | - (void) setFrame: (CGRect) frame |
|
| 452 | { |
|
| 453 | [super setFrame: frame]; |
|
| 454 | [instructionsView setFrame: CGRectInset([self bounds], 0.0f, 0.0f)]; |
|
| 455 | } |
|
| 456 | ||
| 457 | ||
| 458 | ||
| 459 | - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex |
|
| 460 | { |
|
| 461 | 67 | switch(buttonIndex) |
| 462 | { |
|
| 463 | case 0: |
|
| 464 | break; |
|
| 465 | case 1: |
|
| 466 | [self showImagePicker]; |
|
| 467 | break; |
|
| 468 | case 2: |
|
| 469 | [self pasteAction: nil]; |
|
| 470 | break; |
|
| 471 | } |
|
| 472 | ||
| 473 | ||
| 474 | 64 | [alertView dismissWithClickedButtonIndex: buttonIndex animated: YES]; |
| 475 | 67 | [activityIndicatorView stopAnimating]; |
| 476 | [activityIndicatorView layer].opacity = 0.0; |
|
| 477 | 64 | } |
| 478 | ||
| 479 | ||
| 480 | - (void) pbAlert |
|
| 481 | { |
|
| 482 | id alert = [[UIAlertView alloc] initWithTitle: @"No Image to Paste!" message: @"Sorry, there is no usable image or image URL on the pasteboard" delegate: self cancelButtonTitle: nil otherButtonTitles: @"OK", nil]; |
|
| 483 | [alert show]; |
|
| 484 | } |
|
| 485 | ||
| 486 | 67 | - (UIImage*) pbImage |
| 487 | { |
|
| 488 | UIImage* theImage = nil; |
|
| 489 | NSArray* images = [[UIPasteboard generalPasteboard] images]; |
|
| 490 | if ([images count]) |
|
| 491 | { |
|
| 492 | UIImage* img = [images objectAtIndex: 0]; |
|
| 493 | if (img) |
|
| 494 | theImage = img; |
|
| 495 | } |
|
| 496 | else |
|
| 497 | { |
|
| 498 | id url = [[UIPasteboard generalPasteboard] URL]; |
|
| 499 | if (url) |
|
| 500 | { |
|
| 501 | NSData *data = [NSData dataWithContentsOfURL:url]; |
|
| 502 | UIImage *img = [UIImage imageWithData:data]; |
|
| 503 | if (img) |
|
| 504 | { |
|
| 505 | theImage = img; |
|
| 506 | } |
|
| 507 | } |
|
| 508 | } |
|
| 509 | return theImage; |
|
| 510 | } |
|
| 511 | ||
| 512 | 64 | - (void) pasteAction: (id) info |
| 513 | { |
|
| 514 | NSArray* images = [[UIPasteboard generalPasteboard] images]; |
|
| 515 | if ([images count]) |
|
| 516 | { |
|
| 517 | UIImage* img = [images objectAtIndex: 0]; |
|
| 518 | |
|
| 519 | 100 | [delegate image: img wasSelectedInWell: self]; |
| 520 | 64 | [self setImage: img]; |
| 521 | } |
|
| 522 | else |
|
| 523 | { |
|
| 524 | id url = [[UIPasteboard generalPasteboard] URL]; |
|
| 525 | if (url) |
|
| 526 | { |
|
| 527 | NSData *data = [NSData dataWithContentsOfURL:url]; |
|
| 528 | UIImage *img = [UIImage imageWithData:data]; |
|
| 529 | if (img) |
|
| 530 | { |
|
| 531 | 100 | [delegate image: img wasSelectedInWell: self]; |
| 532 | 64 | [self setImage: img]; |
| 533 | } |
|
| 534 | else |
|
| 535 | [self pbAlert]; |
|
| 536 | } |
|
| 537 | else |
|
| 538 | [self pbAlert]; |
|
| 539 | } |
|
| 540 | pasteTimer = nil; |
|
| 541 | } |
|
| 542 | ||
| 543 | - (void) showInstructions: (float) time |
|
| 544 | { |
|
| 545 | time = MAX(1.0f, time); |
|
| 546 | |
|
| 547 | ElFloatAnimation* anim = nil; |
|
| 548 | ||
| 549 | 94 | anim = [[ElFloatAnimation alloc] init]; |
| 550 | 64 | |
| 551 | [anim setStartValue: [[instructionsView layer] opacity]]; |
|
| 552 | [anim setEndValue: 0.667f]; |
|
| 553 | [anim setDuration: 0.5f]; |
|
| 554 | [anim setTarget: [instructionsView layer]]; |
|
| 555 | [anim setProperty: @"opacity"]; |
|
| 556 | [anim queueForKey: @"text-opacity" atBeginning: YES cancelPending: YES]; |
|
| 557 | |
|
| 558 | |
|
| 559 | 94 | anim = [[ElFloatAnimation alloc] init]; |
| 560 | 64 | |
| 561 | [anim setStartValue: imageAlpha]; |
|
| 562 | [anim setEndValue: 0.333f]; |
|
| 563 | [anim setDuration: 0.5f]; |
|
| 564 | [anim setTarget: self]; |
|
| 565 | [anim setProperty: @"imageAlpha"]; |
|
| 566 | [anim queueForKey: @"image-opacity" atBeginning: YES cancelPending: YES]; |
|
| 567 | |
|
| 568 | [[ElAnimation delayedAnimationWithDelay: time - 0.5f] queueForKey: @"text-opacity" atBeginning: NO cancelPending: NO]; |
|
| 569 | [[ElAnimation delayedAnimationWithDelay: time - 0.5f] queueForKey: @"image-opacity" atBeginning: NO cancelPending: NO]; |
|
| 570 | ||
| 571 | 94 | anim = [[ElFloatAnimation alloc] init]; |
| 572 | 64 | |
| 573 | [anim setStartValue: 0.667f]; |
|
| 574 | [anim setEndValue: 0.0f]; |
|
| 575 | [anim setDuration: 0.5f]; |
|
| 576 | [anim setTarget: [instructionsView layer]]; |
|
| 577 | [anim setProperty: @"opacity"]; |
|
| 578 | [anim queueForKey: @"text-opacity" atBeginning: NO cancelPending: NO]; |
|
| 579 | ||
| 580 | ||
| 581 | 94 | anim = [[ElFloatAnimation alloc] init]; |
| 582 | 64 | |
| 583 | [anim setStartValue: 0.333f]; |
|
| 584 | [anim setEndValue: 1.0f]; |
|
| 585 | [anim setDuration: 0.5f]; |
|
| 586 | [anim setTarget: self]; |
|
| 587 | [anim setProperty: @"imageAlpha"]; |
|
| 588 | [anim queueForKey: @"image-opacity" atBeginning: NO cancelPending: NO]; |
|
| 589 | } |
|
| 590 | ||
| 591 | 67 | - (void) showImagePicker |
| 592 | { |
|
| 593 | if (!imagePicker) |
|
| 594 | { |
|
| 595 | imagePicker = [[UIImagePickerController alloc] init]; |
|
| 596 | ||
| 597 | //[imagePicker setSourceType: UIImagePickerControllerSourceTypeCamera]; |
|
| 598 | [imagePicker setDelegate: self]; |
|
| 599 | //[imagePicker setAllowsImageEditing: YES]; |
|
| 600 | //[imagePicker setShowsCameraControls: NO]; |
|
| 601 | } |
|
| 602 | |
|
| 603 | assert(delegate); |
|
| 604 | 70 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2 |
| 605 | 67 | if ([self isItAPad]) |
| 606 | { |
|
| 607 | if (!popoverController) |
|
| 608 | { |
|
| 609 | Class popoverClass = NSClassFromString(@"UIPopoverController"); |
|
| 610 | popoverController = [[popoverClass alloc] initWithContentViewController: imagePicker]; |
|
| 611 | } |
|
| 612 | 97 | CGRect presentRect = [self bounds]; |
| 613 | presentRect.size.height *= 0.5f; |
|
| 614 | [popoverController presentPopoverFromRect: presentRect inView: self permittedArrowDirections: UIPopoverArrowDirectionAny animated: YES]; |
|
| 615 | 67 | } |
| 616 | else |
|
| 617 | #endif |
|
| 618 | [delegate presentModalViewController: imagePicker animated: YES]; |
|
| 619 | } |
|
| 620 | ||
| 621 | 64 | - (void) touchesBegan: (NSSet*) touches withEvent: (UIEvent*) event |
| 622 | { |
|
| 623 | 67 | /* UITouch* touch = [touches anyObject]; |
| 624 | 64 | |
| 625 | if (([touch tapCount] == 1) && [self isItAPhone]) |
|
| 626 | { |
|
| 627 | [self showInstructions: 3.0f]; |
|
| 628 | } |
|
| 629 | ||
| 630 | |
|
| 631 | touchBeganTime = [event timestamp]; |
|
| 632 | |
|
| 633 | pasteTimer = [NSTimer scheduledTimerWithTimeInterval: 2.0 target: self selector:@selector(pasteAction:) userInfo: nil repeats: NO]; |
|
| 634 | |
|
| 635 | if ([touch tapCount] == 2) |
|
| 636 | { |
|
| 637 | [pasteTimer invalidate]; |
|
| 638 | pasteTimer = nil; |
|
| 639 | ||
| 640 | 67 | [self showImagePicker]; |
| 641 | 64 | } |
| 642 | 67 | |
| 643 | */ |
|
| 644 | } |
|
| 645 | ||
| 646 | - (void) showSourceDialog |
|
| 647 | { |
|
| 648 | NSString* msg = NSLocalizedString(@"ImageWell alert message", @""); |
|
| 649 | NSString* title = NSLocalizedString(@"ImageWell alert title", @""); |
|
| 650 | |
|
| 651 | UIImage* img = [self pbImage]; |
|
| 652 | ||
| 653 | UIAlertView* alert = [[UIAlertView alloc] initWithTitle: title message: msg delegate: self cancelButtonTitle: NSLocalizedString(@"ImageWell alert cancel", @"") |
|
| 654 | otherButtonTitles: NSLocalizedString(@"ImageWell alert picker", @""), |
|
| 655 | (img ? NSLocalizedString(@"ImageWell alert paste", @"") : nil), |
|
| 656 | nil]; |
|
| 657 | [alert show]; |
|
| 658 | |
|
| 659 | 64 | } |
| 660 | ||
| 661 | - (void) touchesEnded: (NSSet*) touches withEvent: (UIEvent*) event |
|
| 662 | { |
|
| 663 | // UITouch* touch = [touches anyObject]; |
|
| 664 | |
|
| 665 | [pasteTimer invalidate]; |
|
| 666 | pasteTimer = nil; |
|
| 667 | 67 | |
| 668 | [activityIndicatorView layer].opacity = 1.0; |
|
| 669 | [activityIndicatorView startAnimating]; |
|
| 670 | [NSTimer scheduledTimerWithTimeInterval: 0.01 target: self selector: @selector(showSourceDialog) userInfo: nil repeats: NO]; |
|
| 671 | 64 | |
| 672 | } |
|
| 673 | ||
| 674 | - (void) touchesCancelled: (NSSet*) touches withEvent: (UIEvent*) event |
|
| 675 | { |
|
| 676 | // UITouch* touch = [touches anyObject]; |
|
| 677 | |
|
| 678 | [pasteTimer invalidate]; |
|
| 679 | pasteTimer = nil; |
|
| 680 | |
|
| 681 | } |
|
| 682 | ||
| 683 | - (void)imagePickerController: (UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info |
|
| 684 | { |
|
| 685 | |
|
| 686 | UIImage* img = [info objectForKey: UIImagePickerControllerEditedImage]; |
|
| 687 | |
|
| 688 | if (!img) |
|
| 689 | img = [info objectForKey: UIImagePickerControllerOriginalImage]; |
|
| 690 | ||
| 691 | if (img) |
|
| 692 | { |
|
| 693 | 100 | [delegate image:img wasSelectedInWell: self]; |
| 694 | 64 | [self setImage: img]; |
| 695 | } |
|
| 696 | ||
| 697 | [delegate dismissModalViewControllerAnimated: YES]; |
|
| 698 | ||
| 699 | } |
|
| 700 | - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker |
|
| 701 | { |
|
| 702 | [delegate dismissModalViewControllerAnimated: YES]; |
|
| 703 | } |
|
| 704 | ||
| 705 | 100 | - (void) imageWasLoaded |
| 706 | { |
|
| 707 | [delegate image: image wasLoadedInWell: self]; |
|
| 708 | } |
|
| 709 | 64 | |
| 710 | @synthesize delegate; |
|
| 711 | ||
| 712 | @end |
Loggerhead 1.17 is a web-based interface for Bazaar branches