FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
BlockAlertView.m
1//
2// BlockAlertView.m
3//
4//
5
6#import "BlockAlertView.h"
7#import "BlockBackground.h"
8#import "BlockUI.h"
9
10@implementation BlockAlertView
11
12@synthesize view = _view;
13@synthesize backgroundImage = _backgroundImage;
14@synthesize vignetteBackground = _vignetteBackground;
15
16static UIImage *background = nil;
17static UIImage *backgroundlandscape = nil;
18static UIFont *titleFont = nil;
19static UIFont *messageFont = nil;
20static UIFont *buttonFont = nil;
21
22#pragma mark - init
23
24+ (void)initialize
25{
26 if (self == [BlockAlertView class])
27 {
28 background = [UIImage imageNamed:kAlertViewBackground];
29 background =
30 [[background stretchableImageWithLeftCapWidth:0
31 topCapHeight:kAlertViewBackgroundCapHeight] retain];
32
33 backgroundlandscape = [UIImage imageNamed:kAlertViewBackgroundLandscape];
34 backgroundlandscape = [[backgroundlandscape
35 stretchableImageWithLeftCapWidth:0
36 topCapHeight:kAlertViewBackgroundCapHeight] retain];
37
38 titleFont = [kAlertViewTitleFont retain];
39 messageFont = [kAlertViewMessageFont retain];
40 buttonFont = [kAlertViewButtonFont retain];
41 }
42}
43
44+ (BlockAlertView *)alertWithTitle:(NSString *)title message:(NSString *)message
45{
46 return [[[BlockAlertView alloc] initWithTitle:title message:message] autorelease];
47}
48
49+ (void)showInfoAlertWithTitle:(NSString *)title message:(NSString *)message
50{
51 BlockAlertView *alert = [[BlockAlertView alloc] initWithTitle:title message:message];
52 [alert setCancelButtonWithTitle:NSLocalizedString(@"Dismiss", nil) block:nil];
53 [alert show];
54 [alert release];
55}
56
57+ (void)showErrorAlert:(NSError *)error
58{
59 BlockAlertView *alert = [[BlockAlertView alloc]
60 initWithTitle:NSLocalizedString(@"Operation Failed", nil)
61 message:[NSString
62 stringWithFormat:NSLocalizedString(
63 @"The operation did not complete successfully: %@",
64 nil),
65 error]];
66 [alert setCancelButtonWithTitle:@"Dismiss" block:nil];
67 [alert show];
68 [alert release];
69}
70
72#pragma mark - NSObject
73
74- (void)addComponents:(CGRect)frame
75{
76 if (_title)
77 {
78 CGSize size = [_title sizeWithFont:titleFont
79 constrainedToSize:CGSizeMake(frame.size.width - kAlertViewBorder * 2, 1000)
80 lineBreakMode:NSLineBreakByWordWrapping];
81
82 UILabel *labelView = [[UILabel alloc]
83 initWithFrame:CGRectMake(kAlertViewBorder, _height,
84 frame.size.width - kAlertViewBorder * 2, size.height)];
85 labelView.font = titleFont;
86 labelView.numberOfLines = 0;
87 labelView.lineBreakMode = NSLineBreakByWordWrapping;
88 labelView.textColor = kAlertViewTitleTextColor;
89 labelView.backgroundColor = [UIColor clearColor];
90 labelView.textAlignment = NSTextAlignmentCenter;
91 labelView.shadowColor = kAlertViewTitleShadowColor;
92 labelView.shadowOffset = kAlertViewTitleShadowOffset;
93 labelView.text = _title;
94 [_view addSubview:labelView];
95 [labelView release];
96
97 _height += size.height + kAlertViewBorder;
98 }
99
100 if (_message)
101 {
102 CGSize size =
103 [_message sizeWithFont:messageFont
104 constrainedToSize:CGSizeMake(frame.size.width - kAlertViewBorder * 2, 1000)
105 lineBreakMode:NSLineBreakByWordWrapping];
106
107 UILabel *labelView = [[UILabel alloc]
108 initWithFrame:CGRectMake(kAlertViewBorder, _height,
109 frame.size.width - kAlertViewBorder * 2, size.height)];
110 labelView.font = messageFont;
111 labelView.numberOfLines = 0;
112 labelView.lineBreakMode = NSLineBreakByWordWrapping;
113 labelView.textColor = kAlertViewMessageTextColor;
114 labelView.backgroundColor = [UIColor clearColor];
115 labelView.textAlignment = NSTextAlignmentCenter;
116 labelView.shadowColor = kAlertViewMessageShadowColor;
117 labelView.shadowOffset = kAlertViewMessageShadowOffset;
118 labelView.text = _message;
119 [_view addSubview:labelView];
120 [labelView release];
121
122 _height += size.height + kAlertViewBorder;
123 }
124}
125
126- (void)setupDisplay
127{
128 [[_view subviews] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
129 [obj removeFromSuperview];
130 }];
131
132 UIWindow *parentView = [BlockBackground sharedInstance];
133 CGRect frame = parentView.bounds;
134 frame.origin.x = floorf((frame.size.width - background.size.width) * 0.5);
135 frame.size.width = background.size.width;
136
137 UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
138 if (UIInterfaceOrientationIsLandscape(orientation))
139 {
140 frame.size.width += 150;
141 frame.origin.x -= 75;
142 }
143
144 _view.frame = frame;
145
146 _height = kAlertViewBorder + 15;
147
148 if (NeedsLandscapePhoneTweaks)
149 {
150 _height -= 15; // landscape phones need to trimmed a bit
151 }
152
153 [self addComponents:frame];
154
155 if (_shown)
156 [self show];
157}
158
159- (id)initWithTitle:(NSString *)title message:(NSString *)message
160{
161 self = [super init];
162
163 if (self)
164 {
165 _title = [title copy];
166 _message = [message copy];
167
168 _view = [[UIView alloc] init];
169
170 _view.autoresizingMask =
171 UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin |
172 UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
173
174 _blocks = [[NSMutableArray alloc] init];
175
176 [[NSNotificationCenter defaultCenter]
177 addObserver:self
178 selector:@selector(setupDisplay)
179 name:UIApplicationDidChangeStatusBarOrientationNotification
180 object:nil];
181
182 if ([self class] == [BlockAlertView class])
183 [self setupDisplay];
184
185 _vignetteBackground = NO;
186 }
187
188 return self;
189}
190
191- (void)dealloc
192{
193 [_title release];
194 [_message release];
195 [_backgroundImage release];
196 [_view release];
197 [_blocks release];
198 [super dealloc];
199}
200
202#pragma mark - Public
203
204- (void)addButtonWithTitle:(NSString *)title color:(NSString *)color block:(void (^)())block
205{
206 [_blocks addObject:[NSArray arrayWithObjects:block ? [[block copy] autorelease] : [NSNull null],
207 title, color, nil]];
208}
209
210- (void)addButtonWithTitle:(NSString *)title block:(void (^)())block
211{
212 [self addButtonWithTitle:title color:@"gray" block:block];
213}
214
215- (void)setCancelButtonWithTitle:(NSString *)title block:(void (^)())block
216{
217 [self addButtonWithTitle:title color:@"black" block:block];
218}
219
220- (void)setDestructiveButtonWithTitle:(NSString *)title block:(void (^)())block
221{
222 [self addButtonWithTitle:title color:@"red" block:block];
223}
224
225- (void)show
226{
227 _shown = YES;
228
229 BOOL isSecondButton = NO;
230 NSUInteger index = 0;
231 for (NSUInteger i = 0; i < _blocks.count; i++)
232 {
233 NSArray *block = [_blocks objectAtIndex:i];
234 NSString *title = [block objectAtIndex:1];
235 NSString *color = [block objectAtIndex:2];
236
237 UIImage *image =
238 [UIImage imageNamed:[NSString stringWithFormat:@"alert-%@-button.png", color]];
239 image = [image stretchableImageWithLeftCapWidth:(int)(image.size.width + 1) >> 1
240 topCapHeight:0];
241
242 CGFloat maxHalfWidth = floorf((_view.bounds.size.width - kAlertViewBorder * 3) * 0.5);
243 CGFloat width = _view.bounds.size.width - kAlertViewBorder * 2;
244 CGFloat xOffset = kAlertViewBorder;
245 if (isSecondButton)
246 {
247 width = maxHalfWidth;
248 xOffset = width + kAlertViewBorder * 2;
249 isSecondButton = NO;
250 }
251 else if (i + 1 < _blocks.count)
252 {
253 // In this case there's another button.
254 // Let's check if they fit on the same line.
255 CGSize size = [title sizeWithFont:buttonFont
256 minFontSize:10
257 actualFontSize:nil
258 forWidth:_view.bounds.size.width - kAlertViewBorder * 2
259 lineBreakMode:NSLineBreakByClipping];
260
261 if (size.width < maxHalfWidth - kAlertViewBorder)
262 {
263 // It might fit. Check the next Button
264 NSArray *block2 = [_blocks objectAtIndex:i + 1];
265 NSString *title2 = [block2 objectAtIndex:1];
266 size = [title2 sizeWithFont:buttonFont
267 minFontSize:10
268 actualFontSize:nil
269 forWidth:_view.bounds.size.width - kAlertViewBorder * 2
270 lineBreakMode:NSLineBreakByClipping];
271
272 if (size.width < maxHalfWidth - kAlertViewBorder)
273 {
274 // They'll fit!
275 isSecondButton = YES; // For the next iteration
276 width = maxHalfWidth;
277 }
278 }
279 }
280 else if (_blocks.count == 1)
281 {
282 // In this case this is the only button. We'll size according to the text
283 CGSize size = [title sizeWithFont:buttonFont
284 minFontSize:10
285 actualFontSize:nil
286 forWidth:_view.bounds.size.width - kAlertViewBorder * 2
287 lineBreakMode:UILineBreakModeClip];
288
289 size.width = MAX(size.width, 80);
290 if (size.width + 2 * kAlertViewBorder < width)
291 {
292 width = size.width + 2 * kAlertViewBorder;
293 xOffset = floorf((_view.bounds.size.width - width) * 0.5);
294 }
295 }
296
297 UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
298 button.frame = CGRectMake(xOffset, _height, width, kAlertButtonHeight);
299 button.titleLabel.font = buttonFont;
300 if (IOS_LESS_THAN_6)
301 {
302#pragma clang diagnostic push
303#pragma clang diagnostic ignored "-Wdeprecated-declarations"
304 button.titleLabel.minimumFontSize = 10;
305#pragma clang diagnostic pop
306 }
307 else
308 {
309 button.titleLabel.adjustsFontSizeToFitWidth = YES;
310 button.titleLabel.adjustsLetterSpacingToFitWidth = YES;
311 button.titleLabel.minimumScaleFactor = 0.1;
312 }
313 button.titleLabel.textAlignment = NSTextAlignmentCenter;
314 button.titleLabel.shadowOffset = kAlertViewButtonShadowOffset;
315 button.backgroundColor = [UIColor clearColor];
316 button.tag = i + 1;
317
318 [button setBackgroundImage:image forState:UIControlStateNormal];
319 [button setTitleColor:kAlertViewButtonTextColor forState:UIControlStateNormal];
320 [button setTitleShadowColor:kAlertViewButtonShadowColor forState:UIControlStateNormal];
321 [button setTitle:title forState:UIControlStateNormal];
322 button.accessibilityLabel = title;
323
324 [button addTarget:self
325 action:@selector(buttonClicked:)
326 forControlEvents:UIControlEventTouchUpInside];
327
328 [_view addSubview:button];
329
330 if (!isSecondButton)
331 _height += kAlertButtonHeight + kAlertViewBorder;
332
333 index++;
334 }
335
336 _height += 10; // Margin for the shadow
337
338 if (_height < background.size.height)
339 {
340 CGFloat offset = background.size.height - _height;
341 _height = background.size.height;
342 CGRect frame;
343 for (NSUInteger i = 0; i < _blocks.count; i++)
344 {
345 UIButton *btn = (UIButton *)[_view viewWithTag:i + 1];
346 frame = btn.frame;
347 frame.origin.y += offset;
348 btn.frame = frame;
349 }
350 }
351
352 CGRect frame = _view.frame;
353 frame.origin.y = -_height;
354 frame.size.height = _height;
355 _view.frame = frame;
356
357 UIImageView *modalBackground = [[UIImageView alloc] initWithFrame:_view.bounds];
358
359 if (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation]))
360 modalBackground.image = backgroundlandscape;
361 else
362 modalBackground.image = background;
363
364 modalBackground.contentMode = UIViewContentModeScaleToFill;
365 modalBackground.autoresizingMask =
366 UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
367 [_view insertSubview:modalBackground atIndex:0];
368 [modalBackground release];
369
370 if (_backgroundImage)
371 {
372 [BlockBackground sharedInstance].backgroundImage = _backgroundImage;
373 [_backgroundImage release];
374 _backgroundImage = nil;
375 }
376
377 [BlockBackground sharedInstance].vignetteBackground = _vignetteBackground;
378 [[BlockBackground sharedInstance] addToMainWindow:_view];
379
380 __block CGPoint center = _view.center;
381 center.y = floorf([BlockBackground sharedInstance].bounds.size.height * 0.5) + kAlertViewBounce;
382
383 _cancelBounce = NO;
384
385 [UIView animateWithDuration:0.4
386 delay:0.0
387 options:UIViewAnimationCurveEaseOut
388 animations:^{
389 [BlockBackground sharedInstance].alpha = 1.0f;
390 _view.center = center;
391 }
392 completion:^(BOOL finished) {
393 if (_cancelBounce)
394 return;
395
396 [UIView animateWithDuration:0.1
397 delay:0.0
398 options:0
399 animations:^{
400 center.y -= kAlertViewBounce;
401 _view.center = center;
402 }
403 completion:^(BOOL finished) {
404 [[NSNotificationCenter defaultCenter]
405 postNotificationName:@"AlertViewFinishedAnimations"
406 object:nil];
407 }];
408 }];
409
410 [self retain];
411}
412
413- (void)dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated
414{
415 _shown = NO;
416
417 [[NSNotificationCenter defaultCenter] removeObserver:self];
418
419 if (buttonIndex >= 0 && buttonIndex < [_blocks count])
420 {
421 id obj = [[_blocks objectAtIndex:buttonIndex] objectAtIndex:0];
422 if (![obj isEqual:[NSNull null]])
423 {
424 ((void (^)())obj)();
425 }
426 }
427
428 if (animated)
429 {
430 [UIView animateWithDuration:0.1
431 delay:0.0
432 options:0
433 animations:^{
434 CGPoint center = _view.center;
435 center.y += 20;
436 _view.center = center;
437 }
438 completion:^(BOOL finished) {
439 [UIView animateWithDuration:0.4
440 delay:0.0
441 options:UIViewAnimationCurveEaseIn
442 animations:^{
443 CGRect frame = _view.frame;
444 frame.origin.y = -frame.size.height;
445 _view.frame = frame;
446 [[BlockBackground sharedInstance] reduceAlphaIfEmpty];
447 }
448 completion:^(BOOL finished) {
449 [[BlockBackground sharedInstance] removeView:_view];
450 [_view release];
451 _view = nil;
452 [self autorelease];
453 }];
454 }];
455 }
456 else
457 {
458 [[BlockBackground sharedInstance] removeView:_view];
459 [_view release];
460 _view = nil;
461 [self autorelease];
462 }
463}
464
466#pragma mark - Action
467
468- (void)buttonClicked:(id)sender
469{
470 /* Run the button's block */
471 int buttonIndex = [sender tag] - 1;
472 [self dismissWithClickedButtonIndex:buttonIndex animated:YES];
473}
474
475@end