home *** CD-ROM | disk | FTP | other *** search
- //----------------------------------------------------------------------------------------------------
- //
- // Calendar
- //
- // Inherits From: Control
- //
- // Declared In: Calendar.h
- //
- // Disclaimer
- //
- // You may freely copy, distribute and reuse this software and its
- // associated documentation. I disclaim any warranty of any kind,
- // expressed or implied, as to its fitness for any particular use.
- //
- //----------------------------------------------------------------------------------------------------
- #import "Calendar.h"
-
-
- static const char* DAYS [7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
-
- static const char* MONTHS [12] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
-
- static int LAST_DAY_OF_MONTH [13] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-
- char dateString [25];
-
-
-
- @implementation Calendar
-
- //----------------------------------------------------------------------------------------------------
- // Private Methods
- //----------------------------------------------------------------------------------------------------
- - _initMonthTextField
- {
- // Create the monthTextField instance and add it as a subview.
-
- Font* font = [Font newFont:"Helvetica-Bold" size:12 style:0 matrix:NX_FLIPPEDMATRIX];
- NXRect frameRect = {5.0, 114.0, 94.0, 15.0};
-
- monthTextField = [[TextField allocFromZone:[self zone]] initFrame: &frameRect];
- [monthTextField setEditable: NO];
- [monthTextField setBezeled: NO];
- [monthTextField setBackgroundColor: NX_COLORLTGRAY];
- [monthTextField setFont: font];
- [self addSubview: monthTextField];
- return self;
- }
-
-
- - _initYearTextField
- {
- // Create the yearTextField instance and add it as a subview.
-
- Font* font = [Font newFont:"Helvetica-Bold" size:12 style:0 matrix:NX_FLIPPEDMATRIX];
- NXRect frameRect = {133.0, 114.0, 33.0, 15.0};
-
- yearTextField = [[TextField allocFromZone:[self zone]] initFrame: &frameRect];
- [yearTextField setEditable: NO];
- [yearTextField setBezeled: NO];
- [yearTextField setAlignment: NX_RIGHTALIGNED];
- [yearTextField setBackgroundColor: NX_COLORLTGRAY];
- [yearTextField setFont: font];
- [self addSubview: yearTextField];
- return self;
- }
-
-
- - _initWeekdayTextField
- {
- // Create the weekdayTextField instance and add it as a subview.
-
- Font* font = [Font newFont:"Helvetica-Bold" size:10 style:0 matrix:NX_FLIPPEDMATRIX];
- NXRect frameRect = {7.0, 96.0, 157.0, 13.0};
-
- weekdayTextField = [[TextField allocFromZone:[self zone]] initFrame: &frameRect];
- [weekdayTextField setEditable: NO];
- [weekdayTextField setBezeled: NO];
- [weekdayTextField setAlignment: NX_CENTERED];
- [weekdayTextField setBackgroundColor: NX_COLORDKGRAY];
- [weekdayTextField setTextColor: NX_COLORWHITE];
- [weekdayTextField setFont: font];
- [weekdayTextField setStringValue: " S M T W T F S"];
- [self addSubview: weekdayTextField];
- return self;
- }
-
-
- - _initDayMatrix
- {
- // Create the dayMatrix ButtonCell Matrix and add it as a subview.
-
- id buttonCell;
- int cellTag = 0;
- int row;
- int column;
- Font* font = [Font newFont:"Helvetica" size:10 style:0 matrix:NX_FLIPPEDMATRIX];
- NXRect matrixRect = {7.0, 3.0, 161.0, 90.0};
- NXRect cellRect = {0.0, 0.0, 23.0, 15.0};
- NXSize cellSize = {0.0, 0.0};
-
- buttonCell = [[ButtonCell allocFromZone:[self zone]] initTextCell: ""];
- [buttonCell setHighlightsBy: NX_CHANGEGRAY];
- [buttonCell setType: NX_ONOFF];
- [buttonCell setEditable: NO];
- [buttonCell setBordered: NO];
- [buttonCell setFont: font];
-
- dayMatrix = [[Matrix allocFromZone:[self zone]] initFrame:&matrixRect mode:NX_RADIOMODE prototype:buttonCell numRows:6 numCols:7];
-
- for (row = 0; row < 6; row++)
- for (column = 0; column < 7; column++)
- [[dayMatrix cellAt:row :column] setTag: cellTag++];
-
- [dayMatrix setIntercell:&cellSize];
- [dayMatrix setCellSize:&cellRect.size];
- [dayMatrix sizeToCells];
- [dayMatrix setAutodisplay:YES];
- [[dayMatrix setTarget: self] setAction: @selector (_daySelected:)];
- [dayMatrix setEmptySelectionEnabled: YES];
- [self addSubview: dayMatrix];
- return self;
- }
-
-
- - _initWithSystemDate
- {
- struct timeval greenwich;
- struct tm* today;
-
- gettimeofday (&greenwich, NULL);
- today = (localtime (&(greenwich.tv_sec)));
- day = today->tm_mday;
- month = 1 + today->tm_mon;
- year = 1900 + today->tm_year;
- return self;
- }
-
-
- - (int) _lastDayOfMonth
- {
- if (month == 0) [self _initWithSystemDate];
- if (month == 2) LAST_DAY_OF_MONTH[1] = (year % 4 ? 28 : 29);
- return LAST_DAY_OF_MONTH [month - 1];
- }
-
-
- - (int) _firstWeekdayOfMonth
- {
- int theMonth = month;
- int theYear = year;
- int weekDay;
- int offset;
- long julian;
-
- if (theMonth <= 2) { theYear--; theMonth += 12; }
-
- offset = 0;
- if ((theYear * 10000.0) + (theMonth * 100.0) + 1 >= 15821015.0)
- offset = (2 - (theYear / 100)) + ((theYear / 100) / 4);
-
- julian = (365.25 * theYear);
- julian += (long) (30.6001 * (theMonth +1));
- julian += (long) 1;
- julian += 1720994L;
- julian += (long) offset;
-
- weekDay = (int) ((julian + 2) % 7);
- return (weekDay < 0 || weekDay > 6 ? 0 : weekDay);
- }
-
-
- - _highlightCurrentDay
- {
- // Called by _updateCalendar and day: methods to select current day.
-
- int firstWeekday;
- id selectedCell;
-
- [dayMatrix selectCellAt: -1 :-1];
- if (day == 0) return self;
-
- firstWeekday = [self _firstWeekdayOfMonth];
- selectedCell = [dayMatrix findCellWithTag: day + firstWeekday - 1];
-
- if ([selectedCell title])
- if (strcmp ([selectedCell title], ""))
- [dayMatrix selectCellWithTag: day + firstWeekday - 1];
-
- return self;
- }
-
-
- - _sendActionToTarget
- {
- if ([self target] && [self isEnabled])
- if ([[self target] respondsTo: [self action]])
- [[self target] perform:[self action] with:self];
-
- return self;
- }
-
-
- - _daySelected: sender
- {
- // Private action method for dayMatrix. Send user's action to target.
-
- day = ([sender selectedCell] ? atoi ([[sender selectedCell] title]) : 0);
- [self _sendActionToTarget];
- return self;
- }
-
-
- - _updateCalendar
- {
- // Handles display update of subviews.
-
- int date;
- int cellTag;
- int firstWeekday = [self _firstWeekdayOfMonth];
- int lastDayOfMonth = [self _lastDayOfMonth];
- char dateString[3];
-
- [[dayMatrix window] disableDisplay];
-
- for (cellTag = 0; cellTag < firstWeekday; cellTag++)
- [[[dayMatrix findCellWithTag: cellTag] setTitle: ""] setEnabled: NO];
-
- for (cellTag = lastDayOfMonth; cellTag < [dayMatrix cellCount]; cellTag++)
- [[[dayMatrix findCellWithTag: cellTag] setTitle: ""] setEnabled: NO];
-
- for (cellTag = firstWeekday, date = 1; date <= lastDayOfMonth; cellTag++, date++)
- {
- sprintf (dateString, "%d", date);
- [[[dayMatrix findCellWithTag: cellTag] setTitle: dateString] setEnabled: isEnabled];
- }
-
- [self _highlightCurrentDay];
- [monthTextField setStringValue: MONTHS [month - 1]];
- [yearTextField setIntValue: year];
-
- [[dayMatrix window] reenableDisplay];
- [self display];
- return self;
- }
-
-
- - _nextText: sender
- {
- // Called by 'takeFrom' methods to assist UI flow.
-
- if ([sender isKindOf: [TextField class]])
- if ([[sender nextText] respondsTo: @selector(selectText:)])
- [[sender nextText] selectText:nil];
-
- return self;
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Initializing and Freeing
- //----------------------------------------------------------------------------------------------------
- - initFrame: (const NXRect*) frameRect
- {
- // Init and display current date. Create an ActionCell instance to
- // hold our target/action values. Enable day selection.
-
- [super initFrame: frameRect];
- [self setCell: [[ActionCell allocFromZone:[self zone]] init]];
- [self setEnabled: YES];
- [self _initMonthTextField];
- [self _initYearTextField];
- [self _initWeekdayTextField];
- [self _initDayMatrix];
- [self _initWithSystemDate];
- [self _updateCalendar];
- return self;
- }
-
-
- - free
- {
- if (dayMatrix) [dayMatrix free];
- if (monthTextField) [monthTextField free];
- if (yearTextField) [yearTextField free];
- if (weekdayTextField) [weekdayTextField free];
- return [super free];
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Accessors
- //----------------------------------------------------------------------------------------------------
- - month: (int) aMonth
- {
- month = (aMonth < 1 || aMonth > 12 ? 1 : aMonth);
- [self _updateCalendar];
- return self;
- }
-
-
- - day: (int) aDay
- {
- day = (aDay < 1 || aDay > [self _lastDayOfMonth] ? 0 : aDay);
- [self _highlightCurrentDay];
- return self;
- }
-
-
- - year: (int) aYear
- {
- year = (aYear < 1 || aYear > 9999 ? 1 : aYear);
- [self _updateCalendar];
- return self;
- }
-
-
- - (const char*) monthStringValue
- {
- return [monthTextField stringValue];
- }
-
-
- - (const char*) dayStringValue
- {
- return ([[dayMatrix selectedCell] title]);
- }
-
-
- - (const char*) yearStringValue
- {
- return [yearTextField stringValue];
- }
-
-
- - (const char*) dayOfWeekStringValue
- {
- return DAYS [([[dayMatrix selectedCell] tag] % 7)];
- }
-
-
- - (const char*) dateStringValue
- {
- if (day)
- sprintf (dateString, "%s %d, %.4d", [self monthStringValue], day, [self yearIntValue]);
- else
- sprintf (dateString, "%s %.4d", [self monthStringValue], [self yearIntValue]);
-
- return dateString;
- }
-
-
- - (int) monthIntValue
- {
- return month;
- }
-
-
- - (int) dayIntValue
- {
- return day;
- }
-
-
- - (int) yearIntValue
- {
- return year;
- }
-
-
- - (int) dayOfWeekIntValue
- {
- return ([[dayMatrix selectedCell] tag] % 7);
- }
-
-
- - (const char*) stringValue
- {
- return [self dateStringValue];
- }
-
-
- - (int) intValue
- {
- return day;
- }
-
-
- - (float) floatValue
- {
- return (float) day;
- }
-
-
- - (double) doubleValue
- {
- return (double) day;
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Enabling Day Selection
- //----------------------------------------------------------------------------------------------------
- - setEnabled: (BOOL) aFlag
- {
- // Set enabling of day selection to aFlag and redisplay calendar (this will
- // force update of dayMatrix buttonCells which are what actually gets
- // enabled or disabled). Since the subview dayMatrix handles the mouse
- // events we're interested in, we (the superview) will always remain disabled.
-
- isEnabled = aFlag;
- [self _updateCalendar];
- [super setEnabled: NO];
- return self;
- }
-
-
- - (BOOL) isEnabled
- {
- return isEnabled;
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Action Methods
- //----------------------------------------------------------------------------------------------------
- - incrementMonth: sender
- {
- if (++month > 12) month = 1;
- [self _updateCalendar];
- return self;
- }
-
-
- - decrementMonth: sender
- {
- if (--month < 1) month = 12;
- [self _updateCalendar];
- return self;
- }
-
-
- - incrementYear: sender
- {
- if (++year > 9999) year = 1;
- [self _updateCalendar];
- return self;
- }
-
-
- - decrementYear: sender
- {
- if (--year < 1) year = 9999;
- [self _updateCalendar];
- return self;
- }
-
-
- - takeMonthIntValueFrom: sender
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (intValue)]) [self month: [sender intValue]];
- [self _nextText: sender];
- return self;
- }
-
-
- - takeDayIntValueFrom: sender
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (intValue)]) [self day: [sender intValue]];
- [self _nextText: sender];
- return self;
- }
-
-
- - takeYearIntValueFrom: sender
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (intValue)]) [self year: [sender intValue]];
- [self _nextText: sender];
- return self;
- }
-
-
- - showSystemDate: sender
- {
- [self _initWithSystemDate];
- [self _updateCalendar];
- return self;
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Archiving
- //----------------------------------------------------------------------------------------------------
- - read: (NXTypedStream*) stream
- {
- [super read: stream];
- NXReadTypes (stream, "iii@@@c",
- &month, &day, &year, &monthTextField, &dayMatrix, &yearTextField, &isEnabled);
- return self;
- }
-
-
- - write: (NXTypedStream*) stream
- {
- [super write: stream];
- NXWriteTypes (stream, "iii@@@c",
- &month, &day, &year, &monthTextField, &dayMatrix, &yearTextField, &isEnabled);
- return self;
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // IB Methods
- //----------------------------------------------------------------------------------------------------
- - (const char*) getInspectorClassName
- {
- // Returns the name of the class responsible for managing custom
- // IB Attributes inspection.
-
- return "CalendarInspector";
- }
-
-
- - getMinSize:(NXSize *)minSize maxSize:(NXSize *)maxSize from:(int)where
- {
- // Constrains resize within IB.
-
- minSize->width = maxSize->width = 175.0;
- minSize->height = maxSize->height = 137.0;
- return self;
- }
-
-
- @end