Playlist Generator  1.0
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Properties Defines
MBProgressHUD.m
Go to the documentation of this file.
00001 //
00002 // MBProgressHUD.m
00003 // Version 0.4
00004 // Created by Matej Bukovinski on 2.4.09.
00005 //
00006 
00007 #import "MBProgressHUD.h"
00008 
00009 @interface MBProgressHUD ()
00010 
00011 - (void)hideUsingAnimation:(BOOL)animated;
00012 - (void)showUsingAnimation:(BOOL)animated;
00013 - (void)done;
00014 - (void)updateLabelText:(NSString *)newText;
00015 - (void)updateDetailsLabelText:(NSString *)newText;
00016 - (void)updateProgress;
00017 - (void)updateIndicators;
00018 - (void)handleGraceTimer:(NSTimer *)theTimer;
00019 - (void)handleMinShowTimer:(NSTimer *)theTimer;
00020 - (void)setTransformForCurrentOrientation:(BOOL)animated;
00021 - (void)cleanUp;
00022 - (void)deviceOrientationDidChange:(NSNotification*)notification;
00023 - (void)launchExecution;
00024 - (void)deviceOrientationDidChange:(NSNotification *)notification;
00025 - (void)hideDelayed:(NSNumber *)animated;
00026 - (void)launchExecution;
00027 - (void)cleanUp;
00028 
00029 @property (retain) UIView *indicator;
00030 @property (assign) float width;
00031 @property (assign) float height;
00032 @property (retain) NSTimer *graceTimer;
00033 @property (retain) NSTimer *minShowTimer;
00034 @property (retain) NSDate *showStarted;
00035 
00036 @end
00037 
00038 
00039 @implementation MBProgressHUD
00040 
00041 #pragma mark -
00042 #pragma mark Accessors
00043 
00044 @synthesize animationType;
00045 
00046 @synthesize delegate;
00047 @synthesize opacity;
00048 @synthesize labelFont;
00049 @synthesize detailsLabelFont;
00050 
00051 @synthesize indicator;
00052 
00053 @synthesize width;
00054 @synthesize height;
00055 @synthesize xOffset;
00056 @synthesize yOffset;
00057 @synthesize minSize;
00058 @synthesize square;
00059 @synthesize margin;
00060 @synthesize dimBackground;
00061 
00062 @synthesize graceTime;
00063 @synthesize minShowTime;
00064 @synthesize graceTimer;
00065 @synthesize minShowTimer;
00066 @synthesize taskInProgress;
00067 @synthesize removeFromSuperViewOnHide;
00068 
00069 @synthesize customView;
00070 
00071 @synthesize showStarted;
00072 
00073 - (void)setMode:(MBProgressHUDMode)newMode {
00074     // Dont change mode if it wasn't actually changed to prevent flickering
00075     if (mode && (mode == newMode)) {
00076         return;
00077     }
00078         
00079     mode = newMode;
00080         
00081         if ([NSThread isMainThread]) {
00082                 [self updateIndicators];
00083                 [self setNeedsLayout];
00084                 [self setNeedsDisplay];
00085         } else {
00086                 [self performSelectorOnMainThread:@selector(updateIndicators) withObject:nil waitUntilDone:NO];
00087                 [self performSelectorOnMainThread:@selector(setNeedsLayout) withObject:nil waitUntilDone:NO];
00088                 [self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
00089         }
00090 }
00091 
00092 - (MBProgressHUDMode)mode {
00093         return mode;
00094 }
00095 
00096 - (void)setLabelText:(NSString *)newText {
00097         if ([NSThread isMainThread]) {
00098                 [self updateLabelText:newText];
00099                 [self setNeedsLayout];
00100                 [self setNeedsDisplay];
00101         } else {
00102                 [self performSelectorOnMainThread:@selector(updateLabelText:) withObject:newText waitUntilDone:NO];
00103                 [self performSelectorOnMainThread:@selector(setNeedsLayout) withObject:nil waitUntilDone:NO];
00104                 [self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
00105         }
00106 }
00107 
00108 - (NSString *)labelText {
00109         return labelText;
00110 }
00111 
00112 - (void)setDetailsLabelText:(NSString *)newText {
00113         if ([NSThread isMainThread]) {
00114                 [self updateDetailsLabelText:newText];
00115                 [self setNeedsLayout];
00116                 [self setNeedsDisplay];
00117         } else {
00118                 [self performSelectorOnMainThread:@selector(updateDetailsLabelText:) withObject:newText waitUntilDone:NO];
00119                 [self performSelectorOnMainThread:@selector(setNeedsLayout) withObject:nil waitUntilDone:NO];
00120                 [self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
00121         }
00122 }
00123 
00124 - (NSString *)detailsLabelText {
00125         return detailsLabelText;
00126 }
00127 
00128 - (void)setProgress:(float)newProgress {
00129     progress = newProgress;
00130         
00131     // Update display ony if showing the determinate progress view
00132     if (mode == MBProgressHUDModeDeterminate) {
00133                 if ([NSThread isMainThread]) {
00134                         [self updateProgress];
00135                         [self setNeedsDisplay];
00136                 } else {
00137                         [self performSelectorOnMainThread:@selector(updateProgress) withObject:nil waitUntilDone:NO];
00138                         [self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
00139                 }
00140     }
00141 }
00142 
00143 - (float)progress {
00144         return progress;
00145 }
00146 
00147 #pragma mark -
00148 #pragma mark Accessor helpers
00149 
00150 - (void)updateLabelText:(NSString *)newText {
00151     if (labelText != newText) {
00152         [labelText release];
00153         labelText = [newText copy];
00154     }
00155 }
00156 
00157 - (void)updateDetailsLabelText:(NSString *)newText {
00158     if (detailsLabelText != newText) {
00159         [detailsLabelText release];
00160         detailsLabelText = [newText copy];
00161     }
00162 }
00163 
00164 - (void)updateProgress {
00165     [(MBRoundProgressView *)indicator setProgress:progress];
00166 }
00167 
00168 - (void)updateIndicators {
00169     if (indicator) {
00170         [indicator removeFromSuperview];
00171     }
00172         
00173     if (mode == MBProgressHUDModeDeterminate) {
00174         self.indicator = [[[MBRoundProgressView alloc] init] autorelease];
00175     }
00176     else if (mode == MBProgressHUDModeCustomView && self.customView != nil){
00177         self.indicator = self.customView;
00178     } else {
00179                 self.indicator = [[[UIActivityIndicatorView alloc]
00180                                                    initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge] autorelease];
00181         [(UIActivityIndicatorView *)indicator startAnimating];
00182         }
00183         
00184         
00185     [self addSubview:indicator];
00186 }
00187 
00188 #pragma mark -
00189 #pragma mark Constants
00190 
00191 #define PADDING 4.0f
00192 
00193 #define LABELFONTSIZE 16.0f
00194 #define LABELDETAILSFONTSIZE 12.0f
00195 
00196 #pragma mark -
00197 #pragma mark Class methods
00198 
00199 + (MBProgressHUD *)showHUDAddedTo:(UIView *)view animated:(BOOL)animated {
00200         MBProgressHUD *hud = [[MBProgressHUD alloc] initWithView:view];
00201         [view addSubview:hud];
00202         [hud show:animated];
00203         return [hud autorelease];
00204 }
00205 
00206 + (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated {
00207         UIView *viewToRemove = nil;
00208         for (UIView *v in [view subviews]) {
00209                 if ([v isKindOfClass:[MBProgressHUD class]]) {
00210                         viewToRemove = v;
00211                 }
00212         }
00213         if (viewToRemove != nil) {
00214                 MBProgressHUD *HUD = (MBProgressHUD *)viewToRemove;
00215                 HUD.removeFromSuperViewOnHide = YES;
00216                 [HUD hide:animated];
00217                 return YES;
00218         } else {
00219                 return NO;
00220         }
00221 }
00222 
00223 
00224 #pragma mark -
00225 #pragma mark Lifecycle methods
00226 
00227 - (id)initWithWindow:(UIWindow *)window {
00228     return [self initWithView:window];
00229 }
00230 
00231 - (id)initWithView:(UIView *)view {
00232         // Let's check if the view is nil (this is a common error when using the windw initializer above)
00233         if (!view) {
00234                 [NSException raise:@"MBProgressHUDViewIsNillException" 
00235                                         format:@"The view used in the MBProgressHUD initializer is nil."];
00236         }
00237         id me = [self initWithFrame:view.bounds];
00238         // We need to take care of rotation ourselfs if we're adding the HUD to a window
00239         if ([view isKindOfClass:[UIWindow class]]) {
00240                 [self setTransformForCurrentOrientation:NO];
00241         }
00242         [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:) 
00243                                                                                                  name:UIDeviceOrientationDidChangeNotification object:nil];
00244         
00245         return me;
00246 }
00247 
00248 - (id)initWithFrame:(CGRect)frame {
00249     self = [super initWithFrame:frame];
00250         if (self) {
00251         // Set default values for properties
00252         self.animationType = MBProgressHUDAnimationFade;
00253         self.mode = MBProgressHUDModeIndeterminate;
00254         self.labelText = nil;
00255         self.detailsLabelText = nil;
00256         self.opacity = 0.8f;
00257         self.labelFont = [UIFont boldSystemFontOfSize:LABELFONTSIZE];
00258         self.detailsLabelFont = [UIFont boldSystemFontOfSize:LABELDETAILSFONTSIZE];
00259         self.xOffset = 0.0f;
00260         self.yOffset = 0.0f;
00261                 self.dimBackground = NO;
00262                 self.margin = 20.0f;
00263                 self.graceTime = 0.0f;
00264                 self.minShowTime = 0.0f;
00265                 self.removeFromSuperViewOnHide = NO;
00266                 self.minSize = CGSizeZero;
00267                 self.square = NO;
00268                 
00269                 self.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
00270                 
00271         // Transparent background
00272         self.opaque = NO;
00273         self.backgroundColor = [UIColor clearColor];
00274                 
00275         // Make invisible for now
00276         self.alpha = 0.0f;
00277                 
00278         // Add label
00279         label = [[UILabel alloc] initWithFrame:self.bounds];
00280                 
00281         // Add details label
00282         detailsLabel = [[UILabel alloc] initWithFrame:self.bounds];
00283                 
00284                 taskInProgress = NO;
00285                 rotationTransform = CGAffineTransformIdentity;
00286     }
00287     return self;
00288 }
00289 
00290 - (void)dealloc {
00291         [[NSNotificationCenter defaultCenter] removeObserver:self];
00292         
00293     [indicator release];
00294     [label release];
00295     [detailsLabel release];
00296     [labelText release];
00297     [detailsLabelText release];
00298         [graceTimer release];
00299         [minShowTimer release];
00300         [showStarted release];
00301         [customView release];
00302     [super dealloc];
00303 }
00304 
00305 #pragma mark -
00306 #pragma mark Layout
00307 
00308 - (void)layoutSubviews {
00309     CGRect frame = self.bounds;
00310         
00311     // Compute HUD dimensions based on indicator size (add margin to HUD border)
00312     CGRect indFrame = indicator.bounds;
00313     self.width = indFrame.size.width + 2 * margin;
00314     self.height = indFrame.size.height + 2 * margin;
00315         
00316     // Position the indicator
00317     indFrame.origin.x = floorf((frame.size.width - indFrame.size.width) / 2) + self.xOffset;
00318     indFrame.origin.y = floorf((frame.size.height - indFrame.size.height) / 2) + self.yOffset;
00319     indicator.frame = indFrame;
00320         
00321     // Add label if label text was set
00322     if (nil != self.labelText) {
00323         // Get size of label text
00324         CGSize dims = [self.labelText sizeWithFont:self.labelFont];
00325                 
00326         // Compute label dimensions based on font metrics if size is larger than max then clip the label width
00327         float lHeight = dims.height;
00328         float lWidth;
00329         if (dims.width <= (frame.size.width - 4 * margin)) {
00330             lWidth = dims.width;
00331         }
00332         else {
00333             lWidth = frame.size.width - 4 * margin;
00334         }
00335                 
00336         // Set label properties
00337         label.font = self.labelFont;
00338         label.adjustsFontSizeToFitWidth = NO;
00339         label.textAlignment = UITextAlignmentCenter;
00340         label.opaque = NO;
00341         label.backgroundColor = [UIColor clearColor];
00342         label.textColor = [UIColor whiteColor];
00343         label.text = self.labelText;
00344                 
00345         // Update HUD size
00346         if (self.width < (lWidth + 2 * margin)) {
00347             self.width = lWidth + 2 * margin;
00348         }
00349         self.height = self.height + lHeight + PADDING;
00350                 
00351         // Move indicator to make room for the label
00352         indFrame.origin.y -= (floorf(lHeight / 2 + PADDING / 2));
00353         indicator.frame = indFrame;
00354                 
00355         // Set the label position and dimensions
00356         CGRect lFrame = CGRectMake(floorf((frame.size.width - lWidth) / 2) + xOffset,
00357                                    floorf(indFrame.origin.y + indFrame.size.height + PADDING),
00358                                    lWidth, lHeight);
00359         label.frame = lFrame;
00360                 
00361         [self addSubview:label];
00362                 
00363         // Add details label delatils text was set
00364         if (nil != self.detailsLabelText) {
00365                         
00366             // Set label properties
00367             detailsLabel.font = self.detailsLabelFont;
00368             detailsLabel.adjustsFontSizeToFitWidth = NO;
00369             detailsLabel.textAlignment = UITextAlignmentCenter;
00370             detailsLabel.opaque = NO;
00371             detailsLabel.backgroundColor = [UIColor clearColor];
00372             detailsLabel.textColor = [UIColor whiteColor];
00373             detailsLabel.text = self.detailsLabelText;
00374             detailsLabel.numberOfLines = 0;
00375 
00376                         CGFloat maxHeight = frame.size.height - self.height - 2*margin;
00377                         CGSize labelSize = [detailsLabel.text sizeWithFont:detailsLabel.font constrainedToSize:CGSizeMake(frame.size.width - 4*margin, maxHeight) lineBreakMode:detailsLabel.lineBreakMode];
00378             lHeight = labelSize.height;
00379             lWidth = labelSize.width;
00380                         
00381             // Update HUD size
00382             if (self.width < lWidth) {
00383                 self.width = lWidth + 2 * margin;
00384             }
00385             self.height = self.height + lHeight + PADDING;
00386                         
00387             // Move indicator to make room for the new label
00388             indFrame.origin.y -= (floorf(lHeight / 2 + PADDING / 2));
00389             indicator.frame = indFrame;
00390                         
00391             // Move first label to make room for the new label
00392             lFrame.origin.y -= (floorf(lHeight / 2 + PADDING / 2));
00393             label.frame = lFrame;
00394                         
00395             // Set label position and dimensions
00396             CGRect lFrameD = CGRectMake(floorf((frame.size.width - lWidth) / 2) + xOffset,
00397                                         lFrame.origin.y + lFrame.size.height + PADDING, lWidth, lHeight);
00398             detailsLabel.frame = lFrameD;
00399                         
00400             [self addSubview:detailsLabel];
00401         }
00402     }
00403         
00404         if (square) {
00405                 CGFloat max = MAX(self.width, self.height);
00406                 if (max <= frame.size.width - 2*margin) {
00407                         self.width = max;
00408                 }
00409                 if (max <= frame.size.height - 2*margin) {
00410                         self.height = max;
00411                 }
00412         }
00413         
00414         if (self.width < minSize.width) {
00415                 self.width = minSize.width;
00416         } 
00417         if (self.height < minSize.height) {
00418                 self.height = minSize.height;
00419         }
00420 }
00421 
00422 #pragma mark -
00423 #pragma mark Showing and execution
00424 
00425 - (void)show:(BOOL)animated {
00426         useAnimation = animated;
00427         
00428         // If the grace time is set postpone the HUD display
00429         if (self.graceTime > 0.0) {
00430                 self.graceTimer = [NSTimer scheduledTimerWithTimeInterval:self.graceTime 
00431                                                                                                                    target:self 
00432                                                                                                                  selector:@selector(handleGraceTimer:) 
00433                                                                                                                  userInfo:nil 
00434                                                                                                                   repeats:NO];
00435         } 
00436         // ... otherwise show the HUD imediately 
00437         else {
00438                 [self setNeedsDisplay];
00439                 [self showUsingAnimation:useAnimation];
00440         }
00441 }
00442 
00443 - (void)hide:(BOOL)animated {
00444         useAnimation = animated;
00445         
00446         // If the minShow time is set, calculate how long the hud was shown,
00447         // and pospone the hiding operation if necessary
00448         if (self.minShowTime > 0.0 && showStarted) {
00449                 NSTimeInterval interv = [[NSDate date] timeIntervalSinceDate:showStarted];
00450                 if (interv < self.minShowTime) {
00451                         self.minShowTimer = [NSTimer scheduledTimerWithTimeInterval:(self.minShowTime - interv) 
00452                                                                                                                                  target:self 
00453                                                                                                                            selector:@selector(handleMinShowTimer:) 
00454                                                                                                                            userInfo:nil 
00455                                                                                                                                 repeats:NO];
00456                         return;
00457                 } 
00458         }
00459         
00460         // ... otherwise hide the HUD immediately
00461     [self hideUsingAnimation:useAnimation];
00462 }
00463 
00464 - (void)hide:(BOOL)animated afterDelay:(NSTimeInterval)delay {
00465         [self performSelector:@selector(hideDelayed:) withObject:[NSNumber numberWithBool:delay] afterDelay:delay];
00466 }
00467 
00468 - (void)hideDelayed:(NSNumber *)animated {
00469         [self hide:[animated boolValue]];
00470 }
00471 
00472 - (void)handleGraceTimer:(NSTimer *)theTimer {
00473         // Show the HUD only if the task is still running
00474         if (taskInProgress) {
00475                 [self setNeedsDisplay];
00476                 [self showUsingAnimation:useAnimation];
00477         }
00478 }
00479 
00480 - (void)handleMinShowTimer:(NSTimer *)theTimer {
00481         [self hideUsingAnimation:useAnimation];
00482 }
00483 
00484 - (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated {
00485         
00486     methodForExecution = method;
00487     targetForExecution = [target retain];
00488     objectForExecution = [object retain];
00489         
00490     // Launch execution in new thread
00491         taskInProgress = YES;
00492     [NSThread detachNewThreadSelector:@selector(launchExecution) toTarget:self withObject:nil];
00493         
00494         // Show HUD view
00495         [self show:animated];
00496 }
00497 
00498 - (void)launchExecution {
00499     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
00500         
00501     // Start executing the requested task
00502     [targetForExecution performSelector:methodForExecution withObject:objectForExecution];
00503         
00504     // Task completed, update view in main thread (note: view operations should
00505     // be done only in the main thread)
00506     [self performSelectorOnMainThread:@selector(cleanUp) withObject:nil waitUntilDone:NO];
00507         
00508     [pool release];
00509 }
00510 
00511 - (void)animationFinished:(NSString *)animationID finished:(BOOL)finished context:(void*)context {
00512     [self done];
00513 }
00514 
00515 - (void)done {
00516     isFinished = YES;
00517         
00518     // If delegate was set make the callback
00519     self.alpha = 0.0f;
00520     
00521         if(delegate != nil) {
00522         if ([delegate respondsToSelector:@selector(hudWasHidden:)]) {
00523             [delegate performSelector:@selector(hudWasHidden:) withObject:self];
00524         } else if ([delegate respondsToSelector:@selector(hudWasHidden)]) {
00525             [delegate performSelector:@selector(hudWasHidden)];
00526         }
00527         }
00528         
00529         if (removeFromSuperViewOnHide) {
00530                 [self removeFromSuperview];
00531         }
00532 }
00533 
00534 - (void)cleanUp {
00535         taskInProgress = NO;
00536         
00537         self.indicator = nil;
00538         
00539     [targetForExecution release];
00540     [objectForExecution release];
00541         
00542     [self hide:useAnimation];
00543 }
00544 
00545 #pragma mark -
00546 #pragma mark Fade in and Fade out
00547 
00548 - (void)showUsingAnimation:(BOOL)animated {
00549     self.alpha = 0.0f;
00550     if (animated && animationType == MBProgressHUDAnimationZoom) {
00551         self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(1.5f, 1.5f));
00552     }
00553     
00554         self.showStarted = [NSDate date];
00555     // Fade in
00556     if (animated) {
00557         [UIView beginAnimations:nil context:NULL];
00558         [UIView setAnimationDuration:0.30];
00559         self.alpha = 1.0f;
00560         if (animationType == MBProgressHUDAnimationZoom) {
00561             self.transform = rotationTransform;
00562         }
00563         [UIView commitAnimations];
00564     }
00565     else {
00566         self.alpha = 1.0f;
00567     }
00568 }
00569 
00570 - (void)hideUsingAnimation:(BOOL)animated {
00571     // Fade out
00572     if (animated) {
00573         [UIView beginAnimations:nil context:NULL];
00574         [UIView setAnimationDuration:0.30];
00575         [UIView setAnimationDelegate:self];
00576         [UIView setAnimationDidStopSelector:@selector(animationFinished: finished: context:)];
00577         // 0.02 prevents the hud from passing through touches during the animation the hud will get completely hidden
00578         // in the done method
00579         if (animationType == MBProgressHUDAnimationZoom) {
00580             self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(0.5f, 0.5f));
00581         }
00582         self.alpha = 0.02f;
00583         [UIView commitAnimations];
00584     }
00585     else {
00586         self.alpha = 0.0f;
00587         [self done];
00588     }
00589 }
00590 
00591 #pragma mark BG Drawing
00592 
00593 - (void)drawRect:(CGRect)rect {
00594         
00595     CGContextRef context = UIGraphicsGetCurrentContext();
00596 
00597     if (dimBackground) {
00598         //Gradient colours
00599         size_t gradLocationsNum = 2;
00600         CGFloat gradLocations[2] = {0.0f, 1.0f};
00601         CGFloat gradColors[8] = {0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.75f}; 
00602         CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
00603         CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradColors, gradLocations, gradLocationsNum);
00604                 CGColorSpaceRelease(colorSpace);
00605         
00606         //Gradient center
00607         CGPoint gradCenter= CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
00608         //Gradient radius
00609         float gradRadius = MIN(self.bounds.size.width , self.bounds.size.height) ;
00610         //Gradient draw
00611         CGContextDrawRadialGradient (context, gradient, gradCenter,
00612                                      0, gradCenter, gradRadius,
00613                                      kCGGradientDrawsAfterEndLocation);
00614                 CGGradientRelease(gradient);
00615     }    
00616     
00617     // Center HUD
00618     CGRect allRect = self.bounds;
00619     // Draw rounded HUD bacgroud rect
00620     CGRect boxRect = CGRectMake(roundf((allRect.size.width - self.width) / 2) + self.xOffset,
00621                                 roundf((allRect.size.height - self.height) / 2) + self.yOffset, self.width, self.height);
00622         // Corner radius
00623         float radius = 10.0f;
00624         
00625     CGContextBeginPath(context);
00626     CGContextSetGrayFillColor(context, 0.0f, self.opacity);
00627     CGContextMoveToPoint(context, CGRectGetMinX(boxRect) + radius, CGRectGetMinY(boxRect));
00628     CGContextAddArc(context, CGRectGetMaxX(boxRect) - radius, CGRectGetMinY(boxRect) + radius, radius, 3 * (float)M_PI / 2, 0, 0);
00629     CGContextAddArc(context, CGRectGetMaxX(boxRect) - radius, CGRectGetMaxY(boxRect) - radius, radius, 0, (float)M_PI / 2, 0);
00630     CGContextAddArc(context, CGRectGetMinX(boxRect) + radius, CGRectGetMaxY(boxRect) - radius, radius, (float)M_PI / 2, (float)M_PI, 0);
00631     CGContextAddArc(context, CGRectGetMinX(boxRect) + radius, CGRectGetMinY(boxRect) + radius, radius, (float)M_PI, 3 * (float)M_PI / 2, 0);
00632     CGContextClosePath(context);
00633     CGContextFillPath(context);
00634 }
00635 
00636 #pragma mark -
00637 #pragma mark Manual oritentation change
00638 
00639 #define RADIANS(degrees) ((degrees * (float)M_PI) / 180.0f)
00640 
00641 - (void)deviceOrientationDidChange:(NSNotification *)notification { 
00642         if (!self.superview) {
00643                 return;
00644         }
00645         
00646         if ([self.superview isKindOfClass:[UIWindow class]]) {
00647                 [self setTransformForCurrentOrientation:YES];
00648         } else {
00649                 self.bounds = self.superview.bounds;
00650                 [self setNeedsDisplay];
00651         }
00652 }
00653 
00654 - (void)setTransformForCurrentOrientation:(BOOL)animated {
00655         UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
00656         NSInteger degrees = 0;
00657         
00658         // Stay in sync with the superview
00659         if (self.superview) {
00660                 self.bounds = self.superview.bounds;
00661                 [self setNeedsDisplay];
00662         }
00663         
00664         if (UIInterfaceOrientationIsLandscape(orientation)) {
00665                 if (orientation == UIInterfaceOrientationLandscapeLeft) { degrees = -90; } 
00666                 else { degrees = 90; }
00667                 // Window coordinates differ!
00668                 self.bounds = CGRectMake(0, 0, self.bounds.size.height, self.bounds.size.width);
00669         } else {
00670                 if (orientation == UIInterfaceOrientationPortraitUpsideDown) { degrees = 180; } 
00671                 else { degrees = 0; }
00672         }
00673         
00674         rotationTransform = CGAffineTransformMakeRotation(RADIANS(degrees));
00675 
00676         if (animated) {
00677                 [UIView beginAnimations:nil context:nil];
00678         }
00679         [self setTransform:rotationTransform];
00680         if (animated) {
00681                 [UIView commitAnimations];
00682         }
00683 }
00684 
00685 @end
00686 
00688 
00689 @implementation MBRoundProgressView
00690 
00691 #pragma mark -
00692 #pragma mark Accessors
00693 
00694 - (float)progress {
00695     return _progress;
00696 }
00697 
00698 - (void)setProgress:(float)progress {
00699     _progress = progress;
00700     [self setNeedsDisplay];
00701 }
00702 
00703 #pragma mark -
00704 #pragma mark Lifecycle
00705 
00706 - (id)init {
00707     return [self initWithFrame:CGRectMake(0.0f, 0.0f, 37.0f, 37.0f)];
00708 }
00709 
00710 - (id)initWithFrame:(CGRect)frame {
00711     self = [super initWithFrame:frame];
00712     if (self) {
00713         self.backgroundColor = [UIColor clearColor];
00714                 self.opaque = NO;
00715     }
00716     return self;
00717 }
00718 
00719 #pragma mark -
00720 #pragma mark Drawing
00721 
00722 - (void)drawRect:(CGRect)rect {
00723     
00724     CGRect allRect = self.bounds;
00725     CGRect circleRect = CGRectInset(allRect, 2.0f, 2.0f);
00726     
00727     CGContextRef context = UIGraphicsGetCurrentContext();
00728     
00729     // Draw background
00730     CGContextSetRGBStrokeColor(context, 1.0f, 1.0f, 1.0f, 1.0f); // white
00731     CGContextSetRGBFillColor(context, 1.0f, 1.0f, 1.0f, 0.1f); // translucent white
00732     CGContextSetLineWidth(context, 2.0f);
00733     CGContextFillEllipseInRect(context, circleRect);
00734     CGContextStrokeEllipseInRect(context, circleRect);
00735     
00736     // Draw progress
00737     CGPoint center = CGPointMake(allRect.size.width / 2, allRect.size.height / 2);
00738     CGFloat radius = (allRect.size.width - 4) / 2;
00739     CGFloat startAngle = - ((float)M_PI / 2); // 90 degrees
00740     CGFloat endAngle = (self.progress * 2 * (float)M_PI) + startAngle;
00741     CGContextSetRGBFillColor(context, 1.0f, 1.0f, 1.0f, 1.0f); // white
00742     CGContextMoveToPoint(context, center.x, center.y);
00743     CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, 0);
00744     CGContextClosePath(context);
00745     CGContextFillPath(context);
00746 }
00747 
00748 @end
00749