Main Page | Alphabetical List | Class List | Directories | File List | Class Members | Related Pages

DownAndOutView.m

00001 //
00002 //  DownAndOutView.m
00003 //  DownAndOutª
00004 //
00005 //  Created by Fritz Anderson on Mon Aug 18 2003.
00006 //  Copyright (c) 2003 Trustees of the University of Chicago. All rights reserved.
00007 //  This program is free software; you can redistribute it and/or modify
00008 //  it under the terms of the GNU General Public License as published by
00009 //  the Free Software Foundation; either version 2 of the License, or
00010 //  (at your option) any later version.
00011 //  
00012 //  This program is distributed in the hope that it will be useful,
00013 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 //  GNU General Public License for more details.
00016 //  
00017 //  You should have received a copy of the GNU General Public License
00018 //  along with this program; if not, write to the Free Software
00019 //  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00020 //
00021 
00022 #import "DownAndOutView.h"
00023 #import "DownAndOutController.h"
00024 #import "DAApplication.h"
00025 
00026 #define CLOCK_RADIUS    clockRadius
00027 #define CLOCK_WIDTH     (2.0 * CLOCK_RADIUS + 3.0)
00028 #define CONTENT_HEIGHT  (2.0 * CLOCK_RADIUS)
00029 #define FIXED_WIDTH     (3.0 + 7.0 * CLOCK_RADIUS)
00030 
00031 #define MAX_V_COMPONENT 1.3
00032 
00033 
00034 @implementation DownAndOutView
00035 
00039 - (void) setDeadlineForSeconds: (int) seconds
00040 {
00041     [deadline release];
00042     secondsLeft = seconds;
00043     deadline = [[NSDate dateWithTimeIntervalSinceNow: secondsLeft] retain];
00044 }
00045 
00048 - (void) resetClock
00049 {
00050     [self setDeadlineForSeconds: [controller secondsBeforeLogout]];
00051 }
00052 
00059 - (id) initWithFrame: (NSRect) frame isPreview: (BOOL) isPreview
00060 {
00061     self = [super initWithFrame: frame isPreview: isPreview];
00062     if (self) {     
00063         [self setAnimationTimeInterval:1/20.0];
00064         
00065         clockRadius = -1.0;
00066         controller = [[DownAndOutController alloc] initAsPreview: isPreview forView: self];
00067         //  controller will read and initialize clock radius, and thus also the images.
00068         
00069         state = kDOInitial;
00070     }
00071     return self;
00072 }
00073 
00074 - (float) clockRadius { return clockRadius; }
00075 
00076 static NSDictionary *   attrs = nil;
00077 
00078 - (void) setClockRadius: (float) newRadius
00079 {
00080     if (newRadius != clockRadius) {
00081         clockRadius = newRadius;
00082         
00083         [pieImage release];
00084         pieImage = [[NSImage alloc] initWithSize: NSMakeSize(2.0 * clockRadius + 2.0, 2.0 * clockRadius + 2.0)];
00085         
00086         [textImage release];
00087         textImage = [[NSImage alloc] initWithSize: NSMakeSize(FIXED_WIDTH - CLOCK_WIDTH, CONTENT_HEIGHT)];
00088 
00089         [attrs release];
00090         NSFont *    times24Ital = [NSFont fontWithName: @"Times-Italic" size: (clockRadius/2.0) - 1.0];
00091         attrs = [[NSDictionary alloc] initWithObjectsAndKeys:
00092             times24Ital, NSFontAttributeName,
00093             [NSColor lightGrayColor], NSForegroundColorAttributeName,
00094             nil];
00095     }
00096 }
00097 
00099 - (void) dealloc
00100 {
00101     [controller release];
00102     [deadline release];
00103     [pieImage release];
00104     [textImage release];
00105     [super dealloc];
00106 }
00107 
00111 - (void) fillTextImageWithSeconds: (int) seconds
00112 {
00113     NSRect      frame = NSMakeRect(0.0, 0.0, FIXED_WIDTH - CLOCK_WIDTH, CONTENT_HEIGHT);
00114     
00115     NSString *  message = [controller messageTextForSeconds: seconds];
00116         
00117     [textImage lockFocus];
00118     
00119     [[NSColor blackColor] set];
00120     NSRectFill(frame);
00121     
00122     [message drawInRect: frame withAttributes: attrs];
00123     
00124     [textImage unlockFocus];
00125 }
00126 
00130 - (void) fillTextImageWithString: (NSString *) aString
00131 {
00132     NSRect      frame = NSMakeRect(0.0, 0.0, FIXED_WIDTH - CLOCK_WIDTH, CONTENT_HEIGHT);
00133     
00134     [textImage lockFocus];
00135     
00136     [[NSColor blackColor] set];
00137     NSRectFill(frame);
00138     
00139     [aString drawInRect: frame withAttributes: attrs];
00140     
00141     [textImage unlockFocus];
00142 }
00143 
00147 - (NSRect) addedImageRect
00148 {
00149     NSImage *       image = [controller addedImage];
00150     NSRect          retval = NSMakeRect(NSMinX(contentRect), NSMinY(contentRect), 0.0, CONTENT_HEIGHT);
00151     
00152     if (!image)
00153         return retval;
00154     
00155     NSSize          imageSize = [image size];
00156     
00157     if (imageSize.height <= CONTENT_HEIGHT) {
00158         //  Small images get drawn actual-size, vertically centered.
00159         
00160         retval.size = imageSize;
00161         retval.origin.y += (CONTENT_HEIGHT - imageSize.height) / 2.0;
00162         return retval;
00163     }
00164     
00165     //  Large images are constrained to the content height and
00166     //  proportional width.
00167     
00168     retval.size.height = CONTENT_HEIGHT;
00169     float           aspect = imageSize.width / imageSize.height;
00170     retval.size.width = CONTENT_HEIGHT * aspect;
00171     
00172     return retval;
00173 }
00174 
00177 - (void) startAnimation
00178 {
00179     NSRect      frame = [self frame];
00180     frame.origin = NSZeroPoint;
00181     
00182     NSRect      imageRect = [self addedImageRect];
00183     
00184     contentRect.size = NSMakeSize(FIXED_WIDTH + imageRect.size.width + (imageRect.size.width? 3.0: 0.0), CONTENT_HEIGHT);
00185     contentRect.origin = NSZeroPoint;
00186     
00187     if ([controller shouldMove]) {      
00188         contentRect.origin = SSRandomPointForSizeWithinRect(contentRect.size, frame);
00189         
00190         velocity.x = SSRandomFloatBetween(-MAX_V_COMPONENT, MAX_V_COMPONENT);
00191         velocity.y = SSRandomFloatBetween(-MAX_V_COMPONENT, MAX_V_COMPONENT);
00192     }
00193     else {
00194         contentRect = SSCenteredRectInRect(contentRect, frame);
00195         velocity = NSZeroPoint;
00196     }
00197     
00198     [super startAnimation];
00199     [self resetClock];
00200 }
00201 
00204 - (void) stopAnimation
00205 {
00206     [super stopAnimation];
00207     [deadline release];
00208     deadline = nil;
00209 }
00210 
00211 
00218 - (void) drawPieCenter: (NSPoint) center proportion: (float) proportion radius: (float) radius color: (NSColor *) color
00219 {
00220     if (proportion <= 0.0 || proportion >= 1.0) {
00221         NSRect          bounds = NSMakeRect(center.x - radius, center.y - radius, 2.0 * radius, 2.0 * radius);
00222         NSBezierPath *  circle = [NSBezierPath bezierPathWithOvalInRect: bounds];
00223         
00224         [color set];
00225         [circle stroke];
00226         
00227         if (proportion <= 0.0)
00228             [[NSColor blackColor] set];
00229         [circle fill];
00230     }
00231     else {
00232         NSBezierPath *  emptyPart = [NSBezierPath bezierPath];
00233         [emptyPart moveToPoint: center];
00234         [emptyPart lineToPoint: NSMakePoint(center.x, center.y + radius)];
00235         
00236         float           endAngle = 90.0 + 360.0 * (1.0 - proportion);
00237         
00238         [emptyPart appendBezierPathWithArcWithCenter: center radius: radius startAngle: 90.0 endAngle: endAngle];
00239         [emptyPart lineToPoint: center];
00240         [color set];
00241         [emptyPart stroke];
00242         [[NSColor blackColor] set];
00243         [emptyPart fill];
00244         
00245         NSBezierPath *  filledPart = [NSBezierPath bezierPath];
00246         [filledPart moveToPoint: center];
00247         [filledPart lineToPoint: NSMakePoint(center.x, center.y + radius)];
00248         [filledPart appendBezierPathWithArcWithCenter: center radius: radius startAngle: 90.0 endAngle: endAngle clockwise: YES];
00249         [filledPart lineToPoint: center];
00250         [color set];
00251         [filledPart fill];
00252     }
00253 }
00254 
00259 - (void) fillPieImageInner: (float) inner outer: (float) outer
00260 {
00261     NSPoint     pieCenter = NSMakePoint(CLOCK_RADIUS + 1.0, CLOCK_RADIUS + 1.0);
00262     
00263     [pieImage lockFocus];
00264     [self drawPieCenter: pieCenter
00265              proportion: outer 
00266                  radius: CLOCK_RADIUS 
00267                   color: [NSColor blueColor]];
00268     [self drawPieCenter: pieCenter
00269              proportion: inner
00270                  radius: CLOCK_RADIUS * 2.0/3.0 
00271                   color: [NSColor redColor]];   
00272     [pieImage unlockFocus];
00273 }
00274 
00278 - (void) drawRect: (NSRect) rect
00279 {
00280     //  [super drawRect:rect];  //  Draws black background.
00281     [[NSColor blackColor] set];
00282     NSRectFill(rect);
00283     
00284     NSRect      imageRect = [self addedImageRect];
00285     NSImage *   addedImage = [controller addedImage];
00286     
00287     if (addedImage) {
00288         NSRect      sourceRect;
00289         sourceRect.origin = NSZeroPoint;
00290         sourceRect.size = [addedImage size];
00291         
00292         [addedImage drawInRect: imageRect fromRect: sourceRect operation: NSCompositeCopy fraction: 1.0];
00293     }
00294     
00295     [pieImage compositeToPoint: NSMakePoint(NSMaxX(imageRect) + 3.0, NSMinY(contentRect)) operation: NSCompositeCopy];
00296     [textImage compositeToPoint: NSMakePoint(NSMaxX(imageRect) + 3.0 + CLOCK_WIDTH,
00297                                             NSMinY(contentRect))
00298                       operation: NSCompositeCopy];
00299 }
00300 
00308 - (void) animateOneFrame
00309 {
00310     NSTimeInterval  timeDiff = [deadline timeIntervalSinceDate: [NSDate date]];
00311 
00312     switch (state) {
00313         case kDOInitial:
00314             state = kDOCountdown;
00315             
00316         case kDOCountdown:
00317         {
00318             contentRect.origin.x += velocity.x;
00319             contentRect.origin.y += velocity.y;
00320             
00321             NSRect      frame = [self frame];
00322             
00323             if (NSMaxX(contentRect) >= NSMaxX(frame) || NSMinX(contentRect) <= NSMinX(frame)) {
00324                 velocity.x = -velocity.x;
00325             }
00326             if (NSMaxY(contentRect) >= NSMaxY(frame) || NSMinY(contentRect) <= NSMinY(frame)) {
00327                 velocity.y = -velocity.y;
00328             }
00329             
00330             if (timeDiff <= 0) {
00331                 [self fillPieImageInner: 0.0 outer: 0.0];
00332                 state = kDOQuitting;
00333             }
00334             else {
00335                 if (floor(timeDiff) < secondsLeft) {
00336                     secondsLeft = floor(timeDiff);
00337                     [self fillTextImageWithSeconds: secondsLeft];
00338                     
00339                     float   minutes = floor(timeDiff / 60.0);
00340                     float   setMinutes = floor([controller secondsBeforeLogout] / 60.0);
00341                     float   seconds = floor(timeDiff - 60.0 * minutes);
00342                     
00343                     [self fillPieImageInner: minutes/setMinutes outer: seconds/60.0];
00344                 }
00345                 [self setNeedsDisplay: YES];
00346             }
00347         }
00348             break;
00349             
00350         case kDOQuitting:
00351             if ([self isPreview]) {
00352                 //  Mode: preview/nontriggering
00353                 [self resetClock];
00354                 [self setNeedsDisplay: YES];
00355                 state = kDOCountdown;
00356             }
00357             else {
00358                 [self fillTextImageWithString: [NSString stringWithFormat: @"Logging out. Qutting %d applications.", [DAApplication countApplications]-1]];
00359                 [controller quitApplications];
00360                 [self setDeadlineForSeconds: 10];
00361                 [self setNeedsDisplay: YES];
00362                 state = kDOKilling;
00363             }
00364             break;
00365 
00366         case kDOKilling:
00367 //          if (timeDiff <= 0 || [DAApplication countApplications] == 0) {
00368             if (timeDiff <= 0 || [DAApplication countApplications] != 0) {
00369                 [self fillTextImageWithString: [NSString stringWithFormat: @"Killing %d applications.", [DAApplication countApplications]-1]];
00370                 [self setNeedsDisplay: YES];
00371                 [controller killApplications];
00372                 state = kDOLogout;
00373             }
00374             break;
00375         case kDOLogout:
00376             [controller makeTouchFile];
00377             [controller logOut];
00378             state = kDODone;
00379             break;
00380         case kDODone:
00381             break;
00382     }
00383 }
00384 
00388 - (BOOL) hasConfigureSheet
00389 {
00390     return YES;
00391 }
00392 
00396 - (NSWindow *) configureSheet
00397 {
00398     NSBundle *      myBundle = [NSBundle bundleForClass: [self class]];
00399     NSDictionary *  context = [NSDictionary dictionaryWithObjectsAndKeys: controller, @"NSOwner", nil];
00400     
00401     //  [NSBundle loadNibNamed: @"DownAndOut" owner: controller];
00402     if ([myBundle loadNibFile: @"DownAndOut" externalNameTable: context withZone: [self zone]])
00403         return [controller panel];
00404     else
00405         return nil;
00406 }
00407 
00408 @end

Generated on Wed Jan 25 12:04:27 2006 for DownAndOut by  doxygen 1.4.4