CalendarMonthImageGenerator

  • I have been working on a class that will generate calendar images
    based on the month and year you give the class instance to.  The image
    is inspired from the iCal and the CocoaDevCentral type calendars used.

    I've only been programming in Objective-C and Cocoa for about a total
    of nine months and I need suggestions with this class.  It works,
    atleast you do get an image set to your specifications, but I have
    some warnings and would like to hear suggestions on memory management,
    if anyone has the time.

    ** the warnings are a bunch like this:

    NSStringDrawing.h:23: also found `-(void)drawAtPoint:(NSPoint)point'
    CalendarMonthImageGenerator.m:631: multiple declarations for method
    `drawAtPoint:'

    I never did make any multiple declarations as you can see from my
    class methods below.

    I also am not sure how to manage NSColor memory for the calendar month
    attributes.  When I release them, my app crashes.

    My future plans for the class is:

    - return tracking grid for days, so they will be highlightable.
    - put an image in the back ground of the month.
    - create rectagular grid for face of month, instead of rounded rects.
    - anything else that comes to mind.

    Anyone who thinks it's secure to use may use it if you find it useful.

    I'm looking for any suggestions, here is the code:  (If you would
    prefer to look at the actual XCode files, I can send them, just email
    me.)

    //
    //  CalendarMonthImageGenerator.h
    //
    //  Created by Jordan Evans on 10/20/06.
    //  Copyright 2006 __MyCompanyName__. All rights reserved.
    //

    /* A simple example of how to use this class.  Your purpose:  get a
    month NSImage. */

    /*
        CalendarMonthImageGenerator *ig;
    NSImage *mi, *mi2;

    // Sets the month of the image.
    ig = [[CalendarMonthImageGenerator alloc] initMonthImageWithYear:2006
    month:10 day:17 gmtOffset:-700];

    // Sets the colors of your month image.
    [ig setBackgroundColorWithRed:1.0 green:0.0 blue:0.0 alpha:0.9];
    [ig setMonthYearColorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0];
    [ig setDaysOfWeekColorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];
    [ig setWeekCellColorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0];
    [ig setDayOfMonthColorWithRed:1.0 green:0.0 blue:0.0 alpha:1.0];

    // Sets font and font size.
    [ig prepareCalendarVariablesWithFont:@"Helvetica" fontSize:21];

    // Returns image of the month base on the previously set variables.
    mi = [ig monthImage];


    /*  If you want to create another month using the
    CalendarMonthImageGenerator */

    // Use ig, the same image generator to reset the values.
    [ig resetMonthImageWithYear:2006 month:11 day:17 gmtOffset:-700];

    // Perhaps you want different colors.
    [ig setBackgroundColorWithRed:1.0 green:1.0 blue:1.0 alpha:0.9];
    [ig setMonthYearColorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0];
    [ig setDaysOfWeekColorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0];
    [ig setWeekCellColorWithRed:0.0 green:0.0 blue:0.0 alpha:1.0];
    [ig setDayOfMonthColorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];
    [ig prepareCalendarVariablesWithFont:@"Papyrus" fontSize:21];

    // Returns a new month image.
    mi2 = [cm monthImage];
    */




    #import <Cocoa/Cocoa.h>
    // #import "Bezier.h"

    /*  This sub-class is here, because I have Panther. */

    @interface Bezier : NSBezierPath
    {

    }

    - (void)appendRoundedRect:(NSRect)rect withRadius:(float)radius;
    - (void)appendRoundCapRect:(NSRect)rect isVertical:(BOOL)boolValue;

    @end

    @implementation Bezier

    - (void)appendRoundedRect:(NSRect)rect withRadius:(float)radius
    {
    [self appendBezierPathWithArcWithCenter:NSMakePoint(rect.origin.x+radius,
    rect.origin.y+radius) radius:radius startAngle:180 endAngle:270];

    [self appendBezierPathWithArcWithCenter:NSMakePoint(rect.size.width-radius+rect.origin.x,
    radius+rect.origin.y) radius:radius startAngle:270 endAngle:360];

    [self appendBezierPathWithArcWithCenter:NSMakePoint(rect.size.width-radius+rect.origin.x,
    rect.size.height-radius+rect.origin.y) radius:radius startAngle:0
    endAngle:90];

    [self appendBezierPathWithArcWithCenter:NSMakePoint(radius+rect.origin.x,
    rect.size.height-radius+rect.origin.y) radius:radius startAngle:90
    endAngle:180];
    }

    - (void)appendRoundCapRect:(NSRect)rect isVertical:(BOOL)boolValue
    {
    [self appendBezierPathWithArcWithCenter:NSMakePoint(rect.size.width-(rect.size.height/2)+rect.origin.x,
    (rect.size.height/2)+rect.origin.y) radius:rect.size.height/2
    startAngle:270 endAngle:90];

    [self appendBezierPathWithArcWithCenter:NSMakePoint(rect.size.height/2+rect.origin.x,
    rect.size.height/2+rect.origin.y) radius:rect.size.height/2
    startAngle:90 endAngle:270];

    [self closePath];
    }

    @end

    @interface CalendarMonthImageGenerator : NSObject
    {
    NSCalendarDate *relativeDate;

    NSMutableArray *weeksArray;
    NSMutableArray *weeksStrings;
    NSMutableArray *daysOfWeekAttributedStrings;

    NSAttributedString *yearMonthAttributedString;

    NSMutableDictionary *attributes1;
    NSMutableDictionary *attributes2;
    NSMutableDictionary *attributes3;

    NSColor *backgroundColor;
    NSColor *monthYearColor;
    NSColor *daysOfWeekColor;
    NSColor *weekCellColor;
    NSColor *dayOfMonthColor;

    NSString *calendarFont;

    NSRect weekRect;

    NSSize daySize;
    NSSize weekSize;
    NSSize cappedWeekSize;
    NSSize monthSize;
    NSSize yearMonthTitleSize;

    int monthNumber;
    int relativeDay;
    int daysInMonth;
    int theFirst;
    int weeksInMonth;

    float dayCellSize;
    float fontSize;
    float margin;
    float weekSpace;
    float daySpace;
    }

      /* Methods programmer uses to create a month image. */

    // Set the intial year month of the calendar.
    - (id)initMonthImageWithYear:(int)year month:(int)month day:(int)day
    gmtOffset:(int)offset;

    // Resets the calendar to another date, so another month image can be returned.
    - (void)resetMonthImageWithYear:(int)year month:(int)month
    day:(int)day gmtOffset:(int)offset;

    // Sets attributes of the callendar.
    - (void)setBackgroundColorWithRed:(float)red green:(float)green
    blue:(float)blue alpha:(float)alpha;
    - (void)setMonthYearColorWithRed:(float)red green:(float)green
    blue:(float)blue alpha:(float)alpha;
    - (void)setDaysOfWeekColorWithRed:(float)red green:(float)green
    blue:(float)blue alpha:(float)alpha;
    - (void)setWeekCellColorWithRed:(float)red green:(float)green
    blue:(float)blue alpha:(float)alpha;
    - (void)setDayOfMonthColorWithRed:(float)red green:(float)green
    blue:(float)blue alpha:(float)alpha;

    // These methods are neccessary to set the dimensions of the month image.
    - (void)prepareCalendarVariablesWithFont:(NSString *)font fontSize:(int)size;

    // Returns an image of the month.
    - (NSImage *)monthImage;

    /* Methods that are internal to operations of creating a month image. */

    - (void)setLayOutDimensions:(int)size;
    - (void)prepareAttributes;
    - (void)prepareDaysOfWeekSymbols;
    - (void)prepareYearMonthString;
    - (void)setDaysInMonth;
    - (void)setTheFirst;
    - (void)setWeeksInMonth;
    - (void)setWeeksArray;
    - (void)prepareDaysOfMonthAttributedStrings;
    - (void)drawMonth;
    - (void)drawMonthBackground;
    - (void)drawWeekCells;
    - (void)drawDays;
    - (void)drawDaysOfWeekSymbols;
    - (void)drawYearMonthString;
    - (void)setCalendarFont:(NSString *)font;

    // Method will be used with tracking rect.  (That part of the class
    not implemented yet.)
    - (void)highlightWeek:(int)week day:(int)day;

    @end

    @implementation CalendarMonthImageGenerator

    - (id)initMonthImageWithYear:(int)year month:(int)month day:(int)day
    gmtOffset:(int)offset
    {
    self = [super init];

    if(self)
    {
      NSMutableString *dateString = [[NSMutableString alloc] init];

      [dateString setString:[[NSNumber numberWithInt:year] stringValue]];
      [dateString appendString:@"-"];
      [dateString appendString:[[NSNumber numberWithInt:month]
    stringValue]]; // Month.
      [dateString appendString:@"-"];
      [dateString appendString:[[NSNumber numberWithInt:day]
    stringValue]]; // Day of month.
      [dateString appendString:@" "];
      [dateString appendString:@"0"]; // Hour.
      [dateString appendString:@":"];
      [dateString appendString:@"0"]; // Minutes.
      [dateString appendString:@":"];
      [dateString appendString:@"0"]; // Seconds.
      [dateString appendString:@" "];
      [dateString appendString:[[NSNumber numberWithInt:offset]
    stringValue]]; // GMT offset.

      relativeDate = [[NSCalendarDate alloc] initWithString:dateString];

      [dateString release];
      dateString = nil;
    }

    return self;
    }

    - (void)resetMonthImageWithYear:(int)year month:(int)month
    day:(int)day gmtOffset:(int)offset
    {
    NSMutableString *dateString = [[NSMutableString alloc] init];

    [dateString setString:[[NSNumber numberWithInt:year] stringValue]];
    [dateString appendString:@"-"];
    [dateString appendString:[[NSNumber numberWithInt:month]
    stringValue]]; // Month.
    [dateString appendString:@"-"];
    [dateString appendString:[[NSNumber numberWithInt:day] stringValue]];
    // Day of month.
    [dateString appendString:@" "];
    [dateString appendString:@"0"]; // Hour.
    [dateString appendString:@":"];
    [dateString appendString:@"0"]; // Minutes.
    [dateString appendString:@":"];
    [dateString appendString:@"0"]; // Seconds.
    [dateString appendString:@" "];
    [dateString appendString:[[NSNumber numberWithInt:offset]
    stringValue]]; // GMT offset.

    if( relativeDate == nil )
      relativeDate = [[NSCalendarDate alloc] initWithString:dateString];
    else
    {
      [relativeDate release];
      relativeDate = nil;

      relativeDate = [[NSCalendarDate alloc] initWithString:dateString];
    }

    [dateString release];
    dateString = nil;

    }

    - (void)dealloc
    {
    [relativeDate release];
    [weeksArray release];

    [calendarFont release];

    [backgroundColor release];
    [monthYearColor release];
    [daysOfWeekColor release];
    [weekCellColor release];
    [dayOfMonthColor release];

    [attributes1 release];
    [weeksStrings release];
    [attributes2 release];
    [daysOfWeekAttributedStrings release];
    [attributes3 release];
    [yearMonthAttributedString release];

    [super dealloc];
    }

    - (void)setBackgroundColorWithRed:(float)red green:(float)green
    blue:(float)blue alpha:(float)alpha
    {
    if(backgroundColor == nil)
      backgroundColor = [NSColor colorWithCalibratedRed:red green:green
    blue:blue alpha:alpha];
    else
    {
      //[backgroundColor release];
      backgroundColor = nil;

      backgroundColor = [NSColor colorWithCalibratedRed:red green:green
    blue:blue alpha:alpha];
    }
    }

    - (void)setMonthYearColorWithRed:(float)red green:(float)green
    blue:(float)blue alpha:(float)alpha
    {
    if(monthYearColor == nil)
      monthYearColor = [NSColor colorWithCalibratedRed:red green:green
    blue:blue alpha:alpha];
    else
    {
      //[monthYearColor release];
      monthYearColor = nil;

      monthYearColor = [NSColor colorWithCalibratedRed:red green:green
    blue:blue alpha:alpha];
    }
    }

    - (void)setDaysOfWeekColorWithRed:(float)red green:(float)green
    blue:(float)blue alpha:(float)alpha
    {
    if(daysOfWeekColor == nil)
      daysOfWeekColor = [NSColor colorWithCalibratedRed:red green:green
    blue:blue alpha:alpha];
    else
    {
      //[daysOfWeekColor release];
      daysOfWeekColor = nil;

      daysOfWeekColor = [NSColor colorWithCalibratedRed:red green:green
    blue:blue alpha:alpha];
    }
    }

    - (void)setWeekCellColorWithRed:(float)red green:(float)green
    blue:(float)blue alpha:(float)alpha
    {
    if(weekCellColor == nil)
      weekCellColor = [NSColor colorWithCalibratedRed:red green:green
    blue:blue alpha:alpha];
    else
    {
      //[weekCellColor release];
      weekCellColor = nil;

      weekCellColor = [NSColor colorWithCalibratedRed:red green:green
    blue:blue alpha:alpha];
    }
    }

    - (void)setDayOfMonthColorWithRed:(float)red green:(float)green
    blue:(float)blue alpha:(float)alpha
    {
    if(dayOfMonthColor == nil)
      dayOfMonthColor = [NSColor colorWithCalibratedRed:red green:green
    blue:blue alpha:alpha];
    else
    {
      //[dayOfMonthColor release];
      dayOfMonthColor = nil;

      dayOfMonthColor = [NSColor colorWithCalibratedRed:red green:green
    blue:blue alpha:alpha];
    }
    }

    - (void)prepareCalendarVariablesWithFont:(NSString *)font fontSize:(int)size
    {
    relativeDay = [relativeDate dayOfMonth];
    monthNumber = [relativeDate monthOfYear];

    [self setCalendarFont:font];
    [self setLayOutDimensions:size];

    [self prepareAttributes];
    [self prepareDaysOfWeekSymbols];
    [self prepareYearMonthString];

    [self setDaysInMonth];
    [self setTheFirst];
    [self setWeeksInMonth];
    [self setWeeksArray];

    [self prepareDaysOfMonthAttributedStrings];

    monthSize.width = cappedWeekSize.width + (margin *3);
    monthSize.height = (cappedWeekSize.height * (weeksInMonth + 1)) +
    (weekSpace * weeksInMonth) + ((cappedWeekSize.height + weekSpace)
    *0.35) + (margin *3);
    }

    - (void)setCalendarFont:(NSString *)font
    {
    if(calendarFont == nil)
      calendarFont = [[NSString alloc] initWithString:font];
    else
    {
      [calendarFont release];
      calendarFont = nil;

      calendarFont = [[NSString alloc] initWithString:font];
    }
    }

    - (void)setLayOutDimensions:(int)size
    {
    fontSize = size;
    daySpace = size * 0.125;
    margin = size/2;
    daySize.width = size * 1.5;
    weekSize.width = ((daySize.width * 7) + (daySpace * 6));
    weekSize.height = size;
    daySize.height = weekSize.height;
    cappedWeekSize.width = weekSize.width * 1.1;
    cappedWeekSize.height = weekSize.height * 1.45;
    weekSpace = cappedWeekSize.height * 0.125;
    }

    - (void)prepareAttributes
    {
    if(attributes1 != nil)
    {
      [attributes1 release];
      attributes1 = nil;
    }

    attributes1 = [[NSMutableDictionary alloc] init];
    [attributes1 setObject:[NSFont fontWithName:calendarFont size:fontSize]
                     forKey:NSFontAttributeName];
    [attributes1 setObject:dayOfMonthColor
                     forKey:NSForegroundColorAttributeName];

    if(attributes2 != nil)
    {
      [attributes2 release];
      attributes2 = nil;
    }

    attributes2 = [[NSMutableDictionary alloc] init];
        [attributes2 setObject:[NSFont fontWithName:calendarFont size:fontSize]
                      forKey:NSFontAttributeName];
        [attributes2 setObject:daysOfWeekColor
                      forKey:NSForegroundColorAttributeName];

    if(attributes3 != nil)
    {
      [attributes3 release];
      attributes3 = nil;
    }

    attributes3 = [[NSMutableDictionary alloc] init];
        [attributes3 setObject:[NSFont fontWithName:calendarFont size:fontSize]
                      forKey:NSFontAttributeName];
        [attributes3 setObject:monthYearColor
                      forKey:NSForegroundColorAttributeName];
    }

    - (void)prepareDaysOfWeekSymbols
    {
    if(daysOfWeekAttributedStrings != nil)
    {
      [daysOfWeekAttributedStrings release];
      daysOfWeekAttributedStrings = nil;
    }
    daysOfWeekAttributedStrings = [[NSMutableArray alloc] init];

    NSMutableArray *daysOfWeekSymbols = [[NSMutableArray alloc] init];

    [daysOfWeekSymbols addObject:[[NSString alloc] initWithString:@"S"]];
    [daysOfWeekSymbols addObject:[[NSString alloc] initWithString:@"M"]];
    [daysOfWeekSymbols addObject:[[NSString alloc] initWithString:@"T"]];
    [daysOfWeekSymbols addObject:[[NSString alloc] initWithString:@"W"]];
    [daysOfWeekSymbols addObject:[[NSString alloc] initWithString:@"T"]];
    [daysOfWeekSymbols addObject:[[NSString alloc] initWithString:@"F"]];
    [daysOfWeekSymbols addObject:[[NSString alloc] initWithString:@"S"]];

    int i;

    for( i=0; i<7; i++ )
    {
      [daysOfWeekAttributedStrings addObject:[[NSAttributedString alloc]
    initWithString:[daysOfWeekSymbols objectAtIndex:i]
    attributes:attributes2]];
    }

    [daysOfWeekSymbols release];
    }

    - (void)prepareYearMonthString
    {
    NSMutableString *yearMonthString = [[NSMutableString alloc] init];

    if(monthNumber == 1)
      [yearMonthString setString:@"January"];
    if(monthNumber == 2)
      [yearMonthString setString:@"February"];
    if(monthNumber == 3)
      [yearMonthString setString:@"March"];
    if(monthNumber == 4)
      [yearMonthString setString:@"April"];
    if(monthNumber == 5)
      [yearMonthString setString:@"May"];
    if(monthNumber == 6)
      [yearMonthString setString:@"June"];
    if(monthNumber == 7)
      [yearMonthString setString:@"July"];
    if(monthNumber == 8)
      [yearMonthString setString:@"August"];
    if(monthNumber == 9)
      [yearMonthString setString:@"September"];
    if(monthNumber == 10)
      [yearMonthString setString:@"October"];
    if(monthNumber == 11)
      [yearMonthString setString:@"November"];
    if(monthNumber == 12)
      [yearMonthString setString:@"December"];

    [yearMonthString appendString:@" "];

    NSNumber *year = [[NSNumber alloc] initWithInt:[relativeDate yearOfCommonEra]];
    [yearMonthString appendString:[year stringValue]];

    yearMonthAttributedString = [[NSAttributedString alloc]
    initWithString:yearMonthString attributes:attributes3];

    [yearMonthString release];
    yearMonthString = nil;
    }

    - (void)setDaysInMonth
    {
    NSCalendarDate *testDate;
    NSMutableString *testString;

    int initialMonth = [relativeDate monthOfYear];
    int testMonth = initialMonth;
    int days = 1;

    do
    {
      testString = [[NSMutableString alloc] init];

      [testString setString:[[NSNumber numberWithInt:[relativeDate
    yearOfCommonEra]] stringValue]];
      [testString appendString:@"-"];
      [testString appendString:[[NSNumber numberWithInt:initialMonth]
    stringValue]]; // Month.
      [testString appendString:@"-"];
      [testString appendString:[[NSNumber numberWithInt:days]
    stringValue]]; // Day of month.
      [testString appendString:@" "];
      [testString appendString:@"0"]; // Hour.
      [testString appendString:@":"];
      [testString appendString:@"0"]; // Minutes.
      [testString appendString:@":"];
      [testString appendString:@"0"]; // Seconds.
      [testString appendString:@" "];
      [testString appendString:[[NSNumber numberWithInt:-700]
    stringValue]]; // GMT offset.

      testDate = [[NSCalendarDate alloc] initWithString:testString];

      testMonth = [testDate monthOfYear];

      [testDate release];
      testDate = nil;
      [testString release];
      testString = nil;

      days++;

    }while( testMonth == initialMonth );

    days -=2;

    daysInMonth = days;
    }

    - (void)setTheFirst
    {
    int theMonth = [relativeDate monthOfYear];

    NSMutableString *testString = [[NSMutableString alloc] init];

    [testString setString:[[NSNumber numberWithInt:[relativeDate
    yearOfCommonEra]] stringValue]];
    [testString appendString:@"-"];
    [testString appendString:[[NSNumber numberWithInt:theMonth]
    stringValue]]; // Month.
    [testString appendString:@"-"];
    [testString appendString:[[NSNumber numberWithInt:1] stringValue]];
    // Day of month, The First.
    [testString appendString:@" "];
    [testString appendString:@"0"]; // Hour.
    [testString appendString:@":"];
    [testString appendString:@"0"]; // Minutes.
    [testString appendString:@":"];
    [testString appendString:@"0"]; // Seconds.
    [testString appendString:@" "];
    [testString appendString:[[NSNumber numberWithInt:-700]
    stringValue]]; // GMT offset.

    NSCalendarDate *theFirstDate = [[NSCalendarDate alloc]
    initWithString:testString];

    theFirst = [theFirstDate dayOfWeek];

    [theFirstDate release];
    theFirstDate = nil;

    [testString release];
    testString = nil;
    }

    - (void)setWeeksInMonth
    {
    if(daysInMonth == 28)
    {
      if(theFirst == 0)
      weeksInMonth = 4;
      else
      weeksInMonth = 5;
    }

    if(daysInMonth == 29)
    {
      weeksInMonth = 5;
    }

    if(daysInMonth == 30)
    {
      if(theFirst == 6)
      weeksInMonth = 6;
      else
      weeksInMonth = 5;
    }

    if(daysInMonth == 31)
    {
      if(theFirst >= 5)
      weeksInMonth = 6;
      else
      weeksInMonth = 5;
    }
    }

    - (void)setWeeksArray
    {
    if(weeksArray != nil)
    {
      [weeksArray release];
      weeksArray = nil;

      [weeksStrings release];
      weeksStrings = nil;
    }
    weeksArray = [[NSMutableArray alloc] init];
    weeksStrings = [[NSMutableArray alloc] init];

    int i, j;
    int day;

    int dayCounter = 0;
    int weekdayCounter = 0;
    int weekIndice = 0;
    BOOL incrementDay = NO;

    // Create the weeks array's and zero each day out.
    for(i=0; i<weeksInMonth; i++)
    {
      [weeksArray addObject:[[NSMutableArray alloc] init]];

      for( j=0; j<7; j++ )
      [[weeksArray lastObject] addObject:[[NSNumber alloc] initWithInt:0]];
    }

    day = 1;

    do
    {
      // weekdayCounter represents the numerical representation of the day
    of week, resets after 6.
      // weekIndice represents the week of the month currently having it's day set.
      // day represents the day of the month.

      if(weekdayCounter == 7)
      {
      weekdayCounter = 0;
      weekIndice++;
      }

      if( dayCounter == theFirst )
      {
      incrementDay = YES;
      }

      if(incrementDay == NO)
      dayCounter++;
      else
      {
      [[weeksArray objectAtIndex:weekIndice]
    replaceObjectAtIndex:weekdayCounter withObject:[[NSNumber alloc]
    initWithInt:day]];
      day++;
      }

      weekdayCounter++;

    }while(day <= daysInMonth);
    }

    - (void)prepareDaysOfMonthAttributedStrings
    {
    NSString *dayString;
    int i, j;

    for( i=0; i<weeksInMonth; i++ )
    {
      [weeksStrings addObject:[[NSMutableArray alloc] init]];

      for( j=0; j<7; j++ )
      {
      dayString = [[NSString alloc] initWithString:[[[weeksArray
    objectAtIndex:i] objectAtIndex:j] stringValue]];

      [[weeksStrings lastObject] addObject:[[NSAttributedString alloc]
    initWithString:dayString attributes:attributes1]];

      [dayString release];
      dayString = nil;
      }
    }
    }

    - (NSImage *)monthImage
    {
    NSImage *monthImage = [[NSImage alloc] initWithSize:monthSize];

    [monthImage lockFocus];

    [self drawMonth];

    [monthImage unlockFocus];

    return monthImage;
    }

    - (void)drawMonth
    {
    [backgroundColor set];

    NSPoint point;
    point.x = monthSize.width;
    point.y = monthSize.height;

    [self drawMonthBackground];

    [self drawWeekCells];

    [self highlightWeek:0 day:2];

    [self drawDays];
    [self drawDaysOfWeekSymbols];
    [self drawYearMonthString];
    }

    - (void)drawMonthBackground
    {
    Bezier *path  = [[Bezier alloc] init];

    [path appendRoundedRect:NSMakeRect(0, 0, monthSize.width,
    monthSize.height ) withRadius:margin];

    [path fill];

    [path release];
    path = nil;
    }

    - (void)drawWeekCells
    {
    NSPoint point;
    point.x = margin + margin/2;
    point.y = margin + margin/2;

    [weekCellColor set];

    Bezier *path;

    int i;
    for( i=0; i<weeksInMonth; i++ )
    {
      path = [[Bezier alloc] init];

      [path appendRoundCapRect:NSMakeRect(point.x, point.y,
    cappedWeekSize.width, cappedWeekSize.height) isVertical:NO];

      point.y += (weekSpace + cappedWeekSize.height);

      [path fill];

      [path release];
      path = nil;
    }
    }

    - (void)highlightWeek:(int)week day:(int)day
    {
    float totalWidth = (daySize.width * 7) + (daySpace *6);

    // Selection highlight.  Will also be used for tracking rect.
    [[NSColor colorWithCalibratedRed:0.9 green:0.9 blue:0.9 alpha:0.9] set];
    Bezier *path  = [[Bezier alloc] init];

    float width = daySize.width;
    float height = cappedWeekSize.height-4;

    float x = ((monthSize.width - totalWidth)/2) + ((daySize.width +
    daySpace) *day);
    float y = (margin * 1.5) + ((cappedWeekSize.height + weekSpace)
    *week) + ((cappedWeekSize.height - height)/2);

    [path appendRoundedRect:NSMakeRect( x, y, width, height) withRadius:margin/2];

    [path fill];
    [path release];
    path = nil;
    }

    - (void)drawDays
    {
    float totalWidth = 0.0;
    int i, j;

    totalWidth = (daySize.width * 7) + (daySpace *6);

    NSPoint point;
    point.x = (monthSize.width - totalWidth)/2;
    point.y = margin + ((daySize.height - margin)/2);

    NSSize stringSize;
    float x, y;

    [dayOfMonthColor set];
    for( i=weeksInMonth-1; i>-1; i-- )
    {
      for( j=0; j<7; j++ )
      {
      stringSize = [[[weeksStrings objectAtIndex:i] objectAtIndex:j] size];

      if( ![[[[weeksStrings objectAtIndex:i] objectAtIndex:j] string]
    isEqualTo:@"0"] )
      {
        x = point.x + ((daySize.width - stringSize.width)/2);
        y = point.y + ((cappedWeekSize.height - stringSize.height)/2);

        [[[weeksStrings objectAtIndex:i] objectAtIndex:j]
    drawAtPoint:NSMakePoint(x, y)];
      }

      point.x += (daySpace + daySize.width);
      }

      point.x = (monthSize.width - totalWidth)/2;
      point.y += (cappedWeekSize.height + weekSpace);
    }
    }

    - (void)drawDaysOfWeekSymbols
    {
    float totalWidth = 0.0;
    int i;

    totalWidth = (daySize.width * 7) + (daySpace *6);

    NSPoint point;
    point.x = (monthSize.width - totalWidth)/2;
    point.y = (cappedWeekSize.height * (weeksInMonth)) + (weekSpace *
    (weeksInMonth-1)) + ((cappedWeekSize.height + weekSpace) *0.5);

    NSSize stringSize;

    for( i=0; i<7; i++ )
    {
      stringSize = [[daysOfWeekAttributedStrings objectAtIndex:i] size];

      [[daysOfWeekAttributedStrings objectAtIndex:i]
    drawAtPoint:NSMakePoint(point.x+((daySize.width -
    stringSize.width)/2), point.y)];

      point.x += (daySpace + daySize.width);
    }
    }

    - (void)drawYearMonthString
    {
    NSPoint point;
    NSSize strSize = [yearMonthAttributedString size];

    point.x = (monthSize.width - strSize.width)/2;
    point.y = (cappedWeekSize.height * (weeksInMonth + 1) ) + (weekSpace
    * weeksInMonth) + ((cappedWeekSize.height + weekSpace) *0.35);

    point.y = (cappedWeekSize.height * (weeksInMonth + 1) ) + (weekSpace
    * weeksInMonth) +

    ((cappedWeekSize.height + weekSpace) *0.35);

    [yearMonthAttributedString drawAtPoint:point];

    }

    @end
  • > I also am not sure how to manage NSColor memory for the calendar month
    > attributes.  When I release them, my app crashes.

    Because you didn't retain them in the first place:

    > backgroundColor = [NSColor colorWithCalibratedRed:red
    > green:green blue:blue alpha:alpha];

    retains and releases almost always need to be paired (and sometimes
    instead of "retain" you might get a reference count via a "copy,"
    "alloc," or "new" method).

    Similarly in your monthImage method, you return an allocated object,
    while you should really return an object without a reference count ---
    so autorelease your return value, or name the method something like
    newMonthImage to make it clear to callers that they are getting a
    retained object.

    Ali
previous month october 2006 next month
MTWTFSS
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31          
Go to today