diff --git a/ArrayExtensions/BinarySearchTC.m b/ArrayExtensions/BinarySearchTC.m new file mode 100644 index 0000000..b1ba1ff --- /dev/null +++ b/ArrayExtensions/BinarySearchTC.m @@ -0,0 +1,95 @@ +// +// BinarySearchTC.m +// +// Created by Marcus Rohrmoser on 12.01.10. +// Copyright 2009 Marcus Rohrmoser mobile Software. All rights reserved. +// + +#define USE_APPLICATION_UNIT_TEST 0 + +#import + +@interface BinarySearchTC : SenTestCase {} +@end + +#import "MroBinarySearch.h" + +@implementation BinarySearchTC + +-(void)testBinarySearchUsingSelector +{ + STAssertEquals(NSOrderedAscending, [@"0" compare:@"05"], @""); + STAssertEquals(NSOrderedAscending, [@"05" compare:@"1"], @""); + STAssertEquals(NSOrderedAscending, (NSComparisonResult)[@"0" performSelector:@selector(compare:) withObject:@"05"], @""); + STAssertEquals(NSOrderedAscending, (NSComparisonResult)[@"05" performSelector:@selector(compare:) withObject:@"1"], @""); + + NSArray *a = [NSArray arrayWithObjects:@"0", @"1", @"2", @"3", @"4", nil]; + STAssertEquals(0, [a binarySearch:@"0"], @"0"); + STAssertEquals(1, [a binarySearch:@"1"], @"1"); + STAssertEquals(4, [a binarySearch:@"4"], @"4"); + STAssertEquals(-2, [a binarySearch:@"05"], @"05"); + STAssertEquals(-3, [a binarySearch:@"1" usingSelector:nil inRange:NSMakeRange(2, a.count-2)], @"1"); +} + + +NSInteger stringSort(id str1, id str2, void *context) +{ +// NSLogD(@"a:%@, b:%@", str1, str2); + return [str1 compare:str2]; +} + + +-(void)testBinarySearchUsingFunction +{ + STAssertEquals(NSOrderedAscending, stringSort(@"0", @"05", NULL), @""); + STAssertEquals(NSOrderedAscending, stringSort(@"05", @"1", NULL), @""); + + NSArray *a = [NSArray arrayWithObjects:@"0", @"1", @"2", @"3", @"4", nil]; + STAssertEquals(0, [a binarySearch:@"0" usingFunction:stringSort context:NULL], @"0"); + STAssertEquals(1, [a binarySearch:@"1" usingFunction:stringSort context:NULL], @"1"); + STAssertEquals(4, [a binarySearch:@"4" usingFunction:stringSort context:NULL], @"4"); + STAssertEquals(-3, [a binarySearch:@"1" usingFunction:stringSort context:NULL inRange:NSMakeRange(2, a.count-2)], @"1"); + STAssertEquals(-2, [a binarySearch:@"05" usingFunction:stringSort context:NULL], @"05"); + + a = [[NSArray arrayWithObjects:@"aa", @"ab", @"bb", @"bc", @"ca", @"cb", nil] sortedArrayUsingSelector:@selector(compare:)]; + STAssertEquals(-3, [a binarySearch:@"b" usingFunction:stringSort context:NULL], @"0"); + STAssertEquals(2, -(-3) - 1, @""); + STAssertEquals(-5, [a binarySearch:@"bz" usingFunction:stringSort context:NULL], @"0"); + + a = [NSArray array]; + STAssertEquals(-1, [a binarySearch:@"a" usingFunction:stringSort context:NULL], @"0"); + + a = [NSArray arrayWithObjects:@"b", nil]; + STAssertEquals(-1, [a binarySearch:@"a" usingFunction:stringSort context:NULL], @"0"); + STAssertEquals(0, [a binarySearch:@"b" usingFunction:stringSort context:NULL], @"0"); + STAssertEquals(-2, [a binarySearch:@"c" usingFunction:stringSort context:NULL], @"0"); + + a = [NSArray arrayWithObjects:@"b", @"d", nil]; + STAssertEquals(-1, [a binarySearch:@"a" usingFunction:stringSort context:NULL], @"0"); + STAssertEquals(0, [a binarySearch:@"b" usingFunction:stringSort context:NULL], @"0"); + STAssertEquals(-2, [a binarySearch:@"c" usingFunction:stringSort context:NULL], @"0"); + STAssertEquals(1, [a binarySearch:@"d" usingFunction:stringSort context:NULL], @"0"); + STAssertEquals(-3, [a binarySearch:@"e" usingFunction:stringSort context:NULL], @"0"); +} + + +-(void)testBinarySearchUsingDescriptors +{ + + NSArray *a = [NSArray arrayWithObjects:@"0", @"4", @"1", @"3", @"2", nil]; + NSSortDescriptor *tmp = [[NSSortDescriptor alloc] initWithKey:@"self" ascending:YES]; + NSArray *sort = [NSArray arrayWithObject:tmp]; + a = [a sortedArrayUsingDescriptors:sort]; + + STAssertEquals(NSOrderedAscending, [tmp compareObject:@"0" toObject:@"05"], @""); + STAssertEquals(NSOrderedAscending, [tmp compareObject:@"05" toObject:@"1"], @""); + [tmp release]; + + STAssertEquals(0, [a binarySearch:@"0" usingDescriptors:sort], @"0"); + STAssertEquals(1, [a binarySearch:@"1" usingDescriptors:sort], @"1"); + STAssertEquals(4, [a binarySearch:@"4" usingDescriptors:sort], @"4"); + STAssertEquals(-2, [a binarySearch:@"05" usingDescriptors:sort], @"05"); + STAssertEquals(-3, [a binarySearch:@"1" usingDescriptors:sort inRange:NSMakeRange(2, a.count-2)], @"1"); +} + +@end diff --git a/ArrayExtensions/MroBinarySearch.h b/ArrayExtensions/MroBinarySearch.h new file mode 100644 index 0000000..fbea0d0 --- /dev/null +++ b/ArrayExtensions/MroBinarySearch.h @@ -0,0 +1,65 @@ +// +// MroBinarySearch.h +// +// Created by Marcus Rohrmoser on 12.01.10. +// Copyright 2010 Marcus Rohrmoser mobile Software. All rights reserved. +// + +#if 0 +// No Logging +#define NSLogD(x,...) /* NSLog(x,##__VA_ARGS__) */ +#else +// Do Logging +#define NSLogD(x,...) NSLog(x,##__VA_ARGS__) +#endif + +/** Add binary search capabilities to NSArray. + * + * A port from http://www.jcurl.org/m2/site/jc-core/0.7-SNAPSHOT/apidocs/org/jcurl/math/CurveCombined.html#binarySearch(double[],%20int,%20int,%20double) + * with the author's friendly permission. + * + */ +@interface NSArray(MroBinarySearch) + +-(NSInteger)binarySearch:(id)key; + +/** + * @see MroBinarySearch::binarySearch: + * @see NSArray::sortedArrayUsingSelector: + */ +-(NSInteger)binarySearch:(id)key usingSelector:(SEL)comparator; + +/** + * Binary search a part of an array. + * + * @param key nil returns -1 + * @param comparator may be nil to use @selector(compare:) + * @param range + * @return found index. + * + * @see MroBinarySearch::binarySearch: + * @see NSArray::sortedArrayUsingSelector: + */ +-(NSInteger)binarySearch:(id)key usingSelector:(SEL)comparator inRange:(NSRange)range; + +/** + * @see MroBinarySearch::binarySearch: + * @see NSArray::sortedArrayUsingFunction:context: + */ +-(NSInteger)binarySearch:(id)key usingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context; + +/** + * @see MroBinarySearch::binarySearch: + * @see NSArray::sortedArrayUsingFunction:context: + */ +-(NSInteger)binarySearch:(id)key usingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context inRange:(NSRange)range; + +/** + * @see MroBinarySearch::binarySearch: + * @see NSArray::sortedArrayUsingDescriptors: + */ +-(NSInteger)binarySearch:(id)key usingDescriptors:(NSArray *)sortDescriptors; + +-(NSInteger)binarySearch:(id)key usingDescriptors:(NSArray *)sortDescriptors inRange:(NSRange)range; + +@end diff --git a/ArrayExtensions/MroBinarySearch.m b/ArrayExtensions/MroBinarySearch.m new file mode 100644 index 0000000..ddbdc18 --- /dev/null +++ b/ArrayExtensions/MroBinarySearch.m @@ -0,0 +1,146 @@ +// +// MroBinarySearch.m +// +// Created by Marcus Rohrmoser on 12.01.10. +// Copyright 2010 Marcus Rohrmoser mobile Software. All rights reserved. +// + +#import "MroBinarySearch.h" + +@implementation NSArray(MroBinarySearch) + +#pragma mark Using Selector + +-(NSInteger)binarySearch:(id)key +{ + return [self binarySearch:key usingSelector:nil]; +} + + +-(NSInteger)binarySearch:(id)key usingSelector:(SEL)comparator +{ + return [self binarySearch:key usingSelector:comparator inRange:NSMakeRange(0, self.count)]; +} + + +-(NSInteger)binarySearch:(id)key usingSelector:(SEL)comparator inRange:(NSRange)range +{ + NSLogD(@"[NSArray(MroBinarySearch) binarySearch:%@ usingSelector:]", key); + if (self.count == 0 || key == nil) + return -1; + if(comparator == nil) + comparator = @selector(compare:); + +// check overflow? + NSInteger min = range.location; + NSInteger max = range.location + range.length - 1; + + while (min <= max) + { + // http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html + const NSInteger mid = min + (max - min) / 2; + switch ((NSComparisonResult)[key performSelector:comparator withObject:[self objectAtIndex:mid]]) + { + case NSOrderedSame: + return mid; + case NSOrderedDescending: + min = mid + 1; + break; + case NSOrderedAscending: + max = mid - 1; + break; + } + } + return -(min + 1); +} + + +#pragma mark Using C-Function + +-(NSInteger)binarySearch:(id)key usingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context +{ + return [self binarySearch:key usingFunction:comparator context:context inRange:NSMakeRange(0, self.count)]; +} + + +-(NSInteger)binarySearch:(id)key usingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context inRange:(NSRange)range +{ + NSLogD(@"[NSArray(MroBinarySearch) binarySearch:%@ usingFunction:]", key); + if(self.count == 0 || key == nil || comparator == NULL) + return [self binarySearch:key usingSelector:nil inRange:range]; + +// check overflow? + NSInteger min = range.location; + NSInteger max = range.location + range.length - 1; + + while (min <= max) + { + // http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html + const NSInteger mid = min + (max - min) / 2; + switch (comparator(key, [self objectAtIndex:mid], context)) + { + case NSOrderedSame: + return mid; + case NSOrderedDescending: + min = mid + 1; + break; + case NSOrderedAscending: + max = mid - 1; + break; + } + } + return -(min + 1); +} + + +#pragma mark Using NSSortDescriptors + +-(NSInteger)binarySearch:(id)key usingDescriptors:(NSArray *)sortDescriptors +{ + return [self binarySearch:key usingDescriptors:sortDescriptors inRange:NSMakeRange(0, self.count)]; +} + + +/// internal helper +-(NSComparisonResult)_mroInternalCompare:(const NSArray const*)sortDescriptors a:(id)object1 b:(id)object2 +{ + for (const NSSortDescriptor const *d in sortDescriptors) + { + const NSComparisonResult r = [d compareObject:object1 toObject:object2]; + if (r != NSOrderedSame) + return r; + } + return NSOrderedSame; +} + + +-(NSInteger)binarySearch:(id)key usingDescriptors:(NSArray *)sortDescriptors inRange:(NSRange)range +{ + NSLogD(@"[NSArray(MroBinarySearch) binarySearch:%@ usingDescriptors:]", key); + if (self.count == 0 || key == nil || sortDescriptors == nil || sortDescriptors.count == 0) + return [self binarySearch:key usingSelector:nil inRange:range]; + +// check overflow? + NSInteger min = range.location; + NSInteger max = range.location + range.length - 1; + + while (min <= max) + { + // http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html + const NSInteger mid = min + (max - min) / 2; + switch ([self _mroInternalCompare:sortDescriptors a:key b:[self objectAtIndex:mid]]) + { + case NSOrderedSame: + return mid; + case NSOrderedDescending: + min = mid + 1; + break; + case NSOrderedAscending: + max = mid - 1; + break; + } + } + return -(min + 1); +} + +@end diff --git a/Calendar.h b/Calendar.h new file mode 100644 index 0000000..49c7ea7 --- /dev/null +++ b/Calendar.h @@ -0,0 +1,17 @@ +/** + * Appcelerator Titanium Mobile + * Copyright (c) 2009-2010 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the Apache Public License + * Please see the LICENSE included with this distribution for details. + */ +#import "TiUIView.h" + +@interface Calendar : TiUIView { + +@private + +} + +-(UIView*) calendar; + +@end diff --git a/Calendar.m b/Calendar.m new file mode 100644 index 0000000..3617d9e --- /dev/null +++ b/Calendar.m @@ -0,0 +1,22 @@ +/** + * Appcelerator Titanium Mobile + * Copyright (c) 2009-2010 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the Apache Public License + * Please see the LICENSE included with this distribution for details. + */ + +#import "Calendar.h" + +#import "TiUtils.h" + +@implementation Calendar + +-(UIView*) calendar; +{ +// CalendarViewController* viewController = [CalendarViewController init]; +// return viewController.view; + + NSLog(@"Calendar calendar"); +} + +@end diff --git a/Calendar/.DS_Store b/Calendar/.DS_Store new file mode 100644 index 0000000..f524cfb Binary files /dev/null and b/Calendar/.DS_Store differ diff --git a/Calendar/CheckmarkTile.h b/Calendar/CheckmarkTile.h new file mode 100644 index 0000000..6b1e6b3 --- /dev/null +++ b/Calendar/CheckmarkTile.h @@ -0,0 +1,11 @@ + +// needed to subclass KLTile +#import "KLCalendarView.h" + +@interface CheckmarkTile : KLTile +{ + BOOL checkmarked; +} +@property (nonatomic, assign) BOOL checkmarked; + +@end diff --git a/Calendar/CheckmarkTile.m b/Calendar/CheckmarkTile.m new file mode 100644 index 0000000..e5990e9 --- /dev/null +++ b/Calendar/CheckmarkTile.m @@ -0,0 +1,39 @@ + +#import "CheckmarkTile.h" + +@implementation CheckmarkTile + +@synthesize checkmarked; + +- (void)drawRect:(CGRect)rect +{ + [super drawRect:rect]; + + CGContextRef ctx = UIGraphicsGetCurrentContext(); + CGFloat width = self.bounds.size.width; + CGFloat height = self.bounds.size.height; + + // Draw the checkmark if applicable + if (self.checkmarked) { + unichar character = 0x00B7; //Unicode checkmark + CGContextSaveGState(ctx); + CGContextSetFillColorWithColor(ctx, [[UIColor colorWithHue:0.1f saturation:0.0f brightness:0.0f alpha:0.5f] CGColor]); + CGContextSetShadowWithColor(ctx, CGSizeMake(0.0f, -1.0f), 1.0f, [[UIColor blackColor] CGColor]); + NSString *checkmark = [NSString stringWithCharacters:&character length:1]; + [checkmark drawInRect:CGRectMake(4, 4, width-8, height-8) withFont: [UIFont boldSystemFontOfSize:0.85f*width] lineBreakMode: UILineBreakModeClip alignment: UITextAlignmentCenter]; + CGContextRestoreGState(ctx); + } +} + +-(void) setCheckmarked:(BOOL) c +{ + checkmarked = c; + [self setNeedsDisplay]; +} + +/*-(BOOL) checkmarked +{ + return self.checkmarked; +} + */ +@end diff --git a/Calendar/KCalendar_Prefix.pch b/Calendar/KCalendar_Prefix.pch new file mode 100644 index 0000000..1ddde29 --- /dev/null +++ b/Calendar/KCalendar_Prefix.pch @@ -0,0 +1,8 @@ +// +// Prefix header for all source files of the 'KCalendar' target in the 'KCalendar' project +// + +#ifdef __OBJC__ + #import + #import +#endif diff --git a/Calendar/KLCalendarModel.h b/Calendar/KLCalendarModel.h new file mode 100644 index 0000000..35df6ee --- /dev/null +++ b/Calendar/KLCalendarModel.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2008, Keith Lazuka, dba The Polypeptides + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Neither the name of the The Polypeptides nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Keith Lazuka ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Keith Lazuka BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#import + +@class THCalendarInfo; + +@interface KLCalendarModel : NSObject { + CFCalendarRef _cal; + THCalendarInfo *_calendarInfo; + NSArray *_dayNames; +} + +- (id)initWithDate: (NSDate*) date; + +- (void)decrementMonth; +- (void)incrementMonth; +- (NSString *)selectedMonthName; +- (NSInteger)selectedMonthNumberOfWeeks; +- (NSInteger)selectedYear; +- (NSString *)dayNameAbbreviationForDayOfWeek:(NSUInteger)dayOfWeek; + +- (NSArray *)daysInFinalWeekOfPreviousMonth; +- (NSArray *)daysInSelectedMonth; +- (NSArray *)daysInFirstWeekOfFollowingMonth; + +@end diff --git a/Calendar/KLCalendarModel.m b/Calendar/KLCalendarModel.m new file mode 100644 index 0000000..76d79a4 --- /dev/null +++ b/Calendar/KLCalendarModel.m @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2008, Keith Lazuka, dba The Polypeptides + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Neither the name of the The Polypeptides nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Keith Lazuka ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Keith Lazuka BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "KLCalendarModel.h" +#import "THCalendarInfo.h" +#import "KLDate.h" + +@implementation KLCalendarModel + +- (id)init +{ + if (![super init]) + return nil; + + _calendarInfo = [[THCalendarInfo alloc] init]; + [_calendarInfo setDate:[NSDate date]]; + + _cal = CFCalendarCopyCurrent(); + + _dayNames = [[NSArray alloc] initWithObjects:@"Sun", @"Mon", @"Tue", @"Wed", @"Thu", @"Fri", @"Sat", nil]; + return self; +} + +- (id)initWithDate: (NSDate*) date +{ + if (![super init]) + return nil; + + _calendarInfo = [[THCalendarInfo alloc] init]; + [_calendarInfo setDate:date]; + + _cal = CFCalendarCopyCurrent(); + + _dayNames = [[NSArray alloc] initWithObjects:@"Sun", @"Mon", @"Tue", @"Wed", @"Thu", @"Fri", @"Sat", nil]; + return self; +} + + + +#pragma mark Public methods + +- (void)decrementMonth +{ + [_calendarInfo moveToPreviousMonth]; +} + +- (void)incrementMonth +{ + [_calendarInfo moveToNextMonth]; +} + +- (NSString *)selectedMonthName +{ + return [_calendarInfo monthName]; +} + +- (NSInteger)selectedYear +{ + return [_calendarInfo year]; +} + +- (NSInteger)selectedMonthNumberOfWeeks +{ + return (NSInteger)[_calendarInfo weeksInMonth]; + +} + +// gives you "Mon" for input 1 if region is set to United States ("Mon" for Monday) +// if region uses a calendar that starts the week with monday, an input of 1 will give "Tue" +- (NSString *)dayNameAbbreviationForDayOfWeek:(NSUInteger)dayOfWeek +{ + if (CFCalendarGetFirstWeekday(_cal) == 2) // Monday is first day of week + return [_dayNames objectAtIndex:(dayOfWeek+1)%7]; + + return [_dayNames objectAtIndex:dayOfWeek]; // Sunday is first day of week +} + +- (NSArray *)daysInFinalWeekOfPreviousMonth +{ + NSDate *savedState = [_calendarInfo date]; + NSMutableArray *days = [NSMutableArray array]; + + [_calendarInfo moveToFirstDayOfMonth]; + [_calendarInfo moveToPreviousDay]; + NSInteger year = [_calendarInfo year]; + NSInteger month = [_calendarInfo month]; + NSInteger lastDayOfPreviousMonth = [_calendarInfo dayOfMonth]; + NSInteger lastDayOfWeekInPreviousMonth = [_calendarInfo dayOfWeek]; + + if (lastDayOfWeekInPreviousMonth != 7) + for (NSInteger day = 1 + lastDayOfPreviousMonth - lastDayOfWeekInPreviousMonth; day <= lastDayOfPreviousMonth; day++) { + KLDate *d = [[KLDate alloc] initWithYear:year month:month day:day]; + [days addObject:d]; + [d release]; + } + + + [_calendarInfo setDate:savedState]; + return days; +} + +- (NSArray *)daysInSelectedMonth +{ + NSDate *savedState = [_calendarInfo date]; + NSMutableArray *days = [NSMutableArray array]; + + NSInteger year = [_calendarInfo year]; + NSInteger month = [_calendarInfo month]; + NSInteger lastDayOfMonth = [_calendarInfo daysInMonth]; + + for (NSInteger day = 1; day <= lastDayOfMonth; day++) { + KLDate *d = [[KLDate alloc] initWithYear:year month:month day:day]; + [days addObject:d]; + [d release]; + } + + [_calendarInfo setDate:savedState]; + + return days; +} + +- (NSArray *)daysInFirstWeekOfFollowingMonth +{ + NSDate *savedState = [_calendarInfo date]; + NSMutableArray *days = [NSMutableArray array]; + + [_calendarInfo moveToNextMonth]; + [_calendarInfo moveToFirstDayOfMonth]; + NSInteger year = [_calendarInfo year]; + NSInteger month = [_calendarInfo month]; + NSInteger firstDayOfWeekInFollowingMonth = [_calendarInfo dayOfWeek]; + + if (firstDayOfWeekInFollowingMonth != 1) + for (NSInteger day = 1; day <= 8-firstDayOfWeekInFollowingMonth; day++) { + KLDate *d = [[KLDate alloc] initWithYear:year month:month day:day]; + [days addObject:d]; + [d release]; + } + + [_calendarInfo setDate:savedState]; + return days; +} + +- (void)dealloc +{ + CFRelease(_cal); + [_calendarInfo release]; + [_dayNames release]; + [super dealloc]; +} + +@end + + + + + diff --git a/Calendar/KLCalendarView.h b/Calendar/KLCalendarView.h new file mode 100644 index 0000000..c857246 --- /dev/null +++ b/Calendar/KLCalendarView.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2008, Keith Lazuka, dba The Polypeptides + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Neither the name of the The Polypeptides nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Keith Lazuka ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Keith Lazuka BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#import +#import +#import + +#import "KLTile.h" +#import "KLDate.h" + +#define KL_CHANGE_MONTH_BUTTON_WIDTH 44.0f +#define KL_CHANGE_MONTH_BUTTON_HEIGHT 32.0f +#define KL_SELECTED_MONTH_WIDTH 200.0f +#define KL_HEADER_HEIGHT 27.0f +#define KL_HEADER_FONT_SIZE (KL_HEADER_HEIGHT-6.0f) + +@class KLCalendarModel, KLGridView, KLTile; +@protocol KLCalendarViewDelegate; + +@interface KLCalendarView : UIView +{ + IBOutlet id delegate; + KLCalendarModel *_model; + UILabel *_selectedMonthLabel; + KLGridView *_grid; + NSMutableArray *_trackedTouchPoints; // the gesture's sequential position in calendar view coordinates +} + +@property(nonatomic, assign) id delegate; +@property(nonatomic, retain) KLGridView *grid; + +- (id)initWithFrame:(CGRect)frame delegate:(id )delegate; + +- (BOOL)isZoomedIn; +- (void)zoomInOnTile:(KLTile *)tile; +- (void)zoomOutFromTile:(KLTile *)tile; +- (void)panToTile:(KLTile *)tile; +- (KLTile *)leftNeighborOfTile:(KLTile *)tile; +- (KLTile *)rightNeighborOfTile:(KLTile *)tile; +- (void)redrawNeighborsAndTile:(KLTile *)tile; // when zooming in, only redraw the chosen tile and adjacent tiles +- (NSString *)selectedMonthName; +- (NSInteger)selectedMonthNumberOfWeeks; + +@end + +// +// The delegate for handling date selection and appearance +// +// NOTES: Your application controller should implement this protocol +// to create & configure tiles when the selected month changes, +// and in order to respond to the user's taps on tiles. +// +@protocol KLCalendarViewDelegate +@required +- (void)calendarView:(KLCalendarView *)calendarView tappedTile:(KLTile *)aTile; +- (KLTile *)calendarView:(KLCalendarView *)calendarView createTileForDate:(KLDate *)date; +- (void)didChangeMonths; +@optional +- (void)wasSwipedToTheLeft; +- (void)wasSwipedToTheRight; +@end \ No newline at end of file diff --git a/Calendar/KLCalendarView.m b/Calendar/KLCalendarView.m new file mode 100644 index 0000000..de8781a --- /dev/null +++ b/Calendar/KLCalendarView.m @@ -0,0 +1,535 @@ +/* + * Copyright (c) 2008, Keith Lazuka, dba The Polypeptides + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Neither the name of the The Polypeptides nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Keith Lazuka ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Keith Lazuka BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// +// NOTES +// +// (1) Everything is drawn relative to self's bounds so that +// the graphics can be scaled nicely just by changing the bounds. +// +// (2) The calendar manages switching between months. +// +// (3) When the month changes (or is first loaded), the calendar +// will send the 'didChangeMonths' message to the delegate +// and it will give the delegate an opportunity to configure +// each tile that is part of the selected month. +// + +#import "KLCalendarView.h" +#import "KLCalendarModel.h" +#import "KLGridView.h" +#import "KLColors.h" +#import "THCalendarInfo.h" +#import "KLGraphicsUtils.h" + +static const CGFloat ScaleFactor = 4.0f; // for zooming in/out. You can try changing this, but no guarantees! + +@interface KLCalendarView () +- (void)addUI; +- (void)addTilesToGrid:(KLGridView *)grid; +- (void)refreshViewWithPushDirection:(NSString *)caTransitionSubtype; +- (void)showPreviousMonth; +- (void)showFollowingMonth; +@end + +@implementation KLCalendarView + +@synthesize delegate, grid = _grid; + +- (id)initWithFrame:(CGRect)frame delegate:(id )aDelegate +{ + if (![super initWithFrame:frame]) + return nil; + + self.delegate = aDelegate; + self.backgroundColor = [UIColor colorWithCGColor:kCalendarBodyLightColor]; + //self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + //self.autoresizesSubviews = YES; + _trackedTouchPoints = [[NSMutableArray alloc] init]; + _model = [[KLCalendarModel alloc] init]; + [self addUI]; // Draw the calendar itself (arrows, month & year name, empty grid) + [self refreshViewWithPushDirection:nil]; // add tiles to the grid + + return self; +} + +- (CGFloat)headerHeight { return 0.13707f*self.bounds.size.height; } + +// -------------------------------------------------------------------------------------------- +// drawDayNamesInContext: +// +// Draw the day names (Sunday, Monday, Tuesday, etc.) across the top of the grid +// +- (void)drawDayNamesInContext:(CGContextRef)ctx +{ + NSLog(@"%d", self.bounds.size.width); + + CGContextSaveGState(ctx); + CGContextSetFillColorWithColor(ctx, kTileRegularTopColor); + CGContextSetShadowWithColor(ctx, CGSizeMake(0.0f, -1.0f), 1.0f, kWhiteColor); + + for (NSInteger columnIndex = 0; columnIndex < 7; columnIndex++) { + NSString *header = [_model dayNameAbbreviationForDayOfWeek:columnIndex]; + + CGFloat columnWidth = self.bounds.size.width / 7; + + + + CGFloat fontSize = 0.25f * columnWidth; + CGFloat xOffset = columnIndex * columnWidth; + CGFloat yOffset = (0.94f * [self headerHeight]) - fontSize; + +// NSLog(@"col width = %f7, fontSize = %f", columnWidth, fontSize); + + [header drawInRect:CGRectMake(xOffset, yOffset, columnWidth, fontSize) withFont: [UIFont boldSystemFontOfSize:fontSize] lineBreakMode: UILineBreakModeClip alignment: UITextAlignmentCenter]; + } + + CGContextRestoreGState(ctx); +} + +// -------------------------------------------------------------------------------------------- +// drawGradientHeaderInContext: +// +// Draw the subtle gray vertical gradient behind the month, year, arrows, and day names +// +- (void)drawGradientHeaderInContext:(CGContextRef)ctx +{ + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + + CGColorRef rawColors[2] = { kCalendarHeaderLightColor, kCalendarHeaderDarkColor }; + CFArrayRef colors = CFArrayCreate(NULL, (void*)&rawColors, 2, NULL); + + CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, colors, NULL); + CGContextDrawLinearGradient(ctx, gradient, CGPointMake(0,0), CGPointMake(0, [self headerHeight]), kCGGradientDrawsBeforeStartLocation); + + CGGradientRelease(gradient); + CFRelease(colors); + CGColorSpaceRelease(colorSpace); +} + + +// -------------------------------------------------------------------------------------------- +// drawRect: +// +- (void)drawRect:(CGRect)frame +{ + CGContextRef ctx = UIGraphicsGetCurrentContext(); + [self drawGradientHeaderInContext:ctx]; + [self drawDayNamesInContext:ctx]; +} + +// -------------------------------------------------------------------------------------------- +// tileInSelectedMonthTapped: +// +// A good place to ask the delegate for what to do when a main tile is tapped. +// This is the main interaction for a calendar app. +// +- (void)tileInSelectedMonthTapped:(KLTile *)tile +{ + NSAssert(self.delegate, @"CalendarView's delegate is required for handling calendar tile taps!"); + [self.delegate calendarView:self tappedTile:tile]; +} + +// -------------------------------------------------------------------------------------------- +// addTilesToView: +// +// Add tiles for each date in the weeks of the selected month to the scene. +// This is called when the calendar is first loaded and whenever the user +// switches between months. The KLGridView will handle laying out the tiles. +// +// If you're looking for places to optimize, this code should probably +// be modified to re-use tiles instead of just trashing them to create new ones +// every time the user switches between months. +// +- (void)addTilesToGrid:(KLGridView *)grid +{ + // tiles for dates that belong to the final week of the previous month + for (KLDate *date in [_model daysInFinalWeekOfPreviousMonth]) { + KLTile *tile = [self.delegate calendarView:self createTileForDate:date]; + [tile addTarget:self action:@selector(showPreviousMonth) forControlEvents:UIControlEventTouchUpInside]; + tile.date = date; + tile.text = [NSString stringWithFormat:@"%ld", (long)[date dayOfMonth]]; + tile.opaque = NO; + tile.alpha = 0.4f; + [grid addTile:tile]; + [tile release]; + } + + // tiles for dates that belong to the selected month + NSArray *days = [_model daysInSelectedMonth]; + for (KLDate *date in days) { + KLTile *tile = [self.delegate calendarView:self createTileForDate:date]; + [tile addTarget:self action:@selector(tileInSelectedMonthTapped:) forControlEvents:UIControlEventTouchUpInside]; + tile.date = date; + tile.text = [NSString stringWithFormat:@"%ld", (long)[date dayOfMonth]]; + [grid addTile:tile]; + [tile release]; + } + + // tiles for dates that belong to the first week of the following month + for (KLDate *date in [_model daysInFirstWeekOfFollowingMonth]) { + KLTile *tile = [self.delegate calendarView:self createTileForDate:date]; + [tile addTarget:self action:@selector(showFollowingMonth) forControlEvents:UIControlEventTouchUpInside]; + tile.date = date; + tile.text = [NSString stringWithFormat:@"%ld", (long)[date dayOfMonth]]; + tile.opaque = NO; + tile.alpha = 0.4f; + [grid addTile:tile]; + [tile release]; + } +} + +// -------------------------------------------------------------------------------------------- +// addUI: +// +// Create the calendar header buttons and labels and add them to the calendar view. +// This setup is only performed once during the life of the calendar. +// +- (void)addUI +{ + // Create the previous month button on the left side of the view + CGRect previousMonthButtonFrame = CGRectMake(self.bounds.origin.x, + self.bounds.origin.y, + KL_CHANGE_MONTH_BUTTON_WIDTH, + KL_CHANGE_MONTH_BUTTON_HEIGHT); + UIButton *previousMonthButton = [[UIButton alloc] initWithFrame:previousMonthButtonFrame]; + [previousMonthButton setImage:[UIImage imageNamed:@"left-arrow.png"] forState:UIControlStateNormal]; + previousMonthButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter; + previousMonthButton.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter; + [previousMonthButton addTarget:self action:@selector(showPreviousMonth) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:previousMonthButton]; + [previousMonthButton release]; + + // Draw the selected month name centered and at the top of the view + CGRect selectedMonthLabelFrame = CGRectMake((self.bounds.size.width/2.0f) - (KL_SELECTED_MONTH_WIDTH/2.0f), + self.bounds.origin.y, + KL_SELECTED_MONTH_WIDTH, + KL_HEADER_HEIGHT); + _selectedMonthLabel = [[UILabel alloc] initWithFrame:selectedMonthLabelFrame]; + _selectedMonthLabel.textColor = [UIColor colorWithCGColor:kTileRegularTopColor]; + _selectedMonthLabel.backgroundColor = [UIColor clearColor]; + _selectedMonthLabel.font = [UIFont boldSystemFontOfSize:KL_HEADER_FONT_SIZE]; + _selectedMonthLabel.textAlignment = UITextAlignmentCenter; + [self addSubview:_selectedMonthLabel]; + + // Create the next month button on the right side of the view + CGRect nextMonthButtonFrame = CGRectMake(self.bounds.size.width - KL_CHANGE_MONTH_BUTTON_WIDTH, + self.bounds.origin.y, + KL_CHANGE_MONTH_BUTTON_WIDTH, + KL_CHANGE_MONTH_BUTTON_HEIGHT); + UIButton *nextMonthButton = [[UIButton alloc] initWithFrame:nextMonthButtonFrame]; + [nextMonthButton setImage:[UIImage imageNamed:@"right-arrow.png"] forState:UIControlStateNormal]; + nextMonthButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter; + nextMonthButton.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter; + [nextMonthButton addTarget:self action:@selector(showFollowingMonth) forControlEvents:UIControlEventTouchUpInside]; + [self addSubview:nextMonthButton]; + [nextMonthButton release]; + + // The Grid of tiles + self.grid = [[[KLGridView alloc] initWithFrame:CGRectMake(0,[self headerHeight],320,self.bounds.size.height - [self headerHeight])] autorelease]; + [self addSubview:self.grid]; +} + +- (void)clearAndFillGrid +{ + [self.grid removeAllTiles]; + [self addTilesToGrid:self.grid]; + + [self.delegate didChangeMonths]; +} + +// -------------------------------------------------------------------------------------------- +// refreshViewWithPushDirection: +// +// Triggered when the calendar is first created and whenever the selected month changes. +// +- (void)refreshViewWithPushDirection:(NSString *)caTransitionSubtype +{ + // Update the header month and year + _selectedMonthLabel.text = [NSString stringWithFormat:@"%@ %ld", [_model selectedMonthName], (long)[_model selectedYear]]; + + if (!caTransitionSubtype) { // refresh without animation + [self clearAndFillGrid]; + return; + } + + // Configure the animation for sliding the tiles in + [CATransaction begin]; + [CATransaction setValue:[NSNumber numberWithBool:YES] forKey:kCATransactionDisableActions]; + [CATransaction setValue:[NSNumber numberWithFloat:0.5f] forKey:kCATransactionAnimationDuration]; + + CATransition *push = [CATransition animation]; + push.type = kCATransitionPush; + push.subtype = caTransitionSubtype; + [self.grid.layer addAnimation:push forKey:kCATransition]; + [self clearAndFillGrid]; + + [CATransaction commit]; +} + +// -------------------------------------------------------------------------------------------- +// showPreviousMonth +// +// Triggered whenever the previous button is tapped or when a date in +// the previous month is tapped. Selects the previous month and updates the view. +// Note that it is disabled while the calendar is in editing mode. +// +- (void)showPreviousMonth +{ + if ([self isZoomedIn]) + return; // do not allow it when zoomed in + + [_model decrementMonth]; + [self refreshViewWithPushDirection:kCATransitionFromLeft]; +} + +// -------------------------------------------------------------------------------------------- +// showFollowingMonth +// +// Triggered whenever the 'next' button is tapped or when a date in +// the following month is tapped. Selects the next month and updates the view. +// Note that it is disabled while the calendar is in editing mode. +// + +- (void)showFollowingMonth +{ + if ([self isZoomedIn]) + return; // do not allow it when zoomed in + + [_model incrementMonth]; + [self refreshViewWithPushDirection:kCATransitionFromRight]; +} + +// -------------------------------------------------------------------------------------------- +// panBounds:toTile:scaleFactor +// +// Adjusts the provided 'bounds' rectangle such that the given tile is centered. +// NOTE: This does not actually change the CalendarView's bounds, +// it just modifies the bounds passed in. +// NOTE: When setting up the pan before a zoom, make sure you set the scaleFactor +// to the amount that you are about to zoom by. +// If you are panning the calendar when it is ALREADY zoomed, +// then set scaleFactor to 1.0f +// +- (void)panBounds:(CGRect*)bounds toTile:(KLTile *)tile scaleFactor:(const CGFloat)scaleFactor +{ + UIView *clipView = [self superview]; + CGPoint clipCenter = CGPointMake(clipView.bounds.size.width/2, clipView.bounds.size.height/2); + CGPoint tileCenterInClipCoordinates = [clipView convertPoint:CGPointMake(tile.bounds.size.width/2, tile.bounds.size.height/2) fromView:tile]; + bounds->origin.x -= scaleFactor * (clipCenter.x - tileCenterInClipCoordinates.x); + bounds->origin.y -= scaleFactor * (clipCenter.y - tileCenterInClipCoordinates.y); +} + +// assumes that no scaling is required since the calendar is already zoomed in +- (void)panToTile:(KLTile *)tile +{ + [UIView beginAnimations:nil context:NULL]; + CGRect bounds = self.bounds; + + // pan + [self panBounds:&bounds toTile:tile scaleFactor:1.f]; + self.bounds = bounds; + + // update + [self setNeedsDisplay]; + [self.grid redrawNeighborsAndTile:tile]; + [UIView commitAnimations]; +} + + +// -------------------------------------------------------------------------------------------- +// zoomInOnTile: +// +// Zoom the calendarView and pan such that the given tile is centered +// +- (void)zoomInOnTile:(KLTile *)tile +{ + [UIView beginAnimations:nil context:NULL]; + CGRect bounds = self.bounds; + + // pan + [self panBounds:&bounds toTile:tile scaleFactor:ScaleFactor]; + + // zoom + bounds.size.width *= ScaleFactor; + bounds.size.height *= ScaleFactor; + self.bounds = bounds; + + // update + [self setNeedsDisplay]; + [self.grid redrawNeighborsAndTile:tile]; + [UIView commitAnimations]; +} + +// -------------------------------------------------------------------------------------------- +// zoomOutFromTile: +// +// Zoom the calendarView out to normal size so that the entire month is visible. +// +- (void)zoomOutFromTile:(KLTile *)tile +{ + [UIView beginAnimations:nil context:NULL]; + CGRect bounds = self.bounds; + + bounds.size.width /= ScaleFactor; + bounds.size.height /= ScaleFactor; + bounds.origin.x = bounds.origin.y = 0.0f; + self.bounds = bounds; + + [self setNeedsDisplay]; + [self.grid redrawAllTiles]; // the current chain might have changed so we redraw all tiles, not just the neighbors + [UIView commitAnimations]; +} + + +// -------------------------------------------------------------------------------------------- +// isZoomedIn +// +// Returns YES if the calendar is zoomed in on a tile. +// +- (BOOL)isZoomedIn +{ + return self.bounds.size.width / ScaleFactor == self.superview.bounds.size.width; +} + +// -------------------------------------------------------------------------------------------- +// redrawNeighborsAndTile: +// +// Tells the calendar to redraw the given tile along with its adjacent tiles. +// Motivation: when I zoom into the calendar, there is no need to redraw all of the tiles +// since only the centered tile and its neighbors will be visible. +// +- (void)redrawNeighborsAndTile:(KLTile *)tile +{ + [self.grid redrawNeighborsAndTile:tile]; +} + +// -------------------------------------------------------------------------------------------- +// selectedMonthName +// +// Returns the name of the month currently being displayed +// +- (NSString *)selectedMonthName +{ + return [_model selectedMonthName]; +} + +// -------------------------------------------------------------------------------------------- +// selectedMonthNumberOfWeeks +// +// Returns the number of weeks that the calendar is currently displaying +// +- (NSInteger)selectedMonthNumberOfWeeks +{ + return [_model selectedMonthNumberOfWeeks]; +} + + +// -------------------------------------------------------------------------------------------- +// touchesBegan:withEvent: +// +// Begin tracking a horizontal swipe, single finger +// +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event +{ + [_trackedTouchPoints removeAllObjects]; + UITouch *touch = [touches anyObject]; + [_trackedTouchPoints addObject:[NSValue valueWithCGPoint:[touch locationInView:self]]]; +} + +// -------------------------------------------------------------------------------------------- +// touchesMoved:withEvent: +// +// Continue tracking a horizontal swipe, single finger +// +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event +{ + UITouch *touch = [touches anyObject]; + [_trackedTouchPoints addObject:[NSValue valueWithCGPoint:[touch locationInView:self]]]; +} + +// -------------------------------------------------------------------------------------------- +// touchesEnded:withEvent: +// +// Notifies the delegate when a horizontal swipe occurs +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event +{ + UITouch *touch = [touches anyObject]; + [_trackedTouchPoints addObject:[NSValue valueWithCGPoint:[touch locationInView:self]]]; + + // bail out if the delegate doesn't implement the swipe gesture handlers + if (![self.delegate respondsToSelector:@selector(wasSwipedToTheRight)] + || ![self.delegate respondsToSelector:@selector(wasSwipedToTheLeft)]) + return; + + CGFloat minX, maxX, minY, maxY; + minX = minY = INFINITY; + maxX = maxY = 0.f; + + for (NSValue *v in _trackedTouchPoints) { + CGPoint point = [v CGPointValue]; + minX = MIN(point.x, minX); + maxX = MAX(point.x, maxX); + minY = MIN(point.y, minY); + maxY = MAX(point.y, maxY); + } + + if (abs(minY-maxY) < 30) { + // okay, it's close enough to horizontal + if (abs(minX-maxX) > 40) { + // okay, it's long enough to be a swipe + CGFloat firstX = [[_trackedTouchPoints objectAtIndex:0] CGPointValue].x; + CGFloat lastX = [[_trackedTouchPoints lastObject] CGPointValue].x; + if (firstX < lastX){ + [self showPreviousMonth]; + [self.delegate wasSwipedToTheRight]; + } + else{ + [self showFollowingMonth]; + [self.delegate wasSwipedToTheLeft]; + } + } + } + + +} + +- (KLTile *)leftNeighborOfTile:(KLTile *)tile { return [self.grid leftNeighborOfTile:tile]; } +- (KLTile *)rightNeighborOfTile:(KLTile *)tile { return [self.grid rightNeighborOfTile:tile]; } + + + +// -------------------------------------------------------------------------------------------- +// dealloc +// +- (void)dealloc { + [_trackedTouchPoints release]; + [_model release]; + [_selectedMonthLabel release]; + [_grid release]; + [super dealloc]; +} + +@end + diff --git a/Calendar/KLColors.h b/Calendar/KLColors.h new file mode 100644 index 0000000..4873052 --- /dev/null +++ b/Calendar/KLColors.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008, Keith Lazuka, dba The Polypeptides + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Neither the name of the The Polypeptides nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Keith Lazuka ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Keith Lazuka BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import + +extern CGColorRef kSlateBlueColor, kGridDarkColor, kGridLightColor, kCheckmarkColor, +kCalendarHeaderLightColor, kCalendarHeaderDarkColor, +kCalendarBodyLightColor, kCalendarBodyDarkColor, +kLightCharcoalColor, kDarkCharcoalColor, +kTileRegularTopColor, kTileRegularBottomColor, +kTileDimTopColor, kTileDimBottomColor; + +extern CGColorRef kBlackColor, kWhiteColor; + +CGColorRef CreateGray(CGFloat gray, CGFloat alpha); +CGColorRef CreateRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha); + + + + diff --git a/Calendar/KLColors.m b/Calendar/KLColors.m new file mode 100644 index 0000000..ae0491e --- /dev/null +++ b/Calendar/KLColors.m @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2008, Keith Lazuka, dba The Polypeptides + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Neither the name of the The Polypeptides nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Keith Lazuka ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Keith Lazuka BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#import "KLColors.h" +#import "KLGraphicsUtils.h" + +// Colors derived from Apple's calendar +CGColorRef kSlateBlueColor, kGridDarkColor, kGridLightColor, kCheckmarkColor, + kCalendarHeaderLightColor, kCalendarHeaderDarkColor, + kCalendarBodyLightColor, kCalendarBodyDarkColor, + kLightCharcoalColor, kDarkCharcoalColor, + kTileRegularTopColor, kTileRegularBottomColor, + kTileDimTopColor, kTileDimBottomColor; + +// Basic grayscale colors +CGColorRef kBlackColor, kWhiteColor; + + +__attribute__((constructor)) // Makes this function run when the app loads +static void InitKColors() +{ + kSlateBlueColor = CreateRGB(0.451f, 0.537f, 0.647f, 1.0f); + kGridDarkColor = CreateRGB(0.667f, 0.682f, 0.714f, 1.0f); + kGridLightColor = CreateRGB(0.953f, 0.953f, 0.961f, 1.0f); + kCalendarHeaderLightColor = CreateRGB(0.965f, 0.965f, 0.969f, 1.0f); + kCalendarHeaderDarkColor = CreateRGB(0.808f, 0.808f, 0.824f, 1.0f); + kCalendarBodyLightColor = CreateRGB(0.890f, 0.886f, 0.898f, 1.0f); + kCalendarBodyDarkColor = CreateRGB(0.784f, 0.748f, 0.804f, 1.0f); + kLightCharcoalColor = CreateRGB(0.3f, 0.3f, 0.3f, 1.0f); + kDarkCharcoalColor = CreateRGB(0.1f, 0.1f, 0.1f, 1.0f); + kTileRegularTopColor = CreateRGB(0.173f, 0.212f, 0.255f, 1.0f); + kTileRegularBottomColor = CreateRGB(0.294f, 0.361f, 0.435f, 1.0f); + kTileDimTopColor = CreateRGB(0.545f, 0.565f, 0.588f, 1.0f); + kTileDimBottomColor = CreateRGB(0.600f, 0.635f, 0.675f, 1.0f); + + kBlackColor = CreateGray(0.0f, 1.0f); + kWhiteColor = CreateGray(1.0f, 1.0f); +} + +CGColorRef CreateGray(CGFloat gray, CGFloat alpha) +{ + CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceGray(); + CGFloat components[2] = {gray, alpha}; + CGColorRef color = CGColorCreate(colorspace, components); + CGColorSpaceRelease(colorspace); + return color; +} + +CGColorRef CreateRGB(CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha) +{ + CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); + CGFloat components[4] = {red, green, blue, alpha}; + CGColorRef color = CGColorCreate(colorspace, components); + CGColorSpaceRelease(colorspace); + return color; +} + + + diff --git a/Calendar/KLDate.h b/Calendar/KLDate.h new file mode 100644 index 0000000..02fe70a --- /dev/null +++ b/Calendar/KLDate.h @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2008, Keith Lazuka, dba The Polypeptides + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Neither the name of the The Polypeptides nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Keith Lazuka ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Keith Lazuka BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// +// NOTES +// +// (1) KLDate was created because I didn't want to mess around with time, +// just dates. Also, some of the CFCalendar* functions are quite +// slow on the iPhone (or at least they were in iPhone OS 2.0 +// when I created this class). +// +// (2) Special effort was made such that changing the iPhone's +// regional format and timezone would not change the logical date. +// This was needed in my application, Goalkeep, because the purpose +// of the app was to chain together several days in a row. If you +// changed the timezone or the regional format, I didn't want the +// chain to break just because of international time issues. +// +// (3) Considering the above notes, it may be prudent +// to replace KLDate with NSDate. +// + +#import + +@interface KLDate : NSObject { + NSInteger _year, _month, _day; +} + ++ (id)today; + +// Designated initializer +- (id)initWithYear:(NSInteger)year month:(NSUInteger)month day:(NSUInteger)day; + +- (NSComparisonResult)compare:(KLDate *)otherDate; +- (NSInteger)yearOfCommonEra; +- (NSInteger)monthOfYear; +- (NSInteger)dayOfMonth; + +- (BOOL)isEarlierThan:(KLDate *)aDate; +- (BOOL)isLaterThan:(KLDate *)aDate; +- (BOOL)isToday; +- (BOOL)isTheDayBefore:(KLDate *)anotherDate; + +// NSCopying +- (id)copyWithZone:(NSZone *)zone; + +// NSCoding +- (id)initWithCoder:(NSCoder *)decoder; +- (void)encodeWithCoder:(NSCoder *)encoder; + +-(NSComparisonResult) compareWithNSDate: (NSDate*) date; +-(NSDate*) toNSDate; + +@end + + + + + + + + diff --git a/Calendar/KLDate.m b/Calendar/KLDate.m new file mode 100644 index 0000000..0f55e18 --- /dev/null +++ b/Calendar/KLDate.m @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2008, Keith Lazuka, dba The Polypeptides + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Neither the name of the The Polypeptides nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Keith Lazuka ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Keith Lazuka BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#import "KLDate.h" + +static KLDate *Today; + +static BOOL IsLeapYear(NSInteger year) +{ + return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); +} + +@implementation KLDate + ++ (id)today +{ + if (!Today) { + NSInteger year, month, day; + CFAbsoluteTime absoluteTime = CFDateGetAbsoluteTime((CFDateRef)[NSDate date]); + CFCalendarRef calendar = CFCalendarCopyCurrent(); + CFCalendarDecomposeAbsoluteTime(calendar, absoluteTime, "yMd", &year, &month, &day); + CFRelease(calendar); + Today = [[KLDate alloc] initWithYear:year month:month day:day]; + } + + return Today; +} + +// Designated initializer +- (id)initWithYear:(NSInteger)year month:(NSUInteger)month day:(NSUInteger)day +{ + NSParameterAssert(1 <= month && month <= 12); + NSParameterAssert(1 <= day && day <= 31); + + if (![super init]) + return nil; + + _year = year; + _month = month; + _day = day; + + return self; +} + + + +#pragma mark NSCopying +- (id)copyWithZone:(NSZone *)zone +{ + return [[KLDate allocWithZone:zone] initWithYear:_year month:_month day:_day]; +} + +#pragma mark NSCoding +- (id)initWithCoder:(NSCoder *)decoder +{ + // super is an NSObject and does not implement NSCoding, so we use designated initializer instead + if (![super init]) + return nil; + + [decoder decodeValueOfObjCType:@encode(NSInteger) at:(void*)&_year]; + [decoder decodeValueOfObjCType:@encode(NSInteger) at:(void*)&_month]; + [decoder decodeValueOfObjCType:@encode(NSInteger) at:(void*)&_day]; + + return self; +} + +- (void)encodeWithCoder:(NSCoder *)encoder +{ + // super is an NSObject and does not implement NSCoding, so we don't tell super to encode itself + [encoder encodeValueOfObjCType:@encode(NSInteger) at:(void*)&_year]; + [encoder encodeValueOfObjCType:@encode(NSInteger) at:(void*)&_month]; + [encoder encodeValueOfObjCType:@encode(NSInteger) at:(void*)&_day]; +} + +#pragma mark Operations + +- (NSComparisonResult)compare:(KLDate *)otherDate +{ + NSInteger selfComposite = ([self yearOfCommonEra]*10000) + + ([self monthOfYear]*100) + + [self dayOfMonth]; + + NSInteger otherComposite = ([otherDate yearOfCommonEra]*10000) + + ([otherDate monthOfYear]*100) + + [otherDate dayOfMonth]; + + if (selfComposite < otherComposite) + return NSOrderedAscending; + else if (selfComposite == otherComposite) + return NSOrderedSame; + else + return NSOrderedDescending; +} + +-(NSComparisonResult) compareWithNSDate: (NSDate*) date +{ + NSInteger selfComposite = ([self yearOfCommonEra]*10000) + + ([self monthOfYear]*100) + + [self dayOfMonth]; + + NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; + NSDateComponents* components = [gregorian components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate:date]; + + NSInteger otherComposite = ([components year] *10000) + + ([components month]*100) + + [components day]; + +// NSLog(@"%d %d", selfComposite, otherComposite); + + if (selfComposite < otherComposite) + return NSOrderedAscending; + else if (selfComposite == otherComposite) + { +// NSLog(@"same"); + return NSOrderedSame; + } + else + return NSOrderedDescending; +} + +-(NSDate*) toNSDate +{ + NSDateComponents* components = [[NSDateComponents alloc] init]; + [components setDay: [self dayOfMonth]]; + [components setMonth:[self monthOfYear]]; + [components setYear:[self yearOfCommonEra]]; + + NSCalendar *gregorian = [[NSCalendar alloc] + initWithCalendarIdentifier:NSGregorianCalendar]; + NSDate *date = [gregorian dateFromComponents:components]; + return date; +} + +- (BOOL)isEarlierThan:(KLDate *)aDate +{ + return ([self compare:aDate] == NSOrderedAscending); +} + +- (BOOL)isLaterThan:(KLDate *)aDate +{ + return ([self compare:aDate] == NSOrderedDescending); +} + +- (BOOL)isToday +{ + return ([self compare:[KLDate today]] == NSOrderedSame); +} + +- (BOOL)isEqual:(id)anObject +{ + if ([anObject isKindOfClass:[self class]]) { + return [self compare:anObject] == NSOrderedSame; + } else { + return NO; + } +} + +- (NSUInteger)hash +{ + return [self monthOfYear]; +} + +- (NSString *)description +{ + if([self monthOfYear] <10 && [self dayOfMonth]<10 ) + return [NSString stringWithFormat:@"%ld-0%ld-0%ld",(long)[self yearOfCommonEra],(long)[self monthOfYear],(long)[self dayOfMonth]]; + else if([self monthOfYear] <10) + return [NSString stringWithFormat:@"%ld-0%ld-%ld",(long)[self yearOfCommonEra],(long)[self monthOfYear],(long)[self dayOfMonth]]; + else if ([self dayOfMonth]<10) + return [NSString stringWithFormat:@"%ld-%ld-0%ld",(long)[self yearOfCommonEra],(long)[self monthOfYear],(long)[self dayOfMonth]]; + else + return [NSString stringWithFormat:@"%ld-%ld-%ld",(long)[self yearOfCommonEra],(long)[self monthOfYear],(long)[self dayOfMonth]]; +} +-(NSString*)previousDay +{ + if([self monthOfYear] <10 && [self dayOfMonth]<11 ) + return [NSString stringWithFormat:@"%ld-0%ld-0%ld",(long)[self yearOfCommonEra],(long)[self monthOfYear],(long)([self dayOfMonth]+1)]; + else if([self monthOfYear] <10) + return [NSString stringWithFormat:@"%ld-0%ld-%ld",(long)[self yearOfCommonEra],(long)[self monthOfYear],(long)([self dayOfMonth]+1)]; + else if ([self dayOfMonth]<11) + return [NSString stringWithFormat:@"%ld-%ld-0%ld",(long)[self yearOfCommonEra],(long)[self monthOfYear],(long)([self dayOfMonth]+1)]; + else + return [NSString stringWithFormat:@"%ld-%ld-%ld",(long)[self yearOfCommonEra],(long)[self monthOfYear],(long)([self dayOfMonth]+1)]; +} + +#pragma mark NSCalendarDate-like interface +- (NSInteger)yearOfCommonEra +{ + return _year; +} + +- (NSInteger)monthOfYear +{ + return _month; +} + +- (NSInteger)dayOfMonth +{ + return _day; +} + +- (BOOL)isTheLastDayOfTheYear { return _month == 12 && _day == 31; } +- (BOOL)isTheFirstDayOfTheYear { return _month == 1 && _day == 1; } + +- (BOOL)isTheDayBefore:(KLDate *)anotherDate +{ + // trivial case first + if (![self isEarlierThan:anotherDate]) + return NO; + + // at this point, I know that self is earlier than anotherDate + if ([anotherDate yearOfCommonEra] - _year > 1) + return NO; + else if ([anotherDate yearOfCommonEra] - _year == 1) + return [self isTheLastDayOfTheYear] && [anotherDate isTheFirstDayOfTheYear]; + + // at this point, I know that self and anotherDate are both in the same year + if ([anotherDate monthOfYear] - _month > 1) + return NO; + else if (_month == [anotherDate monthOfYear]) + return [anotherDate dayOfMonth] - _day == 1; + + // at this point, self is in the month before anotherDate + if ([anotherDate dayOfMonth] != 1) + return NO; + + // at this point, self is in the month before anotherDate, and anotherDate is the first day in its month + + switch (_month) { + case 1: + return _day == 31; + case 2: + return IsLeapYear(_year) ? _day == 29 : _day == 28; + case 3: + return _day == 31; + case 4: + return _day == 30; + case 5: + return _day == 31; + case 6: + return _day == 30; + case 7: + return _day == 31; + case 8: + return _day == 31; + case 9: + return _day == 30; + case 10: + return _day == 31; + case 11: + return _day == 30; + case 12: + return _day == 31; + default: + NSAssert(NO, @"Fell through switch statement in [KLDate isTheDayBefore:]"); + break; + } + return NO; +} + +@end diff --git a/Calendar/KLGraphicsUtils.h b/Calendar/KLGraphicsUtils.h new file mode 100644 index 0000000..01e74d4 --- /dev/null +++ b/Calendar/KLGraphicsUtils.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2008, Keith Lazuka, dba The Polypeptides + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Neither the name of the The Polypeptides nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Keith Lazuka ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Keith Lazuka BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import +#import +#import + +static inline CGFloat radians (CGFloat degrees) {return (CGFloat)(degrees * M_PI/180.0);} + +void MyDrawText (CGContextRef myContext, CGRect contextRect, CGFloat fontSize, const char *text, int length); +void MyDrawTextAsClip (CGContextRef myContext, CGRect contextRect, CGFloat fontSize, const char *text, int length); + +CGImageRef CreateCGImageFromCALayer(CALayer *sourceLayer); \ No newline at end of file diff --git a/Calendar/KLGraphicsUtils.m b/Calendar/KLGraphicsUtils.m new file mode 100644 index 0000000..f20ed4c --- /dev/null +++ b/Calendar/KLGraphicsUtils.m @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2008, Keith Lazuka, dba The Polypeptides + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Neither the name of the The Polypeptides nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Keith Lazuka ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Keith Lazuka BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "KLGraphicsUtils.h" +#import + +void MyDrawText (CGContextRef myContext, CGRect contextRect, CGFloat fontSize, const char *text, int length) +{ + float w, h; + w = contextRect.size.width; + h = contextRect.size.height; + + CGContextSaveGState(myContext); + CGContextSelectFont (myContext, + "Helvetica-Bold", + fontSize, + kCGEncodingMacRoman); + CGContextSetCharacterSpacing (myContext, 1); + CGContextSetTextDrawingMode (myContext, kCGTextFill); + CGContextSetRGBFillColor (myContext, 0, 0, 0, 1); + CGContextShowTextAtPoint (myContext, contextRect.origin.x, contextRect.origin.y, text, length); + CGContextRestoreGState(myContext); +} + +void MyDrawTextAsClip (CGContextRef myContext, CGRect contextRect, CGFloat fontSize, const char *text, int length) +{ + float w, h; + w = contextRect.size.width; + h = contextRect.size.height; + + CGContextSelectFont (myContext, + "Helvetica-Bold", + fontSize, + kCGEncodingMacRoman); + CGContextSetCharacterSpacing (myContext, 1); + CGContextSetTextDrawingMode (myContext, kCGTextClip); + CGContextSetRGBFillColor (myContext, 0, 0, 0, 1); + CGContextShowTextAtPoint (myContext, contextRect.origin.x, contextRect.origin.y, text, length); +} + +// -------------------------------------------------------------------------------------------- +// CreateCGImageFromCALayer() +// +// Given a Core Animation layer, render it in a bitmap context and return the CGImageRef +// +CGImageRef CreateCGImageFromCALayer(CALayer *sourceLayer) +{ + CGFloat width = sourceLayer.bounds.size.width; + CGFloat height = sourceLayer.bounds.size.height; + + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGContextRef ctx = CGBitmapContextCreate(NULL, width, height, 8, 4*width, colorSpace, kCGImageAlphaPremultipliedLast); + NSCAssert(ctx, @"failed to create bitmap context from CALayer"); + + // rotate 180 degrees and flip vertically (otherwise the CALayer will render backwards) + CGAffineTransform xform = CGAffineTransformMake(1.0f, 0.0f, 0.0f, -1.0f, 0.0f, width); + CGContextConcatCTM(ctx, xform); + + // rasterize the UIView's backing layer + [sourceLayer renderInContext:ctx]; + CGImageRef raster = CGBitmapContextCreateImage(ctx); + + CGColorSpaceRelease(colorSpace); + CGContextRelease(ctx); + + return raster; +} diff --git a/Calendar/KLGridView.h b/Calendar/KLGridView.h new file mode 100644 index 0000000..44e090d --- /dev/null +++ b/Calendar/KLGridView.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2008, Keith Lazuka, dba The Polypeptides + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Neither the name of the The Polypeptides nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Keith Lazuka ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Keith Lazuka BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#import + +@class KLTile; + +@interface KLGridView : UIView { + NSUInteger _numberOfColumns; + NSMutableArray *_tiles; +} + +@property(nonatomic, readonly) NSMutableArray* tiles; + +- (void)addTile:(KLTile *)tile; +- (void)removeAllTiles; + +- (void)redrawAllTiles; +- (void) resetAllTiles; +- (void)redrawNeighborsAndTile:(KLTile *)tile; +- (void)flipView:(UIView *)viewToBeRemoved toRevealView:(UIView *)replacementView transition:(UIViewAnimationTransition)transition; + +- (KLTile *)leftNeighborOfTile:(KLTile *)tile; +- (KLTile *)rightNeighborOfTile:(KLTile *)tile; + +//- (NSMutableArray*) tiles; + +@end diff --git a/Calendar/KLGridView.m b/Calendar/KLGridView.m new file mode 100644 index 0000000..a1239b5 --- /dev/null +++ b/Calendar/KLGridView.m @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2008, Keith Lazuka, dba The Polypeptides + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Neither the name of the The Polypeptides nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Keith Lazuka ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Keith Lazuka BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#import "KLGridView.h" +#import "KLTile.h" +#import "KLColors.h" + +@implementation KLGridView + +@synthesize tiles = _tiles; + +- (id)initWithFrame:(CGRect)frame +{ + if (![super initWithFrame:frame]) + return nil; + + self.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + self.clipsToBounds = YES; + self.backgroundColor = [UIColor colorWithCGColor:kCalendarBodyDarkColor]; + _numberOfColumns = 7; + _tiles = [[NSMutableArray alloc] init]; + + return self; +} + +- (CGFloat)columnWidth { return 1+floorf(self.bounds.size.width/_numberOfColumns); } // 46px when zoomed out + +- (void)layoutSubviews +{ + NSInteger currentColumnIndex = 0; + NSInteger currentRowIndex = 0; + + [UIView beginAnimations:nil context:NULL]; + for (UIView *tileContainer in [self subviews]) { + CGRect containerFrame = tileContainer.frame; + containerFrame.size.width = containerFrame.size.height = ([self columnWidth]); // square it up and zoom + containerFrame.origin.x = currentColumnIndex * [self columnWidth]; + containerFrame.origin.y = currentRowIndex * [self columnWidth]; // tiles are required to be square! + + KLTile *tile = [[tileContainer subviews] objectAtIndex:0]; + CGRect tileFrame = containerFrame; + tileFrame.origin.x = tileFrame.origin.y = 0.0f; + + tileContainer.frame = containerFrame; + tile.frame = tileFrame; + + currentColumnIndex++; + if (currentColumnIndex == _numberOfColumns) { + currentRowIndex++; + currentColumnIndex = 0; + } + } + [UIView commitAnimations]; +} + +// -------------------------------------------------------------------------------------------- +// addTile: +// +// The only way correct way to place a tile in the KLGridView +// +- (void)addTile:(KLTile *)tile +{ + UIView *container = [[[UIView alloc] initWithFrame:tile.frame] autorelease]; + [container addSubview:tile]; + [self addSubview:container]; + + [_tiles addObject:tile]; +} + +- (void)removeAllTiles +{ + for (KLTile *tile in _tiles) + [[tile superview] removeFromSuperview]; // remove the tile's container + [_tiles removeAllObjects]; +} + +- (void)flipView:(UIView *)viewToBeRemoved toRevealView:(UIView *)replacementView transition:(UIViewAnimationTransition)transition +{ + [UIView beginAnimations:nil context:NULL]; + [UIView setAnimationDuration:1]; + UIView *container = [viewToBeRemoved superview]; + [UIView setAnimationTransition:transition forView:container cache:YES]; + [viewToBeRemoved removeFromSuperview]; + [container addSubview:replacementView]; + [self setNeedsLayout]; + [UIView commitAnimations]; +} + +- (KLTile *)tileOrNilAtIndex:(NSInteger)tileIndex +{ + return (tileIndex >= 0 && tileIndex < [_tiles count]) ? [_tiles objectAtIndex:tileIndex] : nil; +} + +- (void)redrawAllTiles +{ + for (KLTile *tile in _tiles) + [tile setNeedsDisplay]; +} + +- (void)redrawNeighborsAndTile:(KLTile *)tile +{ + NSInteger tileIndex = [_tiles indexOfObject:tile]; + + [[self tileOrNilAtIndex:tileIndex-_numberOfColumns+1] setNeedsDisplay]; // top left + [[self tileOrNilAtIndex:tileIndex-_numberOfColumns] setNeedsDisplay]; // top + [[self tileOrNilAtIndex:tileIndex-_numberOfColumns-1] setNeedsDisplay]; // top right + [[self tileOrNilAtIndex:tileIndex-1] setNeedsDisplay]; // left + [[self tileOrNilAtIndex:tileIndex+1] setNeedsDisplay]; // right + [[self tileOrNilAtIndex:tileIndex+_numberOfColumns-1] setNeedsDisplay]; // bottom left + [[self tileOrNilAtIndex:tileIndex+_numberOfColumns] setNeedsDisplay]; // bottom + [[self tileOrNilAtIndex:tileIndex+_numberOfColumns+1] setNeedsDisplay]; // bottom right + + [tile setNeedsDisplay]; // the center tile itself +} + +- (KLTile *)leftNeighborOfTile:(KLTile *)tile +{ + NSInteger tileIndex = [_tiles indexOfObject:tile]; + return [self tileOrNilAtIndex:tileIndex-1]; +} + +- (KLTile *)rightNeighborOfTile:(KLTile *)tile +{ + NSInteger tileIndex = [_tiles indexOfObject:tile]; + return [self tileOrNilAtIndex:tileIndex+1]; +} + +-(void) resetAllTiles +{ + for (KLTile *tile in _tiles) + [tile restoreBackgroundColor]; +} + +-(NSMutableArray*) tiles +{ + return _tiles; +} + +- (void)dealloc { + [_tiles release]; + [super dealloc]; +} + + +@end diff --git a/Calendar/KLTile.h b/Calendar/KLTile.h new file mode 100644 index 0000000..d0cf81b --- /dev/null +++ b/Calendar/KLTile.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2008, Keith Lazuka, dba The Polypeptides + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Neither the name of the The Polypeptides nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Keith Lazuka ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Keith Lazuka BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#import + +@class KLDate; + +@interface KLTile : UIControl { + NSString *_text; + CGColorRef _textTopColor; + CGColorRef _textBottomColor; + KLDate *_date; +} + +@property(nonatomic, retain) NSString *text; +@property(nonatomic, retain) KLDate *date; + +- (id)init; // designated initializer + +- (void)flash; // flash the tile's background color temporarily + +- (CGColorRef)textTopColor; +- (void)setTextTopColor:(CGColorRef)color; +- (CGColorRef)textBottomColor; +- (void)setTextBottomColor:(CGColorRef)color; +- (void)restoreBackgroundColor; + +@end + + + diff --git a/Calendar/KLTile.m b/Calendar/KLTile.m new file mode 100644 index 0000000..4616180 --- /dev/null +++ b/Calendar/KLTile.m @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2008, Keith Lazuka, dba The Polypeptides + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Neither the name of the The Polypeptides nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Keith Lazuka ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Keith Lazuka BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// +// NOTES +// +// (1) Everything is drawn relative to self's bounds so that +// the graphics can be scaled nicely just by changing the bounds +// +// (2) Since Core Animation can linearly interpolate the view's bounds +// you can easily zoom the view into this tile and everything will +// look nice as soon as you redraw it. +// +// (3) When a tile is marked as "commented", the tile will display +// a small circle indicator near the bottom middle of the tile. +// +// (4) When a tile is marked as "checkmarked", a large green checkmark +// will be drawn over the tile. +// +// (5) If you change either the commented or the checkmarked properties +// on this tile, you must call 'setNeedsDisplay' on the tile +// in order for the changes to become visible. +// + +#import "KLTile.h" +#import "KLDate.h" +#import "KLColors.h" + +static CGGradientRef TextFillGradient; + +__attribute__((constructor)) // Makes this function run when the app loads +static void InitKLTile() +{ + // prepare the gradient + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + + CGColorRef rawColors[2]; + rawColors[0] = CreateRGB(0.173f, 0.212f, 0.255f, 1.0f); + rawColors[1] = CreateRGB(0.294f, 0.361f, 0.435f, 1.0f); + + CFArrayRef colors = CFArrayCreate(NULL, (void*)&rawColors, 2, NULL); + + // create it + TextFillGradient = CGGradientCreateWithColors(colorSpace, colors, NULL); + + CGColorRelease(rawColors[0]); + CGColorRelease(rawColors[1]); + CFRelease(colors); + CGColorSpaceRelease(colorSpace); + +} + +@interface KLTile () +- (CGFloat)thinRectangleWidth; +@end + +@implementation KLTile + +@synthesize text = _text, date = _date; + +- (id)init +{ + if (![super initWithFrame:CGRectMake(0.f, 0.f, 44.f, 44.f)]) + return nil; + + self.backgroundColor = [UIColor colorWithCGColor:kCalendarBodyLightColor]; + [self setTextTopColor:kTileRegularTopColor]; + [self setTextBottomColor:kTileRegularBottomColor]; + + self.clipsToBounds = YES; + + return self; +} + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [[self superview] touchesBegan:touches withEvent:event]; } +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { [[self superview] touchesMoved:touches withEvent:event]; } + +- (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event +{ + UITouch *touch = [touches anyObject]; + if ([touch tapCount] == 1) + [self sendActionsForControlEvents:UIControlEventTouchUpInside]; + else + [[self superview] touchesEnded:touches withEvent:event]; +} + +- (void)drawInnerShadowRect:(CGRect)rect percentage:(CGFloat)percentToCover context:(CGContextRef)ctx +{ + CGFloat width = floorf(rect.size.width); + CGFloat height = floorf(rect.size.height) + 4; + CGFloat gradientLength = percentToCover * height; + + CGColorRef startColor = CreateRGB(0.0f, 0.0f, 0.0f, 0.4f); // black 40% opaque + CGColorRef endColor = CreateRGB(0.0f, 0.0f, 0.0f, 0.0f); // black 0% opaque + CGColorRef rawColors[2] = { startColor, endColor }; + CFArrayRef colors = CFArrayCreate(NULL, (void*)&rawColors, 2, NULL); + CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); + CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, colors, NULL); + + CGContextClipToRect(ctx, rect); + CGContextDrawLinearGradient(ctx, gradient, CGPointMake(0,0), CGPointMake(0, gradientLength), kCGGradientDrawsAfterEndLocation); // top + CGContextDrawLinearGradient(ctx, gradient, CGPointMake(width,0), CGPointMake(width-gradientLength, 0) , kCGGradientDrawsAfterEndLocation); // right + CGContextDrawLinearGradient(ctx, gradient, CGPointMake(0,height), CGPointMake(0, height-gradientLength), kCGGradientDrawsAfterEndLocation); // bottom + CGContextDrawLinearGradient(ctx, gradient, CGPointMake(0,0), CGPointMake(gradientLength, 0) , kCGGradientDrawsAfterEndLocation); // left + + CGGradientRelease(gradient); + CFRelease(colors); + CGColorSpaceRelease(colorSpace); + CGColorRelease(startColor); + CGColorRelease(endColor); +} + +- (CGFloat)thinRectangleWidth { return 1+floorf(0.02f * self.bounds.size.width); } // 1pt width for 46pt tile width (2pt for 4x scale factor) + +- (void)drawTextInContext:(CGContextRef)ctx +{ + CGContextSaveGState(ctx); + CGFloat width = self.bounds.size.width; + CGFloat height = self.bounds.size.height; + + CGFloat numberFontSize = floorf(0.5f * width); + + // create a clipping mask from the text for the gradient + // NOTE: this is a pain in the ass because clipping a string with more than one letter + // results in the clip of each letter being superimposed over each other, + // so instead I have to manually clip each letter and draw the gradient + CGContextSetFillColorWithColor(ctx, kDarkCharcoalColor); + CGContextSetTextDrawingMode(ctx, kCGTextClip); + for (NSInteger i = 0; i < [self.text length]; i++) { + NSString *letter = [self.text substringWithRange:NSMakeRange(i, 1)]; + CGSize letterSize = [letter sizeWithFont:[UIFont boldSystemFontOfSize:numberFontSize]]; + + CGContextSaveGState(ctx); // I will need to undo this clip after the letter's gradient has been drawn + [letter drawAtPoint:CGPointMake(4.0f+(letterSize.width*i), 0.0f) withFont:[UIFont boldSystemFontOfSize:numberFontSize]]; + + if ([self.date isToday]) { + CGContextSetFillColorWithColor(ctx, kWhiteColor); + CGContextFillRect(ctx, self.bounds); + } else { + // nice gradient fill for all tiles except today + CGContextDrawLinearGradient(ctx, TextFillGradient, CGPointMake(0,0), CGPointMake(0, height/3), kCGGradientDrawsAfterEndLocation); + } + + CGContextRestoreGState(ctx); // get rid of the clip for the current letter + } + + CGContextRestoreGState(ctx); +} + +- (void)drawRect:(CGRect)rect +{ + CGContextRef ctx = UIGraphicsGetCurrentContext(); + + CGFloat width = self.bounds.size.width; + CGFloat height = self.bounds.size.height; + CGFloat lineThickness = [self thinRectangleWidth]; // for grid shadow and highlight + + // dark grid line + CGContextSetFillColorWithColor(ctx, kGridDarkColor); + CGContextFillRect(ctx, CGRectMake(0, 0, width, lineThickness)); // top + CGContextFillRect(ctx, CGRectMake(width-lineThickness, 0, lineThickness, height)); // right + + // highlight + CGContextSetFillColorWithColor(ctx, kGridLightColor); + CGContextFillRect(ctx, CGRectMake(0, lineThickness, width-lineThickness, lineThickness)); // top + CGContextFillRect(ctx, CGRectMake(width-2*lineThickness, lineThickness, lineThickness, height-lineThickness)); // right + + // Highlight if this tile represents today + if ([self.date isToday]) { + CGContextSaveGState(ctx); + CGRect innerBounds = self.bounds; + innerBounds.size.width -= lineThickness; + innerBounds.size.height -= lineThickness; + innerBounds.origin.y += lineThickness; + CGContextSetFillColorWithColor(ctx, kSlateBlueColor); + CGContextFillRect(ctx, innerBounds); + [self drawInnerShadowRect:innerBounds percentage:0.1f context:ctx]; + CGContextRestoreGState(ctx); + } + + // Draw the # for this tile + [self drawTextInContext:ctx]; +} + +// -------------------------------------------------------------------------------------------- +// flash +// +// Flash the tile so that the user knows the tap was register but nothing will happen. +// +- (void)flash +{ + //self.backgroundColor = [UIColor colorWithCGColor:kTileRegularTopColor]; + self.backgroundColor = [UIColor lightGrayColor]; + //[self performSelector:@selector(restoreBackgroundColor) withObject:nil afterDelay:0.1f]; +} + +// -------------------------------------------------------------------------------------------- +// restoreBackgroundColor +// +// The inverse of flashTile, this is called at the end of the flash duration +// to restore the tile's origianl background color. +// +- (void)restoreBackgroundColor +{ + self.backgroundColor = [UIColor colorWithCGColor:kCalendarBodyLightColor]; +} + +- (CGColorRef)textTopColor { return _textTopColor; } +- (void)setTextTopColor:(CGColorRef)color +{ + if (color != _textTopColor) { + CGColorRelease(_textTopColor); + _textTopColor = CGColorRetain(color); + } +} + +- (CGColorRef)textBottomColor { return _textBottomColor; } +- (void)setTextBottomColor:(CGColorRef)color +{ + if (color != _textBottomColor) { + CGColorRelease(_textBottomColor); + _textBottomColor = CGColorRetain(color); + } +} + +- (void)dealloc +{ + [_date release]; + [_text release]; + CGColorRelease(_textTopColor); + CGColorRelease(_textBottomColor); + [super dealloc]; +} + +@end + + + + + + + + + + + diff --git a/Calendar/THCalendarInfo.h b/Calendar/THCalendarInfo.h new file mode 100644 index 0000000..5a43872 --- /dev/null +++ b/Calendar/THCalendarInfo.h @@ -0,0 +1,128 @@ +// +// THCalendarInfo.h +// +// Created by Scott Stevenson on 3/10/06. +// Released under a BSD-style license. See THCalendarInfo_License.txt +// + +#import + +typedef enum { + SDCalendarRoundDownRule = (1 << 1), + SDCalendarExactCountRule = (1 << 2), +} SDCalendarRoundingRule; + +typedef enum { + SDCalendar12HourFormat = (1 << 1), + SDCalendar24HourFormat = (1 << 2), +} SDCalendarHourFormat; + +// SDCalendarRoundingRule controls what happens when +// moving back/forward in increments. For example, if +// current date is Jan 31 and we move forward one +// month, should the new date be Feb 28 or Mar 3? +// +// in that example: +// SDCalendarRoundDownRule => Feb 28 +// SDCalendarExactCountRule => Mar 03 + + +// TODO something later -- +// would be nice if the object could cache NSString representations +// of some key int values like month, year, etc. stringWithForrmat +// is somewhat expensive if done frequently + +@interface THCalendarInfo : NSObject { + + CFAbsoluteTime _absoluteTime; + CFCalendarRef _calendar; + CFTimeZoneRef _timeZone; + + NSArray * _dayNames; + NSArray * _monthNames; +} + ++ (id) calendarInfo; + ++ (SDCalendarRoundingRule) defaultRoundingRule; ++ (void) setDefaultRoundingRule: (SDCalendarRoundingRule)roundingRule; ++ (SDCalendarHourFormat) defaultHourFormat; ++ (void) setDefaultHourFormat: (SDCalendarHourFormat)format; + + +// CLASS methods +// universal info for current date/time + ++ (NSDate *) currentDate; ++ (CFAbsoluteTime) currentAbsoluteTime; + ++ (int) currentDayOfWeek; ++ (int) currentDayOfMonth; ++ (int) currentMonth; ++ (int) currentYear; + ++ (int) currentHour; ++ (int) currentHourIn12HourFormat; ++ (int) currentHourIn24HourFormat; ++ (int) currentMinute; ++ (int) currentSecond; + ++ (int) daysInCurrentMonth; + ++ (NSString *) currentDayName; ++ (NSString *) currentMonthName; + + +// INSTANCE methods +// accessors for reference date + +- (CFAbsoluteTime)absoluteTime; +- (void)setAbsoluteTime:(CFAbsoluteTime)newAbsoluteTime; +- (NSDate *)date; +- (void)setDate:(NSDate *)aValue; + +- (void) resetDateAndTimeToCurrent; + +// get info on reference date + +- (int) dayOfWeek; +- (int) dayOfMonth; +- (int) month; +- (int) year; + +- (int) hour; +- (int) hourIn12HourFormat; +- (int) hourIn24HourFormat; +- (int) minute; +- (int) second; + +- (int) daysInMonth; + +- (NSString *) dayName; +- (NSString *) monthName; + +// go forward in time by one unit + +- (void) moveToNextDay; +- (void) moveToNextMonth; +- (void) moveToNextYear; + +// go back in time by one unit + +- (void) moveToPreviousDay; +- (void) moveToPreviousMonth; +- (void) moveToPreviousYear; + +// go back or forward in time an arbitrary number +// of units. negative numbers go backwards + +- (void) adjustDays: (int)days; +- (void) adjustMonths: (int)months; +- (void) adjustYears: (int)years; + +- (void) moveToFirstDayOfMonth; +- (void) moveToBeginningOfDay; + +- (int)weeksInMonth; + +@end diff --git a/Calendar/THCalendarInfo.m b/Calendar/THCalendarInfo.m new file mode 100644 index 0000000..9a9b557 --- /dev/null +++ b/Calendar/THCalendarInfo.m @@ -0,0 +1,630 @@ +// +// THCalendarInfo.m +// +// Created by Scott Stevenson on 3/10/06. +// Released under a BSD-style license. See THCalendarInfo_License.txt +// + +#import "THCalendarInfo.h" + +@interface THCalendarInfo (Private) +- (void) setupEnglishNames; +@end + +@interface THCalendarInfo (PrivateAccessors) +-(CFCalendarRef)calendar; +-(void)setCalendar:(CFCalendarRef)newCalendar; +-(CFTimeZoneRef)timeZone; +-(void)setTimeZone:(CFTimeZoneRef)newTimeZone; +@end + + +static SDCalendarRoundingRule MyDefaultRoundingRule; +static SDCalendarHourFormat MyDefaultHourFormat; + + + +@implementation THCalendarInfo + ++ (void) initialize +{ + MyDefaultRoundingRule = SDCalendarRoundDownRule; + MyDefaultHourFormat = SDCalendar24HourFormat; +} + +- (id) init +{ + [super init]; + _absoluteTime = CFAbsoluteTimeGetCurrent(); + _calendar = CFCalendarCopyCurrent(); + _timeZone = CFCalendarCopyTimeZone( _calendar ); + _dayNames = nil; + _monthNames = nil; + + [self setupEnglishNames]; + return self; +} + +- (void) dealloc +{ + if ( _calendar ) CFRelease( _calendar ); + if ( _timeZone ) CFRelease( _timeZone ); + + [_dayNames release]; + [_monthNames release]; + + [super dealloc]; +} + ++ (id) calendarInfo +{ + return [[[THCalendarInfo alloc] init] autorelease]; +} + ++ (SDCalendarRoundingRule) defaultRoundingRule +{ + return MyDefaultRoundingRule; +} + ++ (void) setDefaultRoundingRule: (SDCalendarRoundingRule)roundingRule +{ + MyDefaultRoundingRule = roundingRule; +} + ++ (SDCalendarHourFormat) defaultHourFormat +{ + return MyDefaultHourFormat; +} + ++ (void) setDefaultHourFormat: (SDCalendarHourFormat)format +{ + MyDefaultHourFormat = format; +} + +#pragma mark - +#pragma mark Class Methods for Current Date and Time + ++ (NSDate *) currentDate +{ + return [NSDate date]; +} + ++ (CFAbsoluteTime) currentAbsoluteTime +{ + return CFAbsoluteTimeGetCurrent(); +} + ++ (int) currentDayOfWeek +{ + return CFCalendarGetOrdinalityOfUnit ( + CFCalendarCopyCurrent(), + kCFCalendarUnitDay, + kCFCalendarUnitWeek, + [self currentAbsoluteTime] + ); +} + ++ (int) currentDayOfMonth +{ + return CFCalendarGetOrdinalityOfUnit ( + CFCalendarCopyCurrent(), + kCFCalendarUnitDay, + kCFCalendarUnitMonth, + [self currentAbsoluteTime] + ); +} + ++ (int) currentMonth +{ + return CFCalendarGetOrdinalityOfUnit ( + CFCalendarCopyCurrent(), + kCFCalendarUnitMonth, + kCFCalendarUnitYear, + [self currentAbsoluteTime] + ); +} + ++ (int) currentYear +{ + return CFCalendarGetOrdinalityOfUnit ( + CFCalendarCopyCurrent(), + kCFCalendarUnitYear, + kCFCalendarUnitEra, + [self currentAbsoluteTime] + ); +} + ++ (int) currentHour +{ + return [self currentHourIn24HourFormat]; +} + ++ (int) currentHourIn12HourFormat +{ + int myHour = CFCalendarGetOrdinalityOfUnit ( + CFCalendarCopyCurrent(), + kCFCalendarUnitHour, + kCFCalendarUnitDay, + [self currentAbsoluteTime] + ); + + // adjust for real-world expectations + // otherwise, 3:45 is '4' (fouth hour) + myHour--; + + // is it midnight? + if ( myHour < 1 ) + { + myHour = 12; + + // afternoon/evening + } else if ( myHour > 12 ) { + + myHour -= 12; + } + + return myHour; +} + ++ (int) currentHourIn24HourFormat +{ + int myHour = CFCalendarGetOrdinalityOfUnit ( + CFCalendarCopyCurrent(), + kCFCalendarUnitHour, + kCFCalendarUnitDay, + [self currentAbsoluteTime] + ); + + // adjust for real-world expectations + // otherwise, 3:45 is '4' (fouth hour) + myHour--; + + return myHour; +} + ++ (int) currentMinute +{ + int myMinute = CFCalendarGetOrdinalityOfUnit ( + CFCalendarCopyCurrent(), + kCFCalendarUnitMinute, + kCFCalendarUnitHour, + [self currentAbsoluteTime] + ); + + // adjust for real-world expectations + // otherwise, 3:10 is '11' (eleventh minute) + myMinute--; + + return myMinute; +} + ++ (int) currentSecond +{ + int mySecond = CFCalendarGetOrdinalityOfUnit ( + CFCalendarCopyCurrent(), + kCFCalendarUnitSecond, + kCFCalendarUnitMinute, + [self currentAbsoluteTime] + ); + + // adjust for real-world expectations + // otherwise, 3:10:09 is '10' (tenth second) + mySecond--; + + return mySecond; +} + ++ (int) daysInCurrentMonth +{ + CFRange r = CFCalendarGetRangeOfUnit ( + CFCalendarCopyCurrent(), + kCFCalendarUnitDay, + kCFCalendarUnitMonth, + [self currentAbsoluteTime] + ); + + return r.length; +} + ++ (NSString *) currentDayName +{ + return @"Undefined"; +} + ++ (NSString *) currentMonthName +{ + return @"Undefined"; +} + + +#pragma mark - +#pragma mark Accessors for Reference Date + +-(CFAbsoluteTime) absoluteTime { + return _absoluteTime; +} + +-(void) setAbsoluteTime:(CFAbsoluteTime)newAbsoluteTime { + _absoluteTime = newAbsoluteTime; +} + +- (NSDate *) date +{ + // This looks weird to me, but this doc says it's okay: + // http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/Concepts/CFObjects.html + + NSDate * newDate = (NSDate *) CFDateCreate( NULL, [self absoluteTime] ); + return [newDate autorelease]; +} + +- (void) setDate:(NSDate *)newDate +{ + if ( newDate == NULL ) return; + [self setAbsoluteTime: CFDateGetAbsoluteTime( (CFDateRef)newDate )]; +} + +- (void) resetDateAndTimeToCurrent +{ + [self setAbsoluteTime: CFAbsoluteTimeGetCurrent()]; +} + + +#pragma mark - +#pragma mark Info for Reference Date + +- (int) dayOfWeek +{ + return CFCalendarGetOrdinalityOfUnit ( + [self calendar], + kCFCalendarUnitDay, + kCFCalendarUnitWeek, + [self absoluteTime] + ); +} + +- (int) dayOfMonth +{ + return CFCalendarGetOrdinalityOfUnit ( + [self calendar], + kCFCalendarUnitDay, + kCFCalendarUnitMonth, + [self absoluteTime] + ); +} + +- (int) month +{ + return CFCalendarGetOrdinalityOfUnit ( + [self calendar], + kCFCalendarUnitMonth, + kCFCalendarUnitYear, + [self absoluteTime] + ); +} + +- (int) year +{ + return CFCalendarGetOrdinalityOfUnit ( + [self calendar], + kCFCalendarUnitYear, + kCFCalendarUnitEra, + [self absoluteTime] + ); +} + +- (int) hour +{ + return [self hourIn24HourFormat]; +} + +- (int) hourIn12HourFormat +{ + int myHour = CFCalendarGetOrdinalityOfUnit ( + [self calendar], + kCFCalendarUnitHour, + kCFCalendarUnitDay, + [self absoluteTime] + ); + + // adjust for real-world expectations + // otherwise, 3:45 is '4' (fouth hour) + myHour--; + + // is it midnight? + if ( myHour < 1 ) + { + myHour = 12; + + // afternoon/evening + } else if ( myHour > 12 ) { + + myHour -= 12; + } + + return myHour; +} + +- (int) hourIn24HourFormat +{ + int myHour = CFCalendarGetOrdinalityOfUnit ( + [self calendar], + kCFCalendarUnitHour, + kCFCalendarUnitDay, + [self absoluteTime] + ); + + // adjust for real-world expectations + // otherwise, 3:45 is '4' (fouth hour) + myHour--; + + return myHour; +} + +- (int) minute +{ + int myMinute = CFCalendarGetOrdinalityOfUnit ( + [self calendar], + kCFCalendarUnitMinute, + kCFCalendarUnitHour, + [self absoluteTime] + ); + + // adjust for real-world expectations + // otherwise, 3:10 is '11' (eleventh minute) + myMinute--; + + return myMinute; +} + +- (int) second +{ + int mySecond = CFCalendarGetOrdinalityOfUnit ( + [self calendar], + kCFCalendarUnitSecond, + kCFCalendarUnitMinute, + [self absoluteTime] + ); + + // adjust for real-world expectations + // otherwise, 3:10:09 is '10' (tenth second) + mySecond--; + + return mySecond; +} + +- (int) daysInMonth +{ + CFRange r = CFCalendarGetRangeOfUnit ( + [self calendar], + kCFCalendarUnitDay, + kCFCalendarUnitMonth, + [self absoluteTime] + ); + + return r.length; +} + +- (NSString *) dayName +{ + unsigned currentDay = [self dayOfWeek]; + return [_dayNames objectAtIndex: (currentDay-1)]; +} + +- (NSString *) monthName +{ + unsigned currentMonth = ([self month] - 1); + return [_monthNames objectAtIndex: currentMonth]; +} + + +// go forward in time by one unit + +- (void) moveToNextDay +{ + [self adjustDays: 1]; +} + +- (void) moveToNextMonth +{ + [self adjustMonths: 1]; +} + +- (void) moveToNextYear +{ + [self adjustYears: 1]; +} + +// go back in time by one unit + +- (void) moveToPreviousDay +{ + [self adjustDays: -1]; +} + +- (void) moveToPreviousMonth +{ + [self adjustMonths: -1]; +} + +- (void) moveToPreviousYear +{ + [self adjustYears: -1]; +} + +// go back or forward in time an arbitrary number +// of units. negative numbers go backwards + +- (void) adjustDays: (int)days +{ + CFAbsoluteTime newTime = [self absoluteTime]; + + // calculate absolute time for new object + // declaring the format separately suppresses warnings + + const unsigned char format[] = "d"; + CFCalendarAddComponents ( [self calendar], &newTime, 0, format, days ); + [self setAbsoluteTime: newTime]; +} + +- (void) adjustMonths: (int)months +{ + CFAbsoluteTime newTime = [self absoluteTime]; + + // calculate absolute time for new object + // declaring the format separately suppresses warnings + + if ( [THCalendarInfo defaultRoundingRule] == SDCalendarExactCountRule ) + { + const unsigned char dFormat[] = "d"; + CFCalendarAddComponents ( [self calendar], &newTime, 0, dFormat, (months * 30) ); + + } else { + + const unsigned char mFormat[] = "M"; + CFCalendarAddComponents ( [self calendar], &newTime, 0, mFormat, months ); + } + + [self setAbsoluteTime: newTime]; +} + +- (void) adjustYears: (int)years +{ + // TODO: What happens if we start at Feb 29 and move one year? + + CFAbsoluteTime newTime = [self absoluteTime]; + + // calculate absolute time for new object + // declaring the format separately suppresses warnings + + const unsigned char format[] = "y"; + CFCalendarAddComponents ( [self calendar], &newTime, 0, format, years ); + [self setAbsoluteTime: newTime]; +} + +- (void) moveToFirstDayOfMonth +{ + CFAbsoluteTime newTime = 0; + BOOL itWorked = NO; + + // build new time from current month and year + // but with '1' for the day + + const unsigned char format[] = "yMdHms"; + + itWorked = CFCalendarComposeAbsoluteTime ( + [self calendar], + &newTime, + format, + [self year], [self month], 1, 0, 0, 0 + ); + + if ( itWorked ) + { + [self setAbsoluteTime: newTime]; + } +} + +// Added by Keith Lazuka +- (void) moveToBeginningOfDay +{ + CFAbsoluteTime newTime = 0; + BOOL itWorked = NO; + + // build new time from current month, day and year + // but with the time set to 00:00 + + const unsigned char format[] = "yMdHms"; + + itWorked = CFCalendarComposeAbsoluteTime ( + [self calendar], + &newTime, + format, + [self year], [self month], [self dayOfMonth], 0, 0, 0 + ); + + if ( itWorked ) + { + [self setAbsoluteTime: newTime]; + } +} + +// Added by Keith Lazuka +- (int)weekOfMonth +{ + return (int)CFCalendarGetOrdinalityOfUnit([self calendar], kCFCalendarUnitWeek, kCFCalendarUnitMonth, [self absoluteTime]); +} + +// Added by Keith Lazuka +- (int)weeksInMonth +{ + // Includes a workaround for some regional formats that return the ordinal week zero-based + // for some months (like France for August 2008). + // My workaround is as follows: + // If the first week is zero-based, + // find the final week number and increment increment it by 1. + // + // Here is the bug report that I filed but Apple never responded: + // + // 29-Jul-2008 12:51 PM Keith Lazuka: + // The documentation for CFCalendarGetOrdinalityOfUnit() says that "Normal return values are 1 and greater," + // but when the iPhone's Regional Format is set to France, determining the week in the month will sometimes give a result of 0. + // To reproduce the problem, set the iPhone's Regional Format to France and run this code: + // CFCalendarRef cal = CFCalendarCopyCurrent(); + // CFAbsoluteTime at; + // CFCalendarComposeAbsoluteTime(cal, &at, "yMd", 2008, 8, 1); + // CFIndex weekNumber = CFCalendarGetOrdinalityOfUnit(cal, kCFCalendarUnitWeek, kCFCalendarUnitMonth, at); + // NSLog(@"In this region, August 1st, 2008 is the ordinal %d of the month", weekNumber); + // + + NSDate *savedState = [self date]; + [self moveToFirstDayOfMonth]; + int firstWeek = [self weekOfMonth]; + + [self moveToNextMonth]; + [self moveToFirstDayOfMonth]; + [self moveToPreviousDay]; + int finalWeek = [self weekOfMonth]; + + if (firstWeek == 0) + finalWeek++; + + [self setDate:savedState]; + return finalWeek; +} + +#pragma mark - +#pragma mark Private + +- (void) setupEnglishNames +{ + _dayNames = [[NSArray alloc] initWithObjects: @"Sunday", @"Monday", @"Tuesday", @"Wednesday", @"Thursday", @"Friday", @"Saturday", nil]; + _monthNames = [[NSArray alloc] initWithObjects: @"January", @"February", @"March", @"April", @"May", @"June", @"July", @"August", @"September", @"October", @"November", @"December", nil]; +} + + + +#pragma mark - +#pragma mark Private Accessors + +-(CFCalendarRef)calendar { + return _calendar; +} + +-(void)setCalendar:(CFCalendarRef)newCalendar +{ + CFCalendarRef temp = _calendar; + _calendar = (CFCalendarRef)CFRetain( newCalendar ); + if ( temp ) CFRelease( temp ); +} +-(CFTimeZoneRef)timeZone { + return _timeZone; +} + +-(void)setTimeZone:(CFTimeZoneRef)newTimeZone +{ + CFTimeZoneRef temp = _timeZone; + _timeZone = CFRetain( newTimeZone ); + if ( temp ) CFRelease( temp ); +} + +@end diff --git a/Calendar/left-arrow.png b/Calendar/left-arrow.png new file mode 100644 index 0000000..71561ca Binary files /dev/null and b/Calendar/left-arrow.png differ diff --git a/Calendar/main.m b/Calendar/main.m new file mode 100644 index 0000000..37996f5 --- /dev/null +++ b/Calendar/main.m @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2008, Keith Lazuka, dba The Polypeptides + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Neither the name of the The Polypeptides nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY Keith Lazuka ''AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL Keith Lazuka BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#import + +int main(int argc, char *argv[]) { + + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + int retVal = UIApplicationMain(argc, argv, nil, @"KCalendarAppDelegate"); + [pool release]; + return retVal; +} diff --git a/Calendar/right-arrow.png b/Calendar/right-arrow.png new file mode 100644 index 0000000..ac64772 Binary files /dev/null and b/Calendar/right-arrow.png differ diff --git a/CalendarModule.xcodeproj/montgomerie.mode1v3 b/CalendarModule.xcodeproj/montgomerie.mode1v3 new file mode 100644 index 0000000..46b7fa8 --- /dev/null +++ b/CalendarModule.xcodeproj/montgomerie.mode1v3 @@ -0,0 +1,1398 @@ + + + + + ActivePerspectiveName + Project + AllowedModules + + + BundleLoadPath + + MaxInstances + n + Module + PBXSmartGroupTreeModule + Name + Groups and Files Outline View + + + BundleLoadPath + + MaxInstances + n + Module + PBXNavigatorGroup + Name + Editor + + + BundleLoadPath + + MaxInstances + n + Module + XCTaskListModule + Name + Task List + + + BundleLoadPath + + MaxInstances + n + Module + XCDetailModule + Name + File and Smart Group Detail Viewer + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXBuildResultsModule + Name + Detailed Build Results Viewer + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXProjectFindModule + Name + Project Batch Find Tool + + + BundleLoadPath + + MaxInstances + n + Module + XCProjectFormatConflictsModule + Name + Project Format Conflicts List + + + BundleLoadPath + + MaxInstances + n + Module + PBXBookmarksModule + Name + Bookmarks Tool + + + BundleLoadPath + + MaxInstances + n + Module + PBXClassBrowserModule + Name + Class Browser + + + BundleLoadPath + + MaxInstances + n + Module + PBXCVSModule + Name + Source Code Control Tool + + + BundleLoadPath + + MaxInstances + n + Module + PBXDebugBreakpointsModule + Name + Debug Breakpoints Tool + + + BundleLoadPath + + MaxInstances + n + Module + XCDockableInspector + Name + Inspector + + + BundleLoadPath + + MaxInstances + n + Module + PBXOpenQuicklyModule + Name + Open Quickly Tool + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXDebugSessionModule + Name + Debugger + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXDebugCLIModule + Name + Debug Console + + + BundleLoadPath + + MaxInstances + n + Module + XCSnapshotModule + Name + Snapshots Tool + + + BundlePath + /Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources + Description + DefaultDescriptionKey + DockingSystemVisible + + Extension + mode1v3 + FavBarConfig + + PBXProjectModuleGUID + 2F895A9211F8A99200C6E55B + XCBarModuleItemNames + + XCBarModuleItems + + + FirstTimeWindowDisplayed + + Identifier + com.apple.perspectives.project.mode1v3 + MajorVersion + 33 + MinorVersion + 0 + Name + Default + Notifications + + OpenEditors + + PerspectiveWidths + + -1 + -1 + + Perspectives + + + ChosenToolbarItems + + active-combo-popup + action + NSToolbarFlexibleSpaceItem + debugger-enable-breakpoints + build-and-go + com.apple.ide.PBXToolbarStopButton + get-info + NSToolbarFlexibleSpaceItem + com.apple.pbx.toolbar.searchfield + + ControllerClassBaseName + + IconName + WindowOfProjectWithEditor + Identifier + perspective.project + IsVertical + + Layout + + + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + + PBXProjectModuleGUID + 1CE0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 186 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 0867D691FE84028FC02AAC07 + 2FD9F904123FCFFE00632593 + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C37FABC05509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 1 + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {186, 578}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + + XCSharingToken + com.apple.Xcode.GFSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {203, 596}} + GroupTreeTableConfiguration + + MainColumn + 186 + + RubberWindowFrame + 1 141 1069 637 0 0 1280 778 + + Module + PBXSmartGroupTreeModule + Proportion + 203pt + + + Dock + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20306471E060097A5F4 + PBXProjectModuleLabel + TiCalendarView.m + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1CE0B20406471E060097A5F4 + PBXProjectModuleLabel + TiCalendarView.m + _historyCapacity + 0 + bookmark + 2FD9FA2E124070C900632593 + history + + 2FD9F99B123FDD9400632593 + 2FD9F99D123FDD9400632593 + 2FD9F99F123FDD9400632593 + 2FD9F9D7123FE1C600632593 + 2FD9F9E0123FE2D700632593 + 2FD9F9E1123FE2D700632593 + 2FD9F9E2123FE2D700632593 + + + SplitCount + 1 + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {861, 369}} + RubberWindowFrame + 1 141 1069 637 0 0 1280 778 + + Module + PBXNavigatorGroup + Proportion + 369pt + + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20506471E060097A5F4 + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{0, 374}, {861, 222}} + RubberWindowFrame + 1 141 1069 637 0 0 1280 778 + + Module + XCDetailModule + Proportion + 222pt + + + Proportion + 861pt + + + Name + Project + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + XCModuleDock + PBXNavigatorGroup + XCDetailModule + + TableOfContents + + 2FD9F836123F46D800632593 + 1CE0B1FE06471DED0097A5F4 + 2FD9F837123F46D800632593 + 1CE0B20306471E060097A5F4 + 1CE0B20506471E060097A5F4 + + ToolbarConfigUserDefaultsMinorVersion + 2 + ToolbarConfiguration + xcode.toolbar.config.defaultV3 + + + ControllerClassBaseName + + IconName + WindowOfProject + Identifier + perspective.morph + IsVertical + 0 + Layout + + + BecomeActive + 1 + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C08E77C0454961000C914BD + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + + PBXProjectModuleGUID + 11E0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 186 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 29B97314FDCFA39411CA2CEA + 1C37FABC05509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {186, 337}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + 1 + XCSharingToken + com.apple.Xcode.GFSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {203, 355}} + GroupTreeTableConfiguration + + MainColumn + 186 + + RubberWindowFrame + 373 269 690 397 0 0 1440 878 + + Module + PBXSmartGroupTreeModule + Proportion + 100% + + + Name + Morph + PreferredWidth + 300 + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + + TableOfContents + + 11E0B1FE06471DED0097A5F4 + + ToolbarConfiguration + xcode.toolbar.config.default.shortV3 + + + PerspectivesBarVisible + + ShelfIsVisible + + SourceDescription + file at '/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources/XCPerspectivesSpecificationMode1.xcperspec' + StatusbarIsVisible + + TimeStamp + 0.0 + ToolbarConfigUserDefaultsMinorVersion + 2 + ToolbarDisplayMode + 1 + ToolbarIsVisible + + ToolbarSizeMode + 1 + Type + Perspectives + UpdateMessage + The Default Workspace in this version of Xcode now includes support to hide and show the detail view (what has been referred to as the "Metro-Morph" feature). You must discard your current Default Workspace settings and update to the latest Default Workspace in order to gain this feature. Do you wish to update to the latest Workspace defaults for project '%@'? + WindowJustification + 5 + WindowOrderList + + 1C530D57069F1CE1000CFCEE + 2F895A9311F8A99200C6E55B + /Users/montgomerie/iPhoneDev/CalendarModule/CalendarModule.xcodeproj + + WindowString + 1 141 1069 637 0 0 1280 778 + WindowToolsV3 + + + FirstTimeWindowDisplayed + + Identifier + windowTool.build + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528F0623707200166675 + PBXProjectModuleLabel + KLDateSort.m + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {902, 270}} + RubberWindowFrame + 583 145 902 552 0 0 1280 778 + + Module + PBXNavigatorGroup + Proportion + 270pt + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + XCMainBuildResultsModuleGUID + PBXProjectModuleLabel + Build Results + XCBuildResultsTrigger_Collapse + 1021 + XCBuildResultsTrigger_Open + 1011 + + GeometryConfiguration + + Frame + {{0, 275}, {902, 236}} + RubberWindowFrame + 583 145 902 552 0 0 1280 778 + + Module + PBXBuildResultsModule + Proportion + 236pt + + + Proportion + 511pt + + + Name + Build Results + ServiceClasses + + PBXBuildResultsModule + + StatusbarIsVisible + + TableOfContents + + 2F895A9311F8A99200C6E55B + 2FD9F839123F46D800632593 + 1CD0528F0623707200166675 + XCMainBuildResultsModuleGUID + + ToolbarConfiguration + xcode.toolbar.config.buildV3 + WindowContentMinSize + 486 300 + WindowString + 583 145 902 552 0 0 1280 778 + WindowToolGUID + 2F895A9311F8A99200C6E55B + WindowToolIsVisible + + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debugger + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + Debugger + + HorizontalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {347, 190}} + {{0, 190}, {347, 191}} + + + VerticalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {347, 381}} + {{347, 0}, {347, 381}} + + + + LauncherConfigVersion + 8 + PBXProjectModuleGUID + 1C162984064C10D400B95A72 + PBXProjectModuleLabel + Debug - GLUTExamples (Underwater) + + GeometryConfiguration + + DebugConsoleVisible + None + DebugConsoleWindowFrame + {{200, 200}, {500, 300}} + DebugSTDIOWindowFrame + {{200, 200}, {500, 300}} + Frame + {{0, 0}, {694, 381}} + PBXDebugSessionStackFrameViewKey + + DebugVariablesTableConfiguration + + Name + 120 + Value + 85 + Summary + 117 + + Frame + {{0, 190}, {347, 191}} + RubberWindowFrame + 22 333 694 422 0 0 1280 778 + + RubberWindowFrame + 22 333 694 422 0 0 1280 778 + + Module + PBXDebugSessionModule + Proportion + 381pt + + + Proportion + 381pt + + + Name + Debugger + ServiceClasses + + PBXDebugSessionModule + + StatusbarIsVisible + + TableOfContents + + 1CD10A99069EF8BA00B06720 + 2FD2B1DF121E64A700D37686 + 1C162984064C10D400B95A72 + 2FD2B1E0121E64A700D37686 + 2FD2B1E1121E64A700D37686 + 2FD2B1E2121E64A700D37686 + 2FD2B1E3121E64A700D37686 + 2FD2B1E4121E64A700D37686 + + ToolbarConfiguration + xcode.toolbar.config.debugV3 + WindowString + 22 333 694 422 0 0 1280 778 + WindowToolGUID + 1CD10A99069EF8BA00B06720 + WindowToolIsVisible + + + + FirstTimeWindowDisplayed + + Identifier + windowTool.find + IsVertical + + Layout + + + Dock + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CDD528C0622207200134675 + PBXProjectModuleLabel + <No Editor> + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {781, 212}} + RubberWindowFrame + 499 308 781 470 0 0 1280 778 + + Module + PBXNavigatorGroup + Proportion + 781pt + + + Proportion + 212pt + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528E0623707200166675 + PBXProjectModuleLabel + Project Find + + GeometryConfiguration + + Frame + {{0, 217}, {781, 212}} + RubberWindowFrame + 499 308 781 470 0 0 1280 778 + + Module + PBXProjectFindModule + Proportion + 212pt + + + Proportion + 429pt + + + Name + Project Find + ServiceClasses + + PBXProjectFindModule + + StatusbarIsVisible + + TableOfContents + + 1C530D57069F1CE1000CFCEE + 2FD9F86F123F544800632593 + 2FD9F870123F544800632593 + 1CDD528C0622207200134675 + 1CD0528E0623707200166675 + + WindowString + 499 308 781 470 0 0 1280 778 + WindowToolGUID + 1C530D57069F1CE1000CFCEE + WindowToolIsVisible + + + + Identifier + MENUSEPARATOR + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debuggerConsole + IsVertical + + Layout + + + Dock + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAAC065D492600B07095 + PBXProjectModuleLabel + Debugger Console + + GeometryConfiguration + + Frame + {{0, 0}, {665, 275}} + RubberWindowFrame + 224 436 665 316 0 0 1280 778 + + Module + PBXDebugCLIModule + Proportion + 275pt + + + Proportion + 275pt + + + Name + Debugger Console + ServiceClasses + + PBXDebugCLIModule + + StatusbarIsVisible + + TableOfContents + + 1C78EAAD065D492600B07095 + 2FF7BC39122F41B800DD1ECA + 1C78EAAC065D492600B07095 + + ToolbarConfiguration + xcode.toolbar.config.consoleV3 + WindowString + 224 436 665 316 0 0 1280 778 + WindowToolGUID + 1C78EAAD065D492600B07095 + WindowToolIsVisible + + + + Identifier + windowTool.snapshots + Layout + + + Dock + + + Module + XCSnapshotModule + Proportion + 100% + + + Proportion + 100% + + + Name + Snapshots + ServiceClasses + + XCSnapshotModule + + StatusbarIsVisible + Yes + ToolbarConfiguration + xcode.toolbar.config.snapshots + WindowString + 315 824 300 550 0 0 1440 878 + WindowToolIsVisible + Yes + + + Identifier + windowTool.scm + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAB2065D492600B07095 + PBXProjectModuleLabel + <No Editor> + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1C78EAB3065D492600B07095 + + SplitCount + 1 + + StatusBarVisibility + 1 + + GeometryConfiguration + + Frame + {{0, 0}, {452, 0}} + RubberWindowFrame + 743 379 452 308 0 0 1280 1002 + + Module + PBXNavigatorGroup + Proportion + 0pt + + + BecomeActive + 1 + ContentConfiguration + + PBXProjectModuleGUID + 1CD052920623707200166675 + PBXProjectModuleLabel + SCM + + GeometryConfiguration + + ConsoleFrame + {{0, 259}, {452, 0}} + Frame + {{0, 7}, {452, 259}} + RubberWindowFrame + 743 379 452 308 0 0 1280 1002 + TableConfiguration + + Status + 30 + FileName + 199 + Path + 197.0950012207031 + + TableFrame + {{0, 0}, {452, 250}} + + Module + PBXCVSModule + Proportion + 262pt + + + Proportion + 266pt + + + Name + SCM + ServiceClasses + + PBXCVSModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C78EAB4065D492600B07095 + 1C78EAB5065D492600B07095 + 1C78EAB2065D492600B07095 + 1CD052920623707200166675 + + ToolbarConfiguration + xcode.toolbar.config.scm + WindowString + 743 379 452 308 0 0 1280 1002 + + + FirstTimeWindowDisplayed + + Identifier + windowTool.breakpoints + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C77FABC04509CD000000102 + + PBXProjectModuleGUID + 1CE0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + no + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 168 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 1C77FABC04509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {168, 350}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + + + GeometryConfiguration + + Frame + {{0, 0}, {185, 368}} + GroupTreeTableConfiguration + + MainColumn + 168 + + RubberWindowFrame + 288 282 744 409 0 0 1280 778 + + Module + PBXSmartGroupTreeModule + Proportion + 185pt + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1CA1AED706398EBD00589147 + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{190, 0}, {554, 368}} + RubberWindowFrame + 288 282 744 409 0 0 1280 778 + + Module + XCDetailModule + Proportion + 554pt + + + Proportion + 368pt + + + MajorVersion + 3 + MinorVersion + 0 + Name + Breakpoints + ServiceClasses + + PBXSmartGroupTreeModule + XCDetailModule + + StatusbarIsVisible + + TableOfContents + + 2F41415211FE37E5008B065F + 2F41415311FE37E5008B065F + 1CE0B1FE06471DED0097A5F4 + 1CA1AED706398EBD00589147 + + ToolbarConfiguration + xcode.toolbar.config.breakpointsV3 + WindowString + 288 282 744 409 0 0 1280 778 + WindowToolGUID + 2F41415211FE37E5008B065F + WindowToolIsVisible + + + + Identifier + windowTool.debugAnimator + Layout + + + Dock + + + Module + PBXNavigatorGroup + Proportion + 100% + + + Proportion + 100% + + + Name + Debug Visualizer + ServiceClasses + + PBXNavigatorGroup + + StatusbarIsVisible + 1 + ToolbarConfiguration + xcode.toolbar.config.debugAnimatorV3 + WindowString + 100 100 700 500 0 0 1280 1002 + + + Identifier + windowTool.bookmarks + Layout + + + Dock + + + Module + PBXBookmarksModule + Proportion + 100% + + + Proportion + 100% + + + Name + Bookmarks + ServiceClasses + + PBXBookmarksModule + + StatusbarIsVisible + 0 + WindowString + 538 42 401 187 0 0 1280 1002 + + + Identifier + windowTool.projectFormatConflicts + Layout + + + Dock + + + Module + XCProjectFormatConflictsModule + Proportion + 100% + + + Proportion + 100% + + + Name + Project Format Conflicts + ServiceClasses + + XCProjectFormatConflictsModule + + StatusbarIsVisible + 0 + WindowContentMinSize + 450 300 + WindowString + 50 850 472 307 0 0 1440 877 + + + Identifier + windowTool.classBrowser + Layout + + + Dock + + + BecomeActive + 1 + ContentConfiguration + + OptionsSetName + Hierarchy, all classes + PBXProjectModuleGUID + 1CA6456E063B45B4001379D8 + PBXProjectModuleLabel + Class Browser - NSObject + + GeometryConfiguration + + ClassesFrame + {{0, 0}, {374, 96}} + ClassesTreeTableConfiguration + + PBXClassNameColumnIdentifier + 208 + PBXClassBookColumnIdentifier + 22 + + Frame + {{0, 0}, {630, 331}} + MembersFrame + {{0, 105}, {374, 395}} + MembersTreeTableConfiguration + + PBXMemberTypeIconColumnIdentifier + 22 + PBXMemberNameColumnIdentifier + 216 + PBXMemberTypeColumnIdentifier + 97 + PBXMemberBookColumnIdentifier + 22 + + PBXModuleWindowStatusBarHidden2 + 1 + RubberWindowFrame + 385 179 630 352 0 0 1440 878 + + Module + PBXClassBrowserModule + Proportion + 332pt + + + Proportion + 332pt + + + Name + Class Browser + ServiceClasses + + PBXClassBrowserModule + + StatusbarIsVisible + 0 + TableOfContents + + 1C0AD2AF069F1E9B00FABCE6 + 1C0AD2B0069F1E9B00FABCE6 + 1CA6456E063B45B4001379D8 + + ToolbarConfiguration + xcode.toolbar.config.classbrowser + WindowString + 385 179 630 352 0 0 1440 878 + WindowToolGUID + 1C0AD2AF069F1E9B00FABCE6 + WindowToolIsVisible + 0 + + + Identifier + windowTool.refactoring + IncludeInToolsMenu + 0 + Layout + + + Dock + + + BecomeActive + 1 + GeometryConfiguration + + Frame + {0, 0}, {500, 335} + RubberWindowFrame + {0, 0}, {500, 335} + + Module + XCRefactoringModule + Proportion + 100% + + + Proportion + 100% + + + Name + Refactoring + ServiceClasses + + XCRefactoringModule + + WindowString + 200 200 500 356 0 0 1920 1200 + + + + diff --git a/CalendarModule.xcodeproj/montgomerie.pbxuser b/CalendarModule.xcodeproj/montgomerie.pbxuser new file mode 100644 index 0000000..3f29a4b --- /dev/null +++ b/CalendarModule.xcodeproj/montgomerie.pbxuser @@ -0,0 +1,473 @@ +// !$*UTF8*$! +{ + 0867D690FE84028FC02AAC07 /* Project object */ = { + activeBuildConfigurationName = Debug; + activeTarget = D2AAC07D0554694100DB518D /* CalendarModule */; + addToTargets = ( + ); + breakpoints = ( + 2F895DD111F95C3000C6E55B /* TiCalendarView.m:27 */, + 2FD2B1CA121E63B600D37686 /* TiCalendarView.m:30 */, + ); + codeSenseManager = 2F895A9611F8A99200C6E55B /* Code sense */; + perUserDictionary = { + "PBXConfiguration.PBXBreakpointsDataSource.v1:1CA1AED706398EBD00589147" = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXBreakpointsDataSource_BreakpointID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 20, + 198, + 20, + 99, + 99, + 29, + 20, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXBreakpointsDataSource_ActionID, + PBXBreakpointsDataSource_TypeID, + PBXBreakpointsDataSource_BreakpointID, + PBXBreakpointsDataSource_UseID, + PBXBreakpointsDataSource_LocationID, + PBXBreakpointsDataSource_ConditionID, + PBXBreakpointsDataSource_IgnoreCountID, + PBXBreakpointsDataSource_ContinueID, + ); + }; + PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 622, + 20, + 48, + 43, + 43, + 20, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXFileDataSource_FiletypeID, + PBXFileDataSource_Filename_ColumnID, + PBXFileDataSource_Built_ColumnID, + PBXFileDataSource_ObjectSize_ColumnID, + PBXFileDataSource_Errors_ColumnID, + PBXFileDataSource_Warnings_ColumnID, + PBXFileDataSource_Target_ColumnID, + ); + }; + PBXConfiguration.PBXTargetDataSource.PBXTargetDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 582, + 60, + 20, + 48, + 43, + 43, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXFileDataSource_FiletypeID, + PBXFileDataSource_Filename_ColumnID, + PBXTargetDataSource_PrimaryAttribute, + PBXFileDataSource_Built_ColumnID, + PBXFileDataSource_ObjectSize_ColumnID, + PBXFileDataSource_Errors_ColumnID, + PBXFileDataSource_Warnings_ColumnID, + ); + }; + PBXPerProjectTemplateStateSaveDate = 306136783; + PBXWorkspaceStateSaveDate = 306136783; + }; + perUserProjectItems = { + 2FD9F99B123FDD9400632593 /* PBXTextBookmark */ = 2FD9F99B123FDD9400632593 /* PBXTextBookmark */; + 2FD9F99D123FDD9400632593 /* PBXTextBookmark */ = 2FD9F99D123FDD9400632593 /* PBXTextBookmark */; + 2FD9F99F123FDD9400632593 /* PBXTextBookmark */ = 2FD9F99F123FDD9400632593 /* PBXTextBookmark */; + 2FD9F9D7123FE1C600632593 /* PBXTextBookmark */ = 2FD9F9D7123FE1C600632593 /* PBXTextBookmark */; + 2FD9F9E0123FE2D700632593 /* PBXTextBookmark */ = 2FD9F9E0123FE2D700632593 /* PBXTextBookmark */; + 2FD9F9E1123FE2D700632593 /* PBXTextBookmark */ = 2FD9F9E1123FE2D700632593 /* PBXTextBookmark */; + 2FD9F9E2123FE2D700632593 /* PBXTextBookmark */ = 2FD9F9E2123FE2D700632593 /* PBXTextBookmark */; + 2FD9FA2E124070C900632593 /* PBXTextBookmark */ = 2FD9FA2E124070C900632593 /* PBXTextBookmark */; + }; + sourceControlManager = 2F895A9511F8A99200C6E55B /* Source Control */; + userBuildSettings = { + }; + }; + 24DD6CF71134B3F500162E58 /* CalendarModule.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {800, 337}}"; + sepNavSelRange = "{226, 0}"; + sepNavVisRange = "{0, 238}"; + sepNavWindowFrame = "{{15, 68}, {1015, 705}}"; + }; + }; + 24DD6CF81134B3F500162E58 /* CalendarModule.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {800, 1261}}"; + sepNavSelRange = "{440, 34}"; + sepNavVisRange = "{0, 506}"; + sepNavWindowFrame = "{{15, 68}, {1015, 705}}"; + }; + }; + 24DD6D1B1134B66800162E58 /* titanium.xcconfig */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {852, 337}}"; + sepNavSelRange = "{551, 0}"; + sepNavVisRange = "{0, 551}"; + }; + }; + 2F895A9511F8A99200C6E55B /* Source Control */ = { + isa = PBXSourceControlManager; + fallbackIsa = XCSourceControlManager; + isSCMEnabled = 0; + scmConfiguration = { + repositoryNamesForRoots = { + "" = ""; + }; + }; + }; + 2F895A9611F8A99200C6E55B /* Code sense */ = { + isa = PBXCodeSenseManager; + indexTemplatePath = ""; + }; + 2F895AD811F8B5ED00C6E55B /* TiCalendarViewProxy.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {800, 337}}"; + sepNavSelRange = "{519, 28}"; + sepNavVisRange = "{0, 553}"; + sepNavWindowFrame = "{{15, 67}, {1015, 705}}"; + }; + }; + 2F895AD911F8B5ED00C6E55B /* TiCalendarViewProxy.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {720, 1378}}"; + sepNavSelRange = "{938, 12}"; + sepNavVisRange = "{748, 385}"; + sepNavWindowFrame = "{{15, 67}, {1015, 705}}"; + }; + }; + 2F895ADC11F8B60300C6E55B /* TiCalendarView.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {800, 546}}"; + sepNavSelRange = "{957, 0}"; + sepNavVisRange = "{467, 552}"; + sepNavWindowFrame = "{{15, 57}, {750, 719}}"; + }; + }; + 2F895ADD11F8B60300C6E55B /* TiCalendarView.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {800, 4069}}"; + sepNavSelRange = "{5355, 0}"; + sepNavVisRange = "{5190, 700}"; + sepNavWindowFrame = "{{15, 57}, {750, 719}}"; + }; + }; + 2F895B5211F8E59500C6E55B /* Calendar.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {800, 337}}"; + sepNavSelRange = "{304, 0}"; + sepNavVisRange = "{0, 334}"; + }; + }; + 2F895B5311F8E59500C6E55B /* Calendar.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {800, 337}}"; + sepNavSelRange = "{467, 0}"; + sepNavVisRange = "{0, 476}"; + }; + }; + 2F895C2A11F8FA8F00C6E55B /* CalendarProxy.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {800, 337}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 323}"; + }; + }; + 2F895C2B11F8FA8F00C6E55B /* CalendarProxy.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {800, 337}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 325}"; + }; + }; + 2F895D1111F903D600C6E55B /* CheckmarkTile.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {800, 337}}"; + sepNavSelRange = "{85, 6}"; + sepNavVisRange = "{0, 169}"; + }; + }; + 2F895D1211F903D600C6E55B /* CheckmarkTile.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1321, 577}}"; + sepNavSelRange = "{1060, 0}"; + sepNavVisRange = "{0, 1125}"; + sepNavWindowFrame = "{{15, 68}, {1015, 705}}"; + }; + }; + 2F895D1411F903D600C6E55B /* KLCalendarModel.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {800, 650}}"; + sepNavSelRange = "{1537, 0}"; + sepNavVisRange = "{1175, 661}"; + }; + }; + 2F895D1511F903D600C6E55B /* KLCalendarModel.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {800, 2236}}"; + sepNavSelRange = "{1765, 35}"; + sepNavVisRange = "{1433, 676}"; + }; + }; + 2F895D1611F903D600C6E55B /* KLCalendarView.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {866, 1079}}"; + sepNavSelRange = "{3117, 90}"; + sepNavVisRange = "{2273, 997}"; + sepNavWindowFrame = "{{13, 68}, {1015, 705}}"; + }; + }; + 2F895D1711F903D600C6E55B /* KLCalendarView.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1391, 7020}}"; + sepNavSelRange = "{4049, 9}"; + sepNavVisRange = "{3783, 533}"; + sepNavWindowFrame = "{{13, 68}, {1015, 705}}"; + }; + }; + 2F895D1811F903D600C6E55B /* KLColors.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {800, 546}}"; + sepNavSelRange = "{1502, 49}"; + sepNavVisRange = "{722, 1136}"; + }; + }; + 2F895D1911F903D600C6E55B /* KLColors.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {800, 988}}"; + sepNavSelRange = "{1939, 0}"; + sepNavVisRange = "{1618, 1230}"; + }; + }; + 2F895D1A11F903D600C6E55B /* KLDate.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {800, 1092}}"; + sepNavSelRange = "{2812, 0}"; + sepNavVisRange = "{2408, 429}"; + }; + }; + 2F895D1B11F903D600C6E55B /* KLDate.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {943, 3562}}"; + sepNavSelRange = "{3887, 56}"; + sepNavVisRange = "{4445, 659}"; + sepNavWindowFrame = "{{15, 68}, {1015, 705}}"; + }; + }; + 2F895D1E11F903D600C6E55B /* KLGridView.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {929, 663}}"; + sepNavSelRange = "{1463, 0}"; + sepNavVisRange = "{1256, 644}"; + sepNavWindowFrame = "{{15, 68}, {1015, 705}}"; + }; + }; + 2F895D1F11F903D600C6E55B /* KLGridView.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {922, 2158}}"; + sepNavSelRange = "{5552, 22}"; + sepNavVisRange = "{5175, 509}"; + sepNavWindowFrame = "{{15, 68}, {1015, 705}}"; + }; + }; + 2F895D2011F903D600C6E55B /* KLTile.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {800, 702}}"; + sepNavSelRange = "{1579, 6}"; + sepNavVisRange = "{1320, 561}"; + }; + }; + 2F895D2111F903D600C6E55B /* KLTile.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {887, 3523}}"; + sepNavSelRange = "{3011, 23}"; + sepNavVisRange = "{2583, 591}"; + sepNavWindowFrame = "{{15, 68}, {1015, 705}}"; + }; + }; + 2F895D2511F903D600C6E55B /* THCalendarInfo.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {800, 1573}}"; + sepNavSelRange = "{1072, 0}"; + sepNavVisRange = "{734, 802}"; + }; + }; + 2F895D2611F903D600C6E55B /* THCalendarInfo.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1335, 7683}}"; + sepNavSelRange = "{1156, 20}"; + sepNavVisRange = "{12519, 469}"; + }; + }; + 2F895DD111F95C3000C6E55B /* TiCalendarView.m:27 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 2F895ADD11F8B60300C6E55B /* TiCalendarView.m */; + functionName = "-init"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 27; + modificationTime = 304058589.116886; + originalNumberOfMultipleMatches = 1; + state = 0; + }; + 2FD2B1CA121E63B600D37686 /* TiCalendarView.m:30 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 2F895ADD11F8B60300C6E55B /* TiCalendarView.m */; + functionName = "-init"; + hitCount = 0; + ignoreCount = 0; + lineNumber = 30; + location = HomeFinder; + modificationTime = 304058589.117323; + originalNumberOfMultipleMatches = 1; + state = 2; + }; + 2FD9F907123FD06800632593 /* MroBinarySearch.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1083, 858}}"; + sepNavSelRange = "{613, 0}"; + sepNavVisRange = "{373, 578}"; + }; + }; + 2FD9F908123FD06800632593 /* MroBinarySearch.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {800, 1989}}"; + sepNavSelRange = "{1174, 13}"; + sepNavVisRange = "{597, 867}"; + }; + }; + 2FD9F90B123FD0D900632593 /* KLDateSort.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {800, 897}}"; + sepNavSelRange = "{280, 0}"; + sepNavVisRange = "{0, 539}"; + }; + }; + 2FD9F90C123FD0D900632593 /* KLDateSort.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {841, 2626}}"; + sepNavSelRange = "{4496, 0}"; + sepNavVisRange = "{4747, 644}"; + }; + }; + 2FD9F961123FD7B100632593 /* NSArray.h */ = { + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.h; + name = NSArray.h; + path = /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.0.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSArray.h; + sourceTree = ""; + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1307, 2106}}"; + sepNavSelRange = "{422, 39}"; + sepNavVisRange = "{74, 852}"; + }; + }; + 2FD9F99B123FDD9400632593 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 2FD9F907123FD06800632593 /* MroBinarySearch.h */; + name = "MroBinarySearch.h: 26"; + rLen = 0; + rLoc = 651; + rType = 0; + vrLen = 685; + vrLoc = 250; + }; + 2FD9F99D123FDD9400632593 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 2FD9F961123FD7B100632593 /* NSArray.h */; + name = "NSArray.h: 17"; + rLen = 39; + rLoc = 422; + rType = 0; + vrLen = 852; + vrLoc = 74; + }; + 2FD9F99F123FDD9400632593 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 2FD9F90B123FD0D900632593 /* KLDateSort.h */; + name = "KLDateSort.h: 13"; + rLen = 0; + rLoc = 280; + rType = 0; + vrLen = 539; + vrLoc = 0; + }; + 2FD9F9D7123FE1C600632593 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 2FD9F908123FD06800632593 /* MroBinarySearch.m */; + name = "MroBinarySearch.m: 42"; + rLen = 13; + rLoc = 1174; + rType = 0; + vrLen = 867; + vrLoc = 597; + }; + 2FD9F9E0123FE2D700632593 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 2F895D1B11F903D600C6E55B /* KLDate.m */; + name = "KLDate.m: 117"; + rLen = 56; + rLoc = 3887; + rType = 0; + vrLen = 659; + vrLoc = 4445; + }; + 2FD9F9E1123FE2D700632593 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 2FD9F90C123FD0D900632593 /* KLDateSort.m */; + name = "KLDateSort.m: 19"; + rLen = 0; + rLoc = 538; + rType = 0; + vrLen = 689; + vrLoc = 147; + }; + 2FD9F9E2123FE2D700632593 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 2F895ADD11F8B60300C6E55B /* TiCalendarView.m */; + name = "TiCalendarView.m: 221"; + rLen = 0; + rLoc = 5355; + rType = 0; + vrLen = 700; + vrLoc = 5190; + }; + 2FD9FA2E124070C900632593 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 2F895ADD11F8B60300C6E55B /* TiCalendarView.m */; + name = "TiCalendarView.m: 221"; + rLen = 0; + rLoc = 5355; + rType = 0; + vrLen = 700; + vrLoc = 5190; + }; + D2AAC07D0554694100DB518D /* CalendarModule */ = { + activeExec = 0; + }; +} diff --git a/CalendarModule.xcodeproj/project.pbxproj b/CalendarModule.xcodeproj/project.pbxproj new file mode 100644 index 0000000..23f5177 --- /dev/null +++ b/CalendarModule.xcodeproj/project.pbxproj @@ -0,0 +1,385 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 24DD6CF91134B3F500162E58 /* CalendarModule.h in Headers */ = {isa = PBXBuildFile; fileRef = 24DD6CF71134B3F500162E58 /* CalendarModule.h */; }; + 24DD6CFA1134B3F500162E58 /* CalendarModule.m in Sources */ = {isa = PBXBuildFile; fileRef = 24DD6CF81134B3F500162E58 /* CalendarModule.m */; }; + 2F895ADA11F8B5ED00C6E55B /* TiCalendarViewProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F895AD811F8B5ED00C6E55B /* TiCalendarViewProxy.h */; }; + 2F895ADB11F8B5ED00C6E55B /* TiCalendarViewProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F895AD911F8B5ED00C6E55B /* TiCalendarViewProxy.m */; }; + 2F895ADE11F8B60300C6E55B /* TiCalendarView.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F895ADC11F8B60300C6E55B /* TiCalendarView.h */; }; + 2F895ADF11F8B60300C6E55B /* TiCalendarView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F895ADD11F8B60300C6E55B /* TiCalendarView.m */; }; + 2F895B5411F8E59500C6E55B /* Calendar.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F895B5211F8E59500C6E55B /* Calendar.h */; }; + 2F895B5511F8E59500C6E55B /* Calendar.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F895B5311F8E59500C6E55B /* Calendar.m */; }; + 2F895C2C11F8FA8F00C6E55B /* CalendarProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F895C2A11F8FA8F00C6E55B /* CalendarProxy.h */; }; + 2F895C2D11F8FA8F00C6E55B /* CalendarProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F895C2B11F8FA8F00C6E55B /* CalendarProxy.m */; }; + 2F895D2711F903D600C6E55B /* CheckmarkTile.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F895D1111F903D600C6E55B /* CheckmarkTile.h */; }; + 2F895D2811F903D600C6E55B /* CheckmarkTile.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F895D1211F903D600C6E55B /* CheckmarkTile.m */; }; + 2F895D2911F903D600C6E55B /* KCalendar_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = 2F895D1311F903D600C6E55B /* KCalendar_Prefix.pch */; }; + 2F895D2A11F903D600C6E55B /* KLCalendarModel.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F895D1411F903D600C6E55B /* KLCalendarModel.h */; }; + 2F895D2B11F903D600C6E55B /* KLCalendarModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F895D1511F903D600C6E55B /* KLCalendarModel.m */; }; + 2F895D2C11F903D600C6E55B /* KLCalendarView.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F895D1611F903D600C6E55B /* KLCalendarView.h */; }; + 2F895D2D11F903D600C6E55B /* KLCalendarView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F895D1711F903D600C6E55B /* KLCalendarView.m */; }; + 2F895D2E11F903D600C6E55B /* KLColors.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F895D1811F903D600C6E55B /* KLColors.h */; }; + 2F895D2F11F903D600C6E55B /* KLColors.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F895D1911F903D600C6E55B /* KLColors.m */; }; + 2F895D3011F903D600C6E55B /* KLDate.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F895D1A11F903D600C6E55B /* KLDate.h */; }; + 2F895D3111F903D600C6E55B /* KLDate.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F895D1B11F903D600C6E55B /* KLDate.m */; }; + 2F895D3211F903D600C6E55B /* KLGraphicsUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F895D1C11F903D600C6E55B /* KLGraphicsUtils.h */; }; + 2F895D3311F903D600C6E55B /* KLGraphicsUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F895D1D11F903D600C6E55B /* KLGraphicsUtils.m */; }; + 2F895D3411F903D600C6E55B /* KLGridView.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F895D1E11F903D600C6E55B /* KLGridView.h */; }; + 2F895D3511F903D600C6E55B /* KLGridView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F895D1F11F903D600C6E55B /* KLGridView.m */; }; + 2F895D3611F903D600C6E55B /* KLTile.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F895D2011F903D600C6E55B /* KLTile.h */; }; + 2F895D3711F903D600C6E55B /* KLTile.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F895D2111F903D600C6E55B /* KLTile.m */; }; + 2F895D3811F903D600C6E55B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F895D2311F903D600C6E55B /* main.m */; }; + 2F895D3911F903D600C6E55B /* THCalendarInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 2F895D2511F903D600C6E55B /* THCalendarInfo.h */; }; + 2F895D3A11F903D600C6E55B /* THCalendarInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 2F895D2611F903D600C6E55B /* THCalendarInfo.m */; }; + 2FD9F909123FD06800632593 /* MroBinarySearch.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FD9F907123FD06800632593 /* MroBinarySearch.h */; }; + 2FD9F90A123FD06800632593 /* MroBinarySearch.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FD9F908123FD06800632593 /* MroBinarySearch.m */; }; + 2FD9F90D123FD0D900632593 /* KLDateSort.h in Headers */ = {isa = PBXBuildFile; fileRef = 2FD9F90B123FD0D900632593 /* KLDateSort.h */; }; + 2FD9F90E123FD0D900632593 /* KLDateSort.m in Sources */ = {isa = PBXBuildFile; fileRef = 2FD9F90C123FD0D900632593 /* KLDateSort.m */; }; + 2FF7BC2C122F3F2F00DD1ECA /* EventKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2FF7BC2B122F3F2F00DD1ECA /* EventKit.framework */; }; + AA747D9F0F9514B9006C5449 /* CalendarModule_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = AA747D9E0F9514B9006C5449 /* CalendarModule_Prefix.pch */; }; + AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AACBBE490F95108600F1A2B1 /* Foundation.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 24DD6CF71134B3F500162E58 /* CalendarModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CalendarModule.h; path = Classes/CalendarModule.h; sourceTree = ""; }; + 24DD6CF81134B3F500162E58 /* CalendarModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CalendarModule.m; path = Classes/CalendarModule.m; sourceTree = ""; }; + 24DD6D1B1134B66800162E58 /* titanium.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = titanium.xcconfig; sourceTree = ""; }; + 2F895AD811F8B5ED00C6E55B /* TiCalendarViewProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TiCalendarViewProxy.h; sourceTree = ""; }; + 2F895AD911F8B5ED00C6E55B /* TiCalendarViewProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TiCalendarViewProxy.m; sourceTree = ""; }; + 2F895ADC11F8B60300C6E55B /* TiCalendarView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TiCalendarView.h; sourceTree = ""; }; + 2F895ADD11F8B60300C6E55B /* TiCalendarView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TiCalendarView.m; sourceTree = ""; }; + 2F895B5211F8E59500C6E55B /* Calendar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Calendar.h; sourceTree = ""; }; + 2F895B5311F8E59500C6E55B /* Calendar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Calendar.m; sourceTree = ""; }; + 2F895C2A11F8FA8F00C6E55B /* CalendarProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CalendarProxy.h; sourceTree = ""; }; + 2F895C2B11F8FA8F00C6E55B /* CalendarProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CalendarProxy.m; sourceTree = ""; }; + 2F895D1111F903D600C6E55B /* CheckmarkTile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CheckmarkTile.h; sourceTree = ""; }; + 2F895D1211F903D600C6E55B /* CheckmarkTile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CheckmarkTile.m; sourceTree = ""; }; + 2F895D1311F903D600C6E55B /* KCalendar_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KCalendar_Prefix.pch; sourceTree = ""; }; + 2F895D1411F903D600C6E55B /* KLCalendarModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KLCalendarModel.h; sourceTree = ""; }; + 2F895D1511F903D600C6E55B /* KLCalendarModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KLCalendarModel.m; sourceTree = ""; }; + 2F895D1611F903D600C6E55B /* KLCalendarView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KLCalendarView.h; sourceTree = ""; }; + 2F895D1711F903D600C6E55B /* KLCalendarView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KLCalendarView.m; sourceTree = ""; }; + 2F895D1811F903D600C6E55B /* KLColors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KLColors.h; sourceTree = ""; }; + 2F895D1911F903D600C6E55B /* KLColors.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KLColors.m; sourceTree = ""; }; + 2F895D1A11F903D600C6E55B /* KLDate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KLDate.h; sourceTree = ""; }; + 2F895D1B11F903D600C6E55B /* KLDate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KLDate.m; sourceTree = ""; }; + 2F895D1C11F903D600C6E55B /* KLGraphicsUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KLGraphicsUtils.h; sourceTree = ""; }; + 2F895D1D11F903D600C6E55B /* KLGraphicsUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KLGraphicsUtils.m; sourceTree = ""; }; + 2F895D1E11F903D600C6E55B /* KLGridView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KLGridView.h; sourceTree = ""; }; + 2F895D1F11F903D600C6E55B /* KLGridView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KLGridView.m; sourceTree = ""; }; + 2F895D2011F903D600C6E55B /* KLTile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KLTile.h; sourceTree = ""; }; + 2F895D2111F903D600C6E55B /* KLTile.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KLTile.m; sourceTree = ""; }; + 2F895D2211F903D600C6E55B /* left-arrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "left-arrow.png"; sourceTree = ""; }; + 2F895D2311F903D600C6E55B /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 2F895D2411F903D600C6E55B /* right-arrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "right-arrow.png"; sourceTree = ""; }; + 2F895D2511F903D600C6E55B /* THCalendarInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = THCalendarInfo.h; sourceTree = ""; }; + 2F895D2611F903D600C6E55B /* THCalendarInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = THCalendarInfo.m; sourceTree = ""; }; + 2FD9F907123FD06800632593 /* MroBinarySearch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MroBinarySearch.h; path = ArrayExtensions/MroBinarySearch.h; sourceTree = ""; }; + 2FD9F908123FD06800632593 /* MroBinarySearch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MroBinarySearch.m; path = ArrayExtensions/MroBinarySearch.m; sourceTree = ""; }; + 2FD9F90B123FD0D900632593 /* KLDateSort.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KLDateSort.h; sourceTree = ""; }; + 2FD9F90C123FD0D900632593 /* KLDateSort.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KLDateSort.m; sourceTree = ""; }; + 2FD9F921123FD1C600632593 /* Test-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Test-Info.plist"; sourceTree = ""; }; + 2FF7BC2B122F3F2F00DD1ECA /* EventKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = EventKit.framework; path = System/Library/Frameworks/EventKit.framework; sourceTree = SDKROOT; }; + AA747D9E0F9514B9006C5449 /* CalendarModule_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CalendarModule_Prefix.pch; sourceTree = SOURCE_ROOT; }; + AACBBE490F95108600F1A2B1 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + D2AAC07E0554694100DB518D /* libCalendarModule.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCalendarModule.a; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + D2AAC07C0554694100DB518D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + AACBBE4A0F95108600F1A2B1 /* Foundation.framework in Frameworks */, + 2FF7BC2C122F3F2F00DD1ECA /* EventKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 034768DFFF38A50411DB9C8B /* Products */ = { + isa = PBXGroup; + children = ( + D2AAC07E0554694100DB518D /* libCalendarModule.a */, + ); + name = Products; + sourceTree = ""; + }; + 0867D691FE84028FC02AAC07 /* CalendarModule */ = { + isa = PBXGroup; + children = ( + 2FD9F904123FCFFE00632593 /* ArrayExtensions */, + 2F895D1011F903D600C6E55B /* Calendar */, + 08FB77AEFE84172EC02AAC07 /* Classes */, + 32C88DFF0371C24200C91783 /* Other Sources */, + 0867D69AFE84028FC02AAC07 /* Frameworks */, + 034768DFFF38A50411DB9C8B /* Products */, + 2FD9F921123FD1C600632593 /* Test-Info.plist */, + ); + name = CalendarModule; + sourceTree = ""; + }; + 0867D69AFE84028FC02AAC07 /* Frameworks */ = { + isa = PBXGroup; + children = ( + AACBBE490F95108600F1A2B1 /* Foundation.framework */, + 2FF7BC2B122F3F2F00DD1ECA /* EventKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 08FB77AEFE84172EC02AAC07 /* Classes */ = { + isa = PBXGroup; + children = ( + 2F895C2A11F8FA8F00C6E55B /* CalendarProxy.h */, + 2F895C2B11F8FA8F00C6E55B /* CalendarProxy.m */, + 2F895B5211F8E59500C6E55B /* Calendar.h */, + 2F895B5311F8E59500C6E55B /* Calendar.m */, + 24DD6CF71134B3F500162E58 /* CalendarModule.h */, + 24DD6CF81134B3F500162E58 /* CalendarModule.m */, + 2F895AD811F8B5ED00C6E55B /* TiCalendarViewProxy.h */, + 2F895AD911F8B5ED00C6E55B /* TiCalendarViewProxy.m */, + 2F895ADC11F8B60300C6E55B /* TiCalendarView.h */, + 2F895ADD11F8B60300C6E55B /* TiCalendarView.m */, + ); + name = Classes; + sourceTree = ""; + }; + 2F895D1011F903D600C6E55B /* Calendar */ = { + isa = PBXGroup; + children = ( + 2F895D1111F903D600C6E55B /* CheckmarkTile.h */, + 2F895D1211F903D600C6E55B /* CheckmarkTile.m */, + 2F895D1311F903D600C6E55B /* KCalendar_Prefix.pch */, + 2F895D1411F903D600C6E55B /* KLCalendarModel.h */, + 2F895D1511F903D600C6E55B /* KLCalendarModel.m */, + 2F895D1611F903D600C6E55B /* KLCalendarView.h */, + 2F895D1711F903D600C6E55B /* KLCalendarView.m */, + 2F895D1811F903D600C6E55B /* KLColors.h */, + 2F895D1911F903D600C6E55B /* KLColors.m */, + 2F895D1A11F903D600C6E55B /* KLDate.h */, + 2F895D1B11F903D600C6E55B /* KLDate.m */, + 2F895D1C11F903D600C6E55B /* KLGraphicsUtils.h */, + 2F895D1D11F903D600C6E55B /* KLGraphicsUtils.m */, + 2F895D1E11F903D600C6E55B /* KLGridView.h */, + 2F895D1F11F903D600C6E55B /* KLGridView.m */, + 2F895D2011F903D600C6E55B /* KLTile.h */, + 2F895D2111F903D600C6E55B /* KLTile.m */, + 2F895D2211F903D600C6E55B /* left-arrow.png */, + 2F895D2311F903D600C6E55B /* main.m */, + 2F895D2411F903D600C6E55B /* right-arrow.png */, + 2F895D2511F903D600C6E55B /* THCalendarInfo.h */, + 2F895D2611F903D600C6E55B /* THCalendarInfo.m */, + ); + path = Calendar; + sourceTree = ""; + }; + 2FD9F904123FCFFE00632593 /* ArrayExtensions */ = { + isa = PBXGroup; + children = ( + 2FD9F907123FD06800632593 /* MroBinarySearch.h */, + 2FD9F908123FD06800632593 /* MroBinarySearch.m */, + 2FD9F90B123FD0D900632593 /* KLDateSort.h */, + 2FD9F90C123FD0D900632593 /* KLDateSort.m */, + ); + name = ArrayExtensions; + sourceTree = ""; + }; + 32C88DFF0371C24200C91783 /* Other Sources */ = { + isa = PBXGroup; + children = ( + AA747D9E0F9514B9006C5449 /* CalendarModule_Prefix.pch */, + 24DD6D1B1134B66800162E58 /* titanium.xcconfig */, + ); + name = "Other Sources"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + D2AAC07A0554694100DB518D /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + AA747D9F0F9514B9006C5449 /* CalendarModule_Prefix.pch in Headers */, + 24DD6CF91134B3F500162E58 /* CalendarModule.h in Headers */, + 2F895ADA11F8B5ED00C6E55B /* TiCalendarViewProxy.h in Headers */, + 2F895ADE11F8B60300C6E55B /* TiCalendarView.h in Headers */, + 2F895B5411F8E59500C6E55B /* Calendar.h in Headers */, + 2F895C2C11F8FA8F00C6E55B /* CalendarProxy.h in Headers */, + 2F895D2711F903D600C6E55B /* CheckmarkTile.h in Headers */, + 2F895D2911F903D600C6E55B /* KCalendar_Prefix.pch in Headers */, + 2F895D2A11F903D600C6E55B /* KLCalendarModel.h in Headers */, + 2F895D2C11F903D600C6E55B /* KLCalendarView.h in Headers */, + 2F895D2E11F903D600C6E55B /* KLColors.h in Headers */, + 2F895D3011F903D600C6E55B /* KLDate.h in Headers */, + 2F895D3211F903D600C6E55B /* KLGraphicsUtils.h in Headers */, + 2F895D3411F903D600C6E55B /* KLGridView.h in Headers */, + 2F895D3611F903D600C6E55B /* KLTile.h in Headers */, + 2F895D3911F903D600C6E55B /* THCalendarInfo.h in Headers */, + 2FD9F909123FD06800632593 /* MroBinarySearch.h in Headers */, + 2FD9F90D123FD0D900632593 /* KLDateSort.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + D2AAC07D0554694100DB518D /* CalendarModule */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "CalendarModule" */; + buildPhases = ( + D2AAC07A0554694100DB518D /* Headers */, + D2AAC07B0554694100DB518D /* Sources */, + D2AAC07C0554694100DB518D /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = CalendarModule; + productName = CalendarModule; + productReference = D2AAC07E0554694100DB518D /* libCalendarModule.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0867D690FE84028FC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "CalendarModule" */; + compatibilityVersion = "Xcode 3.1"; + hasScannedForEncodings = 1; + mainGroup = 0867D691FE84028FC02AAC07 /* CalendarModule */; + productRefGroup = 034768DFFF38A50411DB9C8B /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + D2AAC07D0554694100DB518D /* CalendarModule */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + D2AAC07B0554694100DB518D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 24DD6CFA1134B3F500162E58 /* CalendarModule.m in Sources */, + 2F895ADB11F8B5ED00C6E55B /* TiCalendarViewProxy.m in Sources */, + 2F895ADF11F8B60300C6E55B /* TiCalendarView.m in Sources */, + 2F895B5511F8E59500C6E55B /* Calendar.m in Sources */, + 2F895C2D11F8FA8F00C6E55B /* CalendarProxy.m in Sources */, + 2F895D2811F903D600C6E55B /* CheckmarkTile.m in Sources */, + 2F895D2B11F903D600C6E55B /* KLCalendarModel.m in Sources */, + 2F895D2D11F903D600C6E55B /* KLCalendarView.m in Sources */, + 2F895D2F11F903D600C6E55B /* KLColors.m in Sources */, + 2F895D3111F903D600C6E55B /* KLDate.m in Sources */, + 2F895D3311F903D600C6E55B /* KLGraphicsUtils.m in Sources */, + 2F895D3511F903D600C6E55B /* KLGridView.m in Sources */, + 2F895D3711F903D600C6E55B /* KLTile.m in Sources */, + 2F895D3811F903D600C6E55B /* main.m in Sources */, + 2F895D3A11F903D600C6E55B /* THCalendarInfo.m in Sources */, + 2FD9F90A123FD06800632593 /* MroBinarySearch.m in Sources */, + 2FD9F90E123FD0D900632593 /* KLDateSort.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1DEB921F08733DC00010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + COPY_PHASE_STRIP = NO; + DSTROOT = /tmp/CalendarModule.dst; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = CalendarModule_Prefix.pch; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = CalendarModule; + }; + name = Debug; + }; + 1DEB922008733DC00010E9CD /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + DSTROOT = /tmp/CalendarModule.dst; + GCC_MODEL_TUNING = G5; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = CalendarModule_Prefix.pch; + INSTALL_PATH = /usr/local/lib; + PRODUCT_NAME = CalendarModule; + }; + name = Release; + }; + 1DEB922308733DC00010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OTHER_LDFLAGS = ""; + PREBINDING = NO; + SDKROOT = iphoneos4.0; + }; + name = Debug; + }; + 1DEB922408733DC00010E9CD /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 24DD6D1B1134B66800162E58 /* titanium.xcconfig */; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OTHER_LDFLAGS = ""; + PREBINDING = NO; + SDKROOT = iphoneos4.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "CalendarModule" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB921F08733DC00010E9CD /* Debug */, + 1DEB922008733DC00010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "CalendarModule" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB922308733DC00010E9CD /* Debug */, + 1DEB922408733DC00010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0867D690FE84028FC02AAC07 /* Project object */; +} diff --git a/CalendarModule_Prefix.pch b/CalendarModule_Prefix.pch new file mode 100644 index 0000000..8bec24f --- /dev/null +++ b/CalendarModule_Prefix.pch @@ -0,0 +1,4 @@ + +#ifdef __OBJC__ + #import +#endif diff --git a/CalendarProxy.h b/CalendarProxy.h new file mode 100644 index 0000000..8167bfc --- /dev/null +++ b/CalendarProxy.h @@ -0,0 +1,15 @@ +/** + * Appcelerator Titanium Mobile + * Copyright (c) 2009-2010 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the Apache Public License + * Please see the LICENSE included with this distribution for details. + */ +#import "TiViewProxy.h" + +@interface CalendarProxy : TiViewProxy { + +@private + +} + +@end diff --git a/CalendarProxy.m b/CalendarProxy.m new file mode 100644 index 0000000..8924d1e --- /dev/null +++ b/CalendarProxy.m @@ -0,0 +1,16 @@ +/** + * Appcelerator Titanium Mobile + * Copyright (c) 2009-2010 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the Apache Public License + * Please see the LICENSE included with this distribution for details. + */ + +#import "CalendarProxy.h" + +#import "TiUtils.h" + +@implementation CalendarProxy + + + +@end diff --git a/CalendarViewController.h b/CalendarViewController.h new file mode 100644 index 0000000..5570d51 --- /dev/null +++ b/CalendarViewController.h @@ -0,0 +1,24 @@ +// +// CalendarTestViewController.h +// CalendarTest +// +// Created by Ved Surtani on 10/03/09. +// Copyright Pramati Technologies 2009. All rights reserved. +// + +#import +#import "KLCalendarView.h" +#import "CheckmarkTile.h" + +@interface CalendarViewController : UIViewController { + KLCalendarView *calendarView; + KLTile *currentTile; + UITableView *myTableView; + NSMutableArray *tableViewData; + KLTile *tile; + BOOL shouldPushAnotherView; + +} + +@end + diff --git a/CalendarViewController.m b/CalendarViewController.m new file mode 100644 index 0000000..0f80171 --- /dev/null +++ b/CalendarViewController.m @@ -0,0 +1,154 @@ +// +// CalendarTestViewController.m +// CalendarTest +// +// Created by Ved Surtani on 10/03/09. +// Copyright Pramati Technologies 2009. All rights reserved. +// + +#import "CalendarViewController.h" + +@implementation CalendarViewController + + + +/* +// The designated initializer. Override to perform setup that is required before the view is loaded. +- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { + if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) { + // Custom initialization + } + return self; +} +*/ + + +- (void)loadView { + [super loadView]; + calendarView = [[[KLCalendarView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 360) delegate:self] autorelease]; + + myTableView = [[UITableView alloc]initWithFrame:CGRectMake(0,260,320,160) style:UITableViewStylePlain]; + + myTableView.dataSource = self; + myTableView.delegate = self; + UIView *myHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0,0,myTableView.frame.size.width , 20)]; + myHeaderView.backgroundColor = [UIColor grayColor]; + [myTableView setTableHeaderView:myHeaderView]; + + + [self.view addSubview:myTableView]; + [self.view addSubview:calendarView]; + [self.view bringSubviewToFront:myTableView]; + +} +#pragma mark tableViewDelegate Methods +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return 5; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + static NSString *MyIdentifier = @"MyIdentifier"; + + + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier]; + if (cell == nil) { + cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease]; + } + cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; + [cell setText:@"No Data For Now"]; + + return cell; + +} + + +/*----- Calendar Delegates -----> */ + +- (void)calendarView:(KLCalendarView *)calendarView tappedTile:(KLTile *)aTile{ + NSLog(@"Date Selected is %@",[aTile date]); + + [aTile flash]; + + /*if(tile == nil) + tile = aTile; + else + [tile restoreBackgroundColor];*/ + + + +} + +- (KLTile *)calendarView:(KLCalendarView *)calendarView createTileForDate:(KLDate *)date{ + + + CheckmarkTile *tile = [[CheckmarkTile alloc] init]; + + return tile; + +} + +- (void)didChangeMonths{ + + UIView *clip = calendarView.superview; + if (!clip) + return; + + CGRect f = clip.frame; + NSInteger weeks = [calendarView selectedMonthNumberOfWeeks]; + CGFloat adjustment = 0.f; + + switch (weeks) { + case 4: + adjustment = (92/321)*360+30; + break; + case 5: + adjustment = (46/321)*360; + break; + case 6: + adjustment = 0.f; + break; + default: + break; + } + f.size.height = 360 - adjustment; + clip.frame = f; + + CGRect f2 = CGRectMake(0,260-adjustment,320,160+adjustment); + myTableView.frame = f2; + [self.view bringSubviewToFront:myTableView]; + tile = nil; +} + + +/* +// Implement viewDidLoad to do additional setup after loading the view, typically from a nib. +- (void)viewDidLoad { + [super viewDidLoad]; +} +*/ + + +/* +// Override to allow orientations other than the default portrait orientation. +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { + // Return YES for supported orientations + return (interfaceOrientation == UIInterfaceOrientationPortrait); +} +*/ + + +- (void)didReceiveMemoryWarning { + [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview + // Release anything that's not essential, such as cached data +} + + +- (void)dealloc { + [super dealloc]; +} + +@end diff --git a/CalendarViewController.xib b/CalendarViewController.xib new file mode 100644 index 0000000..29f4396 --- /dev/null +++ b/CalendarViewController.xib @@ -0,0 +1,138 @@ + + + + 528 + 9E17 + 672 + 949.33 + 352.00 + + YES + + + + YES + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + YES + + IBFilesOwner + + + IBFirstResponder + + + + 274 + {320, 460} + + + 3 + MC43NQA + + 2 + + + NO + + + + + + YES + + + view + + + + 7 + + + + + YES + + 0 + + YES + + + + + + -1 + + + RmlsZSdzIE93bmVyA + + + -2 + + + + + 6 + + + + + + + YES + + YES + -1.CustomClassName + -2.CustomClassName + 6.IBEditorWindowLastContentRect + 6.IBPluginDependency + + + YES + CalendarTestViewController + UIResponder + {{438, 347}, {320, 480}} + com.apple.InterfaceBuilder.IBCocoaTouchPlugin + + + + YES + + YES + + + YES + + + + + YES + + YES + + + YES + + + + 7 + + + + YES + + CalendarTestViewController + UIViewController + + IBProjectSource + Classes/CalendarTestViewController.h + + + + + 0 + CalendarTest.xcodeproj + 3 + + diff --git a/Classes/CalendarModule.h b/Classes/CalendarModule.h new file mode 100644 index 0000000..7b6479b --- /dev/null +++ b/Classes/CalendarModule.h @@ -0,0 +1,13 @@ +/** + * Your Copyright Here + * + * Appcelerator Titanium is Copyright (c) 2009-2010 by Appcelerator, Inc. + * and licensed under the Apache Public License (version 2) + */ +#import "TiModule.h" + +@interface CalendarModule : TiModule +{ +} + +@end diff --git a/Classes/CalendarModule.m b/Classes/CalendarModule.m new file mode 100644 index 0000000..836e533 --- /dev/null +++ b/Classes/CalendarModule.m @@ -0,0 +1,98 @@ +/** + * Your Copyright Here + * + * Appcelerator Titanium is Copyright (c) 2009-2010 by Appcelerator, Inc. + * and licensed under the Apache Public License (version 2) + */ +#import "CalendarModule.h" +#import "TiBase.h" +#import "TiHost.h" +#import "TiUtils.h" + +@implementation CalendarModule + +#pragma mark Lifecycle + +-(void)startup +{ + // this method is called when the module is first loaded + // you *must* call the superclass + [super startup]; + + NSLog(@"[INFO] %@ loaded",self); +} + +-(void)shutdown:(id)sender +{ + // this method is called when the module is being unloaded + // typically this is during shutdown. make sure you don't do too + // much processing here or the app will be quit forceably + + // you *must* call the superclass + [super shutdown:sender]; +} + +#pragma mark Cleanup + +-(void)dealloc +{ + // release any resources that have been retained by the module + [super dealloc]; +} + +#pragma mark Internal Memory Management + +-(void)didReceiveMemoryWarning:(NSNotification*)notification +{ + // optionally release any resources that can be dynamically + // reloaded once memory is available - such as caches + [super didReceiveMemoryWarning:notification]; +} + +#pragma mark Listener Notifications + +-(void)_listenerAdded:(NSString *)type count:(int)count +{ + if (count == 1 && [type isEqualToString:@"my_event"]) + { + // the first (of potentially many) listener is being added + // for event named 'my_event' + } +} + +-(void)_listenerRemoved:(NSString *)type count:(int)count +{ + if (count == 0 && [type isEqualToString:@"my_event"]) + { + // the last listener called for event named 'my_event' has + // been removed, we can optionally clean up any resources + // since no body is listening at this point for that event + } +} + +#pragma Public APIs + +-(id)example:(id)args +{ +// KLCalendarView* calendarView = [[[KLCalendarView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 360) delegate:self] autorelease]; +// return calendarView; + +// view = [[[UIView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 360) delegate:self] autorelease]; +// return view; + + // example method + return @"hello world"; +} + +-(id)exampleProp +{ + // example property getter + return @"hello world"; +} + +-(void)exampleProp:(id)value +{ + // example property setter +} + +@end diff --git a/KLDateSort.h b/KLDateSort.h new file mode 100644 index 0000000..7a10f7c --- /dev/null +++ b/KLDateSort.h @@ -0,0 +1,62 @@ +// +// KLDateSort.h +// CalendarModule +// +// Created by Scott Montgomerie on 10-09-14. +// Copyright 2010 __MyCompanyName__. All rights reserved. +// + +#import + +NSInteger KLDateSort(id date, id kldate, void *context); + +@interface MroBinarySearch :NSObject { + NSArray *theArray; +} + +- (MroBinarySearch*) initWithArray: (NSArray*) array; +- (int)count; +- (id)objectAtIndex:(NSUInteger)index; + +-(NSInteger)binarySearch:(id)key; + +/** + * @see MroBinarySearch::binarySearch: + * @see NSArray::sortedArrayUsingSelector: + */ +-(NSInteger)binarySearch:(id)key usingSelector:(SEL)comparator; + +/** + * Binary search a part of an array. + * + * @param key nil returns -1 + * @param comparator may be nil to use @selector(compare:) + * @param range + * @return found index. + * + * @see MroBinarySearch::binarySearch: + * @see NSArray::sortedArrayUsingSelector: + */ +-(NSInteger)binarySearch:(id)key usingSelector:(SEL)comparator inRange:(NSRange)range; + +/** + * @see MroBinarySearch::binarySearch: + * @see NSArray::sortedArrayUsingFunction:context: + */ +-(NSInteger)binarySearch:(id)key usingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context; + +/** + * @see MroBinarySearch::binarySearch: + * @see NSArray::sortedArrayUsingFunction:context: + */ +-(NSInteger)binarySearch:(id)key usingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context inRange:(NSRange)range; + +/** + * @see MroBinarySearch::binarySearch: + * @see NSArray::sortedArrayUsingDescriptors: + */ +-(NSInteger)binarySearch:(id)key usingDescriptors:(NSArray *)sortDescriptors; + +-(NSInteger)binarySearch:(id)key usingDescriptors:(NSArray *)sortDescriptors inRange:(NSRange)range; + +@end diff --git a/KLDateSort.m b/KLDateSort.m new file mode 100644 index 0000000..d087955 --- /dev/null +++ b/KLDateSort.m @@ -0,0 +1,194 @@ +// +// KLDateSort.m +// CalendarModule +// +// Created by Scott Montgomerie on 10-09-14. +// Copyright 2010 __MyCompanyName__. All rights reserved. +// + +#import "KLDateSort.h" +#import "KLDate.h" + +NSInteger KLDateSort(id date, id kldate, void *context) +{ +// NSLog(@"KLDateSortComparing %@ with %@", date, kldate); + + if ([date isKindOfClass:[NSDate class]] && [kldate isKindOfClass:[NSDate class]]) + { + NSLog(@"Can't compare two NSDates... one has to be a KLDate"); + // Because the compareWithNSDate function only takes into account dd/mm/yyyy, not time + } + else if ([date isKindOfClass:[KLDate class]]) + { + return [((KLDate* )date) compareWithNSDate: ((NSDate*) kldate)]; + } + else if ([kldate isKindOfClass:[KLDate class]]) + { + return [((KLDate* )kldate) compareWithNSDate: ((NSDate*) date)]; + } + return 0; +} + +// +// MroBinarySearch.m +// +// Created by Marcus Rohrmoser on 12.01.10. +// Copyright 2010 Marcus Rohrmoser mobile Software. All rights reserved. +// + +@implementation MroBinarySearch + +#pragma mark Using Selector + +- (MroBinarySearch*) initWithArray: (NSArray*) array +{ + self = [super init]; + if ( self ) + { + theArray = array; + } + return self; +} + +- (int)count { + return [theArray count]; +} + +- (id)objectAtIndex:(NSUInteger)index +{ + return [theArray objectAtIndex:index]; +} + +-(NSInteger)binarySearch:(id)key +{ + return [self binarySearch:key usingSelector:nil]; +} + + +-(NSInteger)binarySearch:(id)key usingSelector:(SEL)comparator +{ + return [self binarySearch:key usingSelector:comparator inRange:NSMakeRange(0, self.count)]; +} + + +-(NSInteger)binarySearch:(id)key usingSelector:(SEL)comparator inRange:(NSRange)range +{ + // NSLogD(@"[NSArray(MroBinarySearch) binarySearch:%@ usingSelector:]", key); + if (self.count == 0 || key == nil) + return -1; + if(comparator == nil) + comparator = @selector(compare:); + + // check overflow? + NSInteger min = range.location; + NSInteger max = range.location + range.length - 1; + + while (min <= max) + { + // http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html + const NSInteger mid = min + (max - min) / 2; + switch ((NSComparisonResult)[key performSelector:comparator withObject:[self objectAtIndex:mid]]) + { + case NSOrderedSame: + return mid; + case NSOrderedDescending: + min = mid + 1; + break; + case NSOrderedAscending: + max = mid - 1; + break; + } + } + return -(min + 1); +} + + +#pragma mark Using C-Function + +-(NSInteger)binarySearch:(id)key usingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context +{ + return [self binarySearch:key usingFunction:comparator context:context inRange:NSMakeRange(0, self.count)]; +} + + +-(NSInteger)binarySearch:(id)key usingFunction:(NSInteger (*)(id, id, void *))comparator context:(void *)context inRange:(NSRange)range +{ + // NSLogD(@"[NSArray(MroBinarySearch) binarySearch:%@ usingFunction:]", key); + if(self.count == 0 || key == nil || comparator == NULL) + return [self binarySearch:key usingSelector:nil inRange:range]; + + // check overflow? + NSInteger min = range.location; + NSInteger max = range.location + range.length - 1; + + while (min <= max) + { + // http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html + const NSInteger mid = min + (max - min) / 2; + switch (comparator(key, [self objectAtIndex:mid], context)) + { + case NSOrderedSame: + return mid; + case NSOrderedDescending: + min = mid + 1; + break; + case NSOrderedAscending: + max = mid - 1; + break; + } + } + return -(min + 1); +} + + +#pragma mark Using NSSortDescriptors + +-(NSInteger)binarySearch:(id)key usingDescriptors:(NSArray *)sortDescriptors +{ + return [self binarySearch:key usingDescriptors:sortDescriptors inRange:NSMakeRange(0, self.count)]; +} + + +/// internal helper +-(NSComparisonResult)_mroInternalCompare:(const NSArray const*)sortDescriptors a:(id)object1 b:(id)object2 +{ + for (const NSSortDescriptor const *d in sortDescriptors) + { + const NSComparisonResult r = [d compareObject:object1 toObject:object2]; + if (r != NSOrderedSame) + return r; + } + return NSOrderedSame; +} + + +-(NSInteger)binarySearch:(id)key usingDescriptors:(NSArray *)sortDescriptors inRange:(NSRange)range +{ + // NSLogD(@"[NSArray(MroBinarySearch) binarySearch:%@ usingDescriptors:]", key); + if (self.count == 0 || key == nil || sortDescriptors == nil || sortDescriptors.count == 0) + return [self binarySearch:key usingSelector:nil inRange:range]; + + // check overflow? + NSInteger min = range.location; + NSInteger max = range.location + range.length - 1; + + while (min <= max) + { + // http://googleresearch.blogspot.com/2006/06/extra-extra-read-all-about-it-nearly.html + const NSInteger mid = min + (max - min) / 2; + switch ([self _mroInternalCompare:sortDescriptors a:key b:[self objectAtIndex:mid]]) + { + case NSOrderedSame: + return mid; + case NSOrderedDescending: + min = mid + 1; + break; + case NSOrderedAscending: + max = mid - 1; + break; + } + } + return -(min + 1); +} + +@end diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6ae867d --- /dev/null +++ b/LICENSE @@ -0,0 +1 @@ +TODO: place your license here and we'll include it in the module distribution diff --git a/README b/README new file mode 100644 index 0000000..142b4a7 --- /dev/null +++ b/README @@ -0,0 +1,87 @@ +Appcelerator Titanium iPhone Module Project +=========================================== + +This is a skeleton Titanium Mobile iPhone module project. Modules can be +used to extend the functionality of Titanium by providing additional native +code that is compiled into your application at build time and can expose certain +APIs into JavaScript. + +MODULE NAMING +-------------- + +Choose a unique name for your module to not cause conflict with other third-party +modules. Typically, we recommend prefixing your module with a token that identifies +your organization. In the future, we may provide the ability to register your own +top level namespaces. Currently, all modules will be available only via the +Titanium namespace. For example, if your module is named `MyFirstModule`, you would +access module APIs via the API: `Titanium.Myfirst`. The module in the name will +automatically be removed when resolving your module. Also, all characters after the +first are always lower-cased. + +COMPONENTS +----------- + +Components that are exposed by your module must follow a special naming convention. +A component (widget, proxy, etc) must be named with the pattern: + + TiProxy + +For example, if you component was called Foo, your proxy would be named: + + TiMyfirstFooProxy + +For view proxies or widgets, you must create both a view proxy and a view implementation. +If you widget was named proxy, you would create the following files: + + TiMyfirstFooProxy.h + TiMyfirstFooProxy.m + TiMyfirstFoo.h + TiMyfirstFoo.m + +The view implementation is named the same except it does contain the suffix `Proxy`. + +View implementations extend the Titanium base class `TiUIView`. View Proxies extend the +Titanium base class `TiUIViewProxy` or `TiUIWidgetProxy`. + +For proxies that are simply native objects that can be returned to JavaScript, you can +simply extend `TiProxy` and no view implementation is required. + + +GET STARTED +------------ + +1. Edit manifest with the appropriate details about your module. +2. Edit LICENSE to add your license details. +3. Place any assets (such as PNG files) that are required in the assets folder. +4. Edit the titanium.xcconfig and make sure you're building for the right Titanium version. +5. Code and build. + +INSTALL YOUR MODULE +-------------------- + +1. Run `build.py` which creates your distribution +2. cd to `/Library/Application Support/Titanium` +3. extract your zip into this folder + +REGISTER YOUR MODULE +--------------------- + +Register your module with your application by editing `tiapp.xml` and adding your module. +Example: + + + mymodule + + +When you run your project, the compiler will know automatically compile in your module +dependencies and copy appropriate image assets into the application. + +DISTRIBUTING YOUR MODULE +------------------------- + +Currently, you will need to manually distribution your module distribution zip file directly. +However, in the near future, we will make module distribution and sharing built-in to +Titanium Developer! + + +Cheers! diff --git a/TiCalendarView.h b/TiCalendarView.h new file mode 100644 index 0000000..40b9484 --- /dev/null +++ b/TiCalendarView.h @@ -0,0 +1,41 @@ +/** + * Appcelerator Titanium Mobile + * Copyright (c) 2009-2010 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the Apache Public License + * Please see the LICENSE included with this distribution for details. + */ +#import "TiUIView.h" +#import + +#import "KLCalendarView.h" +#import "KLTile.h" +#import "CheckmarkTile.h" + +@interface TiCalendarView : TiUIView { + +@private + MKMapView *map; + KLCalendarView *calendarView; + KLTile *currentTile; + UITableView *myTableView; + NSMutableArray *tableViewData; + KLTile *tile; + BOOL shouldPushAnotherView; + + NSMutableArray* dates; + NSNumber* month; +} + +@property(nonatomic, retain) NSArray* dates; +@property(nonatomic, retain) NSNumber* month; + +- (void) setDatesArray: (NSArray*) datesArray; +- (void) setMonth: (NSNumber*) value; +- (void) setCalendarColor_: (id) color; +- (void) setHeaderColor_: (id) color; +- (bool) dateChecked: (KLDate*) date; + +//-(UIView*) calendar; + + +@end diff --git a/TiCalendarView.m b/TiCalendarView.m new file mode 100644 index 0000000..8c6e0f3 --- /dev/null +++ b/TiCalendarView.m @@ -0,0 +1,304 @@ +/** + * Appcelerator Titanium Mobile + * Copyright (c) 2009-2010 by Appcelerator, Inc. All Rights Reserved. + * Licensed under the terms of the Apache Public License + * Please see the LICENSE included with this distribution for details. + */ + +#import "TiCalendarView.h" +#import "KLGridView.h" +#import "KLTile.h" +#import "KLDateSort.h" +#import "MroBinarySearch.h" + +#import "TiUtils.h" + +@implementation TiCalendarView + +@synthesize dates, month; + +- (id) init +{ + // NSLog(@"Init view"); + + self = [super init]; + if (self != nil) + { + calendarView = [[[KLCalendarView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 360) delegate:self] autorelease]; + //myTableView = [[UITableView alloc]initWithFrame:CGRectMake(0,260,320,160) style:UITableViewStylePlain]; + + id c = [self.proxy valueForUndefinedKey:@"calendarColor"]; + if ( c != nil ) + { + NSLog(@"Setting color: %@", c); + TiColor *color = [TiUtils colorValue:c]; + [calendarView setBackgroundColor:[color _color]]; + } + + NSLog(@"Init"); + + //myTableView.dataSource = self; + //myTableView.delegate = self; + UIView *myHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0,0,myTableView.frame.size.width , 20)]; + c = [self.proxy valueForUndefinedKey:@"headerColor"]; + if ( c != nil ) + { + TiColor *color = [TiUtils colorValue:c]; + myHeaderView.backgroundColor = [color _color]; + } + else + { + myHeaderView.backgroundColor = [UIColor grayColor]; + } + //[myTableView setTableHeaderView:myHeaderView]; + + + // [self addSubview:myTableView]; + [self addSubview:calendarView]; + //[self bringSubviewToFront:myTableView]; + + + } + return self; +} + +/* +-(UIView*) calendar +{ + NSLog(@"Build view"); + + + if (map==nil) + { + map = [[MKMapView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 360)]; + map.delegate = self; + map.userInteractionEnabled = YES; + map.showsUserLocation = YES; // defaults + map.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; + [self addSubview:map]; + } + return map; +} + */ + +#pragma mark tableViewDelegate Methods +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + return 5; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + static NSString *MyIdentifier = @"MyIdentifier"; + + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier]; + if (cell == nil) { + cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease]; + } + cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; + // [cell setText:@"No Data For Now"]; + + return cell; + +} + + +/*----- Calendar Delegates -----> */ + +- (void)calendarView:(KLCalendarView *)calView tappedTile:(KLTile *)aTile{ + NSLog(@"Date Selected is %@",[aTile date]); + + [aTile flash]; + + if(tile == nil) + { + tile = aTile; + } + else + { + [tile restoreBackgroundColor]; +// tile.backgroundColor = calendarView.backgroundColor; + tile = aTile; + } + + NSMutableDictionary* data = [NSMutableDictionary dictionaryWithObjectsAndKeys: + [[aTile date] toNSDate],@"date", + nil]; + + [self.proxy fireEvent:@"dateSelected" withObject: data propagate:NO]; +// [self _fireEventToListener:@"dateSelected" withObject:[aTile date] listener:callback thisObject:nil]; +} + +- (KLTile *)calendarView:(KLCalendarView *)calView createTileForDate:(KLDate *)date{ + + //NSLog(@"createTileForDate: %@", date); + + CheckmarkTile *t = [[CheckmarkTile alloc] init]; + t.checkmarked = NO;//based on any condition you can checkMark a tile + + bool checked = [self dateChecked: date]; + + /* + int index = [dates indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop) { + if ( [date compareWithNSDate: ((NSDate*) obj)] == NSOrderedSame) + { + // NSLog(@"Same %@ with %@", date, obj); + *stop =YES; + return YES; + } + return NO; + }]; + */ +// NSLog(@"index: %d", index); + + if ( checked ) + { + ((CheckmarkTile*) t).checkmarked = YES; + [t setNeedsDisplay]; + } + +// t.backgroundColor = calendarView.backgroundColor; + + return t; + +} + +- (void)didChangeMonths{ + + UIView *clip = calendarView.superview; + if (!clip) + return; + + CGRect f = clip.frame; + NSInteger weeks = [calendarView selectedMonthNumberOfWeeks]; + CGFloat adjustment = 0.f; + + switch (weeks) { + case 4: + adjustment = (92/321)*360+30; + break; + case 5: + adjustment = (46/321)*360; + break; + case 6: + adjustment = 0.f; + break; + default: + break; + } + f.size.height = 360 - adjustment; + clip.frame = f; + + CGRect f2 = CGRectMake(0,260-adjustment,320,160+adjustment); + myTableView.frame = f2; + [self bringSubviewToFront:myTableView]; + tile = nil; +} + +-(bool) dateChecked: (KLDate*) date +{ +// NSLog(@"datechecked %@", date); +/* + bool found=false; + for ( int i=0; i< dates.count; i++) + { + NSDate* obj = [dates objectAtIndex:i]; + // NSLog(@"Comparing %@ with %@", date, obj); + if ( [date compareWithNSDate: ((NSDate*) obj)] == NSOrderedSame) + { + found = TRUE; + break; + } + + if (found) break; + } + NSLog(@"index: %d", found); +*/ + + MroBinarySearch* binarySearch = [[MroBinarySearch alloc] initWithArray:dates]; + NSInteger index= [binarySearch binarySearch:date usingFunction: KLDateSort context:NULL]; +// NSLog(@"bs1 index: %d", index); + + /* NSInteger bs1 = [dates binarySearch:[date toNSDate]]; + NSLog(@"bs1 index: %d", bs1); + + NSInteger bs = [dates binarySearch:date usingFunction:KLDateSort context:NULL]; + NSLog(@"bs index: %d", bs); +*/ + + return ( index >=0 && dates.count > 0 ); +} + + +- (void) setDatesArray: (NSArray*) datesArray +{ + ENSURE_TYPE(datesArray,NSArray); + + + NSLog(@"setdatesArray %d objects", datesArray.count); + dates = [NSMutableArray arrayWithCapacity:datesArray.count]; + + if ( datesArray.count > 0 ) + { + for (int i=0; i + +@implementation TiCalendarViewProxy + +#pragma mark Internal + +-(void)_configure +{ + NSLog(@"configure"); +} + +-(void)_destroy +{ + NSLog(@"destroy"); +} + +-(void)viewDidAttach +{ + NSLog(@"view Did Attach"); +} + +-(NSArray*) dates +{ + return [((TiCalendarView* ) self.view) dates]; +} + +- (void) setDates: (NSArray*) datesArray +{ + ENSURE_UI_THREAD(setDates,datesArray); + + NSLog(@"setDates %d", datesArray.count); + + dates = [NSMutableArray arrayWithCapacity:datesArray.count]; + + for (int i=0; i