home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-12-08 | 40.0 KB | 1,812 lines |
- //----------------------------------------------------------------------------------------------------
- //
- // Clock
- //
- // Inherits From: Control
- //
- // Declared In: Clock.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 "Clock.h"
-
-
- static const char* ClockPboardType = "ClockPboardType";
-
- #define TIMER_RELATIVE 0x0 // compute relative time values.
- #define TIMER_REALTIME 0x1 // stay synced with system time.
-
- #define DISPLAY_CLOCK 0x0 // display clock time
- #define DISPLAY_ALARM 0x1 // display alarm time
- #define DISPLAY_OTHER 0x2 // display user specified time
-
- #define ALARM_STOPWATCH 0x0 // execute after fixed time
- #define ALARM_TIME 0x1 // match on time
- #define ALARM_TIMEDATE 0x2 // match on time and date
- #define ALARM_TIMEWEEKDAY 0x4 // match on time and weekday
-
- #define AWAKE_STOPPED 0x0 // no timed entry on awake
- #define AWAKE_RUNNING 0x1 // add timed entry on awake
- #define AWAKE_PREVENT 0x2 // should but don't (for pboard)
-
-
- @implementation Clock
-
- //----------------------------------------------------------------------------------------------------
- // Private Methods
- //----------------------------------------------------------------------------------------------------
- - (int) _timerMode
- {
- return privateFlags.timerMode;
- }
-
-
- - (int) _alarmMode
- {
- return privateFlags.alarmMode;
- }
-
-
- - (int) _displayMode
- {
- return privateFlags.displayMode;
- }
-
-
- - (BOOL) _backgroundIsColor
- {
- return privateFlags.backgroundIsColor;
- }
-
-
- - _backgroundIsColor: (BOOL)aFlag
- {
- privateFlags.backgroundIsColor = aFlag;
- [self update];
- return self;
- }
-
-
- - _alarmMode: (int) aMode
- {
- privateFlags.alarmMode = aMode;
- return self;
- }
-
-
- - _timerMode: (int) aMode
- {
- privateFlags.timerMode = aMode;
- return self;
- }
-
-
- - (int) _previousClock
- {
- return previousClock;
- }
-
-
- - (struct tm*) _systemTime
- {
- struct timeval greenwich;
- struct tm* currentTime;
-
- gettimeofday (&greenwich, NULL);
- currentTime = (localtime (&(greenwich.tv_sec)));
- return currentTime;
- }
-
-
- - (int) _lastDayOfMonth: (struct tm*) aTime
- {
- int lastDayOfMonth[] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-
- if (MONTH (aTime) == 1) lastDayOfMonth[1] = (YEAR (aTime) % 4 ? 28 : 29);
- return lastDayOfMonth[MONTH (aTime)];
- }
-
-
- - _addDayToClockTime
- {
- // Increment current clockTimeAndDate by one day.
-
- ++DAY(&clockTimeAndDate);
-
- if (DAY(&clockTimeAndDate) > [self _lastDayOfMonth:&clockTimeAndDate])
- {
- DAY(&clockTimeAndDate) = 1;
- if (++MONTH (&clockTimeAndDate) > 11)
- {
- MONTH (&clockTimeAndDate) = 0;
- YEAR (&clockTimeAndDate) =
- (++YEAR (&clockTimeAndDate) > 1999 ? 0 : YEAR (&clockTimeAndDate));
- }
- }
-
- WEEKDAY(&clockTimeAndDate) = [self weekDay: &clockTimeAndDate];
- return self;
- }
-
-
- - (struct tm*) _computeClockTimeRelativeTo: (struct tm*) aTime
- {
- // User has manually set time, now increment based on system clock delta.
- // (i.e. if it changed by 2 seconds, increment user time by 2 seconds.)
-
- int newClock;
-
- previousClock = (privateFlags.initRelativeTimerMode ? SECONDS (aTime) : previousClock);
- newClock = SECONDS (&clockTimeAndDate) + (SECONDS (aTime) - previousClock);
- previousClock = SECONDS (aTime);
- privateFlags.initRelativeTimerMode = NO;
-
- HOUR (&clockTimeAndDate) = newClock / 3600;
- if (HOUR (&clockTimeAndDate) == 24)
- {
- HOUR (&clockTimeAndDate) = 0;
- [self _addDayToClockTime];
- }
- MINUTE (&clockTimeAndDate) = (newClock % 3600) / 60;
- SECOND (&clockTimeAndDate) = ((newClock % 3600) % 60);
-
- return &clockTimeAndDate;
- }
-
-
- - _updateClockTime
- {
- // Update the clock time as appropriate (REALTIME stays synced with system
- // clock, RELATIVE computes based on system clock delta).
-
- if (privateFlags.timerMode == TIMER_REALTIME)
- [self clockTimeAndDate: [self _systemTime]];
- else
- [self _computeClockTimeRelativeTo: [self _systemTime]];
-
- return self;
- }
-
-
- - _checkAlarm
- {
- // Check for match of current Clock time and Alarm time. Seconds will be checked
- // within some tolerance (current time + tolerance) in case timed entry was delayed.
- // Check date or day of week if appropriate.
-
- int alarmSeconds = SECONDS (&alarmTimeAndDate);
- int clockSeconds = SECONDS (&clockTimeAndDate);
-
- if (clockSeconds < alarmSeconds || clockSeconds - 10 > alarmSeconds)
- {
- privateFlags.alarmSleep = NO;
- return self;
- }
-
- if (privateFlags.alarmSleep) return self;
- privateFlags.alarmSleep = YES;
-
- if (privateFlags.alarmMode == ALARM_TIMEDATE)
- {
- if (DAY(&alarmTimeAndDate) != DAY(&clockTimeAndDate)) return self;
- if (MONTH(&alarmTimeAndDate) != MONTH(&clockTimeAndDate)) return self;
- if (YEAR(&alarmTimeAndDate) != YEAR(&clockTimeAndDate)) return self;
- }
- else if (privateFlags.alarmMode == ALARM_TIMEWEEKDAY)
- if (WEEKDAY(&alarmTimeAndDate) != WEEKDAY(&clockTimeAndDate)) return self;
-
- [self executeAlarmAction: nil];
- return self;
- }
-
-
- void Tick (timedEntry, now, self)
- DPSTimedEntry timedEntry;
- double now;
- void* self;
- {
- // Callback function for DPS timed entry.
-
- struct _clock{ @defs (Clock) } *clock = (struct _clock*) self;
- [(id)self _updateClockTime];
- if (clock->flags.isAlarmEnabled && clock->privateFlags.alarmMode) [(id)self _checkAlarm];
- if (clock->flags.wantsDisplay && clock->privateFlags.displayMode == DISPLAY_CLOCK)
- {
- clock->displayTimeAndDate = &clock->clockTimeAndDate;
- [(id)self display];
- }
- }
-
-
- - _addTimedEntry
- {
- timedEntry = DPSAddTimedEntry(1.0, Tick, (void*) self, NX_MODALRESPTHRESHOLD);
- flags.activateOnAwake = YES;
- NXPing();
- return self;
- }
-
-
- - _removeTimedEntry
- {
- DPSRemoveTimedEntry (timedEntry);
- timedEntry = 0;
- flags.activateOnAwake = NO;
- return self;
- }
-
-
- - (NXPoint) _compositePointForImage: anImage
- {
- NXSize iconSize;
-
- [anImage getSize: &iconSize];
-
- if ( iconSize.width < NX_WIDTH (&bounds) )
- NX_X (&bounds) += (NX_WIDTH (&bounds) - iconSize.width ) / 2.0;
-
- if ( iconSize.height < NX_HEIGHT (&bounds) )
- NX_Y (&bounds) += (NX_HEIGHT (&bounds) - iconSize.width ) / 2.0;
-
- return bounds.origin;
- }
-
-
- - _nextText: sender
- {
- // This method will allow an action to be sent and nextText to be selected when
- // 'return' is entered. Only works with TextFields and TextField subclasses. Used by // 'takeIntValueFrom' methods.
-
- if ([sender isKindOf: [TextField class]])
- if ([[sender nextText] respondsTo: @selector(selectText:)])
- [[sender nextText] selectText:nil];
-
- return self;
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Initialization and Freeing
- //----------------------------------------------------------------------------------------------------
- - initFrame: (const NXRect *)aRect
- {
- [super initFrame:aRect];
-
- [self setCell: [[ActionCell allocFromZone:[self zone]] init]];
- [self setDisplayEnabled: YES];
- [self wantsMilitaryTime: NO];
- [self wantsSeconds: YES];
- [self wantsDate: YES];
- [self isDraggable: YES];
- [self willAcceptDrop: YES];
- [self enableAlarm: NO];
- [self wantsAlarmIndicator: NO];
- [self backgroundColor: NX_COLORLTGRAY];
- [self clockTimeAndDate: [self _systemTime]];
- [self alarmTimeAndDate: &clockTimeAndDate];
-
- flags.activateOnAwake = AWAKE_STOPPED;
- privateFlags.displayMode = DISPLAY_CLOCK;
- privateFlags.timerMode = TIMER_REALTIME;
- privateFlags.alarmMode = ALARM_TIME;
- displayTimeAndDate = &clockTimeAndDate;
-
- return self;
- }
-
-
- - free
- {
- [self stop:nil];
- if (clockFace) [clockFace free];
- if (backgroundImage) [backgroundImage free];
- if (alarmSound) [alarmSound free];
- return [super free];
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Accessing Display
- //----------------------------------------------------------------------------------------------------
- - backgroundImage: (NXImage*) anImage
- {
- // Background images will be scaled to fit.
-
- if ( (backgroundImage) && (backgroundImage != anImage) ) [backgroundImage free];
- backgroundImage = [anImage copyFromZone: [self zone]];
- privateFlags.backgroundIsColor = NO;
- [backgroundImage setScalable:YES];
- [self update];
- return self;
- }
-
-
- - backgroundColor: (NXColor) aColor
- {
- privateFlags.backgroundIsColor = YES;
- backgroundColor = aColor;
- [self update];
- return self;
- }
-
-
- - clockFace: (NXImage*) anImage
- {
- // ClockFace images will be centered.
-
- if ( (clockFace) && (clockFace != anImage) ) [clockFace free];
- clockFace = [anImage copyFromZone: [self zone]];
- [self update];
- return self;
- }
-
-
- - (NXImage*) backgroundImage
- {
- return backgroundImage;
- }
-
-
- - (NXColor) backgroundColor
- {
- return backgroundColor;
- }
-
-
- - (NXImage*) clockFace
- {
- return clockFace;
- }
-
-
- - setDisplayEnabled: (BOOL) aFlag;
- {
- flags.wantsDisplay = aFlag;
- [self update];
- return self;
- }
-
-
- - wantsMilitaryTime: (BOOL) aFlag
- {
- flags.wantsMilitaryTime = aFlag;
- [self update];
- return self;
- }
-
-
- - wantsDate: (BOOL) aFlag
- {
- flags.wantsDate = aFlag;
- [self update];
- return self;
- }
-
-
- - wantsSeconds: (BOOL) aFlag
- {
- flags.wantsSeconds = aFlag;
- [self update];
- return self;
- }
-
-
- - (BOOL) isDisplayEnabled
- {
- return flags.wantsDisplay;
- }
-
-
- - (BOOL) wantsMilitaryTime
- {
- return flags.wantsMilitaryTime;
- }
-
-
- - (BOOL) wantsDate
- {
- return flags.wantsDate;
- }
-
-
- - (BOOL) wantsSeconds
- {
- return flags.wantsSeconds;
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Accessing Clock Time and Date
- //----------------------------------------------------------------------------------------------------
- - clockTimeAndDate: (struct tm*) theClockTimeAndDate
- {
-
- memcpy (&clockTimeAndDate, theClockTimeAndDate, sizeof (struct tm));
- return self;
- }
-
-
- - clockSecond: (int) theSecond
- {
- if (theSecond < 0) theSecond = 0; else if (theSecond > 59) theSecond = 59;
- SECOND(&clockTimeAndDate) = theSecond;
- return self;
- }
-
-
- - clockMinute: (int) theMinute
- {
- if (theMinute < 0) theMinute = 0; else if (theMinute > 59) theMinute = 59;
- MINUTE(&clockTimeAndDate) = theMinute;
- return self;
- }
-
-
- - clockHour: (int) theHour
- {
- if (theHour < 0) theHour = 0; else if (theHour > 23) theHour = 23;
- HOUR(&clockTimeAndDate) = theHour;
- return self;
- }
-
- - clockDay: (int) theDay
- {
- if (theDay < 1)
- theDay = 1;
- else if (theDay > [self _lastDayOfMonth:&clockTimeAndDate])
- theDay = [self _lastDayOfMonth:&clockTimeAndDate];
-
- DAY(&clockTimeAndDate) = theDay;
- WEEKDAY(&clockTimeAndDate) = [self weekDay: &clockTimeAndDate];
- return self;
- }
-
-
- - clockMonth: (int) theMonth
- {
- if (theMonth < 0) theMonth = 0; else if (theMonth > 11) theMonth = 11;
- MONTH(&clockTimeAndDate) = theMonth;
- WEEKDAY(&clockTimeAndDate) = [self weekDay: &clockTimeAndDate];
- [self clockDay: [self clockDay]];
- return self;
- }
-
-
- - clockYear: (int) theYear
- {
- if (theYear < 0) theYear = 0; else if (theYear > 99) theYear = 99;
- YEAR(&clockTimeAndDate) = theYear;
- WEEKDAY(&clockTimeAndDate) = [self weekDay: &clockTimeAndDate];
- [self clockDay: [self clockDay]];
- return self;
- }
-
-
- - clockWeekday: (int) theWeekday
- {
- if (theWeekday < 0) theWeekday = 0; else if (theWeekday > 6) theWeekday = 6;
- WEEKDAY(&clockTimeAndDate) = theWeekday;
- return self;
- }
-
-
- - (struct tm*) clockTimeAndDate
- {
- return &clockTimeAndDate;
- }
-
-
- - (int) clockSecond
- {
- return SECOND(&clockTimeAndDate);
- }
-
-
- - (int) clockMinute
- {
- return MINUTE(&clockTimeAndDate);
- }
-
-
- - (int) clockHour
- {
- return HOUR(&clockTimeAndDate);
- }
-
-
- - (int) clockDay
- {
- return DAY(&clockTimeAndDate);
- }
-
-
- - (int) clockMonth
- {
- return MONTH(&clockTimeAndDate);
- }
-
-
- - (int) clockYear
- {
- return YEAR(&clockTimeAndDate);
- }
-
-
- - (int) clockWeekday
- {
- return WEEKDAY(&clockTimeAndDate);
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Setting. Enabling And Executing the Alarm
- //----------------------------------------------------------------------------------------------------
- - enableAlarm: (BOOL) aFlag
- {
- // Alarm must be activated (and clock running) before it will execute.
- // Merely setting the alarm will not activate it.
-
- flags.isAlarmEnabled = aFlag;
- privateFlags.alarmSleep = NO;
- return self;
- }
-
-
- - (BOOL) isAlarmEnabled
- {
- return flags.isAlarmEnabled;
- }
-
-
- - wantsAlarmIndicator: (BOOL) aFlag
- {
- // Displays a visible indicater if the alarm is enabled and this flag is YES.
-
- flags.wantsAlarmIndicator = aFlag;
- [self update];
- return self;
- }
-
-
- - (BOOL) wantsAlarmIndicator
- {
- return flags.wantsAlarmIndicator;
- }
-
-
- - setAlarmTime: (struct tm*) theTime
- {
- // Sets alarm time to hour, minute, and second values of theTime. All
- // other values will be ignored. Alarm will execute if a match of the specified
- // time occurs. The setTimeAndDate method is helpful in filling a tm struct.
-
- [self alarmTimeAndDate: theTime];
- [self enableAlarm: YES];
- privateFlags.alarmMode = ALARM_TIME;
- return self;
- }
-
-
- - setAlarmTimeAndDate: (struct tm*) theTimeAndDate;
- {
- // Sets alarm time and date to the hour, minute, second, day, month, and
- // year values of theTimeAndDate. All other values will be ignored.
- // Alarm will execute if a match on the specified time and date
- // occurs. The setTimeAndDate method is helpful in filling a tm struct.
-
- [self alarmTimeAndDate: theTimeAndDate];
- [self enableAlarm: YES];
- privateFlags.alarmMode = ALARM_TIMEDATE;
- return self;
- }
-
-
- - setAlarmTimeAndWeekday: (struct tm*) theTimeAndWeekday;
- {
- // Sets alarm time and weekday to the hour, minute, second, and weekday
- // values of theTimeAndWeekday. All other values will be ignored.
- // Alarm will execute if a match on the specified time and weekday
- // occurs. For example, every Monday at 12:00. The setTimeAndDate
- // method is helpful in filling a tm struct.
-
- [self alarmTimeAndDate: theTimeAndWeekday];
- [self enableAlarm: YES];
- privateFlags.alarmMode = ALARM_TIMEWEEKDAY;
- return self;
- }
-
-
- - executeAlarmAction: sender
- {
- // Called if match on alarm.
-
- if (alarmSound) [alarmSound play];
-
- if ([self target])
- if ([[self target] respondsTo: [self action]])
- [[self target] perform:[self action] with:self];
-
- return self;
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Accessing Alarm Time and Date
- //----------------------------------------------------------------------------------------------------
- - alarmTimeAndDate: (struct tm*) theAlarmTimeAndDate
- {
- memcpy (&alarmTimeAndDate, theAlarmTimeAndDate, sizeof (struct tm));
- return self;
- }
-
-
- - alarmSecond: (int) theSecond
- {
- if (theSecond < 0) theSecond = 0; else if (theSecond > 59) theSecond = 59;
- SECOND(&alarmTimeAndDate) = theSecond;
- return self;
- }
-
-
- - alarmMinute: (int) theMinute
- {
- if (theMinute < 0) theMinute = 0; else if (theMinute > 59) theMinute = 59;
- MINUTE(&alarmTimeAndDate) = theMinute;
- return self;
- }
-
-
- - alarmHour: (int) theHour
- {
- if (theHour < 0) theHour = 0; else if (theHour > 23) theHour = 23;
- HOUR(&alarmTimeAndDate) = theHour;
- return self;
- }
-
- - alarmDay: (int) theDay
- {
- if (theDay < 1)
- theDay = 1;
- else if (theDay > [self _lastDayOfMonth:&alarmTimeAndDate])
- theDay = [self _lastDayOfMonth:&alarmTimeAndDate];
-
- DAY(&alarmTimeAndDate) = theDay;
- WEEKDAY(&alarmTimeAndDate) = [self weekDay: &alarmTimeAndDate];
- return self;
- }
-
-
- - alarmMonth: (int) theMonth
- {
- if (theMonth < 0) theMonth = 0; else if (theMonth > 11) theMonth = 11;
- MONTH(&alarmTimeAndDate) = theMonth;
- WEEKDAY(&alarmTimeAndDate) = [self weekDay: &alarmTimeAndDate];
- [self alarmDay: [self alarmDay]];
- return self;
- }
-
-
- - alarmYear: (int) theYear
- {
- if (theYear < 0) theYear = 0; else if (theYear > 99) theYear = 99;
- YEAR(&alarmTimeAndDate) = theYear;
- WEEKDAY(&alarmTimeAndDate) = [self weekDay: &alarmTimeAndDate];
- [self alarmDay: [self alarmDay]];
- return self;
- }
-
-
- - alarmWeekday: (int) theWeekday
- {
- if (theWeekday < 0) theWeekday = 0; else if (theWeekday > 6) theWeekday = 6;
- WEEKDAY(&alarmTimeAndDate) = theWeekday;
- return self;
- }
-
-
- - (struct tm*) alarmTimeAndDate
- {
- return &alarmTimeAndDate;
- }
-
-
- - (int) alarmSecond
- {
- return SECOND(&alarmTimeAndDate);
- }
-
-
- - (int) alarmMinute
- {
- return MINUTE(&alarmTimeAndDate);
- }
-
-
- - (int) alarmHour
- {
- return HOUR(&alarmTimeAndDate);
- }
-
-
- - (int) alarmDay
- {
- return DAY(&alarmTimeAndDate);
- }
-
-
- - (int) alarmMonth
- {
- return MONTH(&alarmTimeAndDate);
- }
-
-
- - (int) alarmYear
- {
- return YEAR(&alarmTimeAndDate);
- }
-
-
- - (int) alarmWeekday
- {
- return WEEKDAY(&alarmTimeAndDate);
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Accessing Alarm Sound
- //----------------------------------------------------------------------------------------------------
- - alarmSound: aSound
- {
- // Audible notification of alarm match (in addition to action send to target).
-
- if (! alarmSound) alarmSound = [[Sound alloc] init];
- [alarmSound copySound: aSound];
- return self;
- }
-
-
- - alarmSound
- {
- return alarmSound;
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Starting and Stopping the Clock
- //----------------------------------------------------------------------------------------------------
- - startFromSystem: sender
- {
- // Clock starts (and stays synced) with system time.
-
- privateFlags.timerMode = TIMER_REALTIME;
- [self clockTimeAndDate: [self _systemTime]];
- if (! [self isClockRunning]) [self _addTimedEntry];
- return self;
- }
-
-
- - startFromSelf: sender
- {
- // Clock starts from current setting.
-
- privateFlags.timerMode = TIMER_RELATIVE;
- privateFlags.initRelativeTimerMode = YES;
- if (! [self isClockRunning]) [self _addTimedEntry];
- return self;
- }
-
-
- - startFromTime: (struct tm*) theTime
- {
- // Clock sets time and date to theTime and starts timer from this time.
-
- [self clockTimeAndDate: theTime];
- return [self startFromSelf: nil];
- }
-
-
- - stop: sender
- {
- if ([self isClockRunning]) [self _removeTimedEntry];
- return self;
- }
-
-
- - activateOnAwake: (int) aFlag;
- {
- // If YES, timer will begin when unarchived.
-
- flags.activateOnAwake = aFlag;
- return self;
- }
-
-
- - (int) activateOnAwake;
- {
- return flags.activateOnAwake;
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Timer Status
- //----------------------------------------------------------------------------------------------------
- - (BOOL) isClockRunning
- {
- return (timedEntry ? YES : NO);
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Utility Methods
- //----------------------------------------------------------------------------------------------------
- + setTimeAndDate:(struct tm*)time :(int)hour :(int)minute :(int)second :(int)month :(int)day :(int)year;
- {
- // Returns by reference the tm struct time. Struct values are filled with any valid
- // arguments (ranges are checked). Weekday (tm_wday) is calculated based
- // on the date values passed. Other struct members use current system defaults.
-
- if (! time) return self;
- memcpy (time, [self _systemTime], sizeof (struct tm));
- SECOND(time) = (second < 0 || second > 59) ? 0 : second;
- MINUTE(time) = (minute < 0 || minute > 59) ? 0 : minute;
- HOUR(time) = (hour < 0 || hour > 23) ? 0 : hour;
- DAY(time) = (day < 1 || day > 31) ? 1 : day;
- MONTH(time) = (month < 0 || month > 11) ? 0 : month;
- YEAR(time) = (year < 0 || year > 99) ? 0 : year;
- WEEKDAY(time) = [self weekDay: time];
- return self;
- }
-
-
- - setTimeAndDate:(struct tm*)time :(int)hour :(int)minute :(int)second :(int)month :(int)day :(int)year;
- {
- return [Clock setTimeAndDate: time :hour :minute :second :month :day :year];
- }
-
-
- - (int) weekDay: (struct tm*) aTime
- {
- // Determine the day of week based on date info in aTime. Calculated
- // in Julian format, return value 0 - 6, where 0 = Sunday.
-
- int day = DAY (aTime);
- int month = MONTH (aTime) +1;
- int year = YEAR (aTime) + 1900;
- int weekDay;
- int offset;
- long julian;
-
- if (month <= 2) { year--; month += 12;}
- offset = (2 - (year / 100)) + ((year / 100) / 4);
- julian = (365.25 * year);
- julian += (long) (30.6001 * (month +1));
- julian += (long) day;
- julian += 1720994L;
- julian += (long) offset;
-
- weekDay = (int) ((julian + 2) % 7);
- return (weekDay < 0 || weekDay > 6 ? 0 : weekDay);
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Display Methods
- //----------------------------------------------------------------------------------------------------
- - showClockTime: sender
- {
- // Shows current time and date setting. Will not disturb current timer.
-
- displayTimeAndDate = &clockTimeAndDate;
- privateFlags.displayMode = DISPLAY_OTHER;
- [self update];
- return self;
- }
-
-
- - showSystemTime: sender
- {
- // Displays system time. Will not disturb current timer.
-
- displayTimeAndDate = [self _systemTime];
- privateFlags.displayMode = DISPLAY_OTHER;
- [self update];
- return self;
- }
-
-
- - showAlarmTime: sender
- {
- // Displays current alarm time and date. Will not disturb current timer.
-
- displayTimeAndDate = &alarmTimeAndDate;
- privateFlags.displayMode = DISPLAY_ALARM;
- [self update];
- return self;
- }
-
-
- - showTime: (struct tm*) aTime
- {
- // Displays system time. Will not disturb current timer.
-
- displayTimeAndDate = aTime;
- privateFlags.displayMode = DISPLAY_OTHER;
- [self update];
- return self;
- }
-
-
- - resumeClockDisplay: sender
- {
- // Invoke this to resume display of current clock time.
-
- displayTimeAndDate = &clockTimeAndDate;
- privateFlags.displayMode = DISPLAY_CLOCK;
- [self update];
- return self;
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // IB Action Methods
- //----------------------------------------------------------------------------------------------------
- - takeDisplayEnabledFlagFrom: sender;
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (state)]) [self setDisplayEnabled: [sender state]];
- return self;
- }
-
-
- - takeWantsSecondsFlagFrom: sender
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (state)]) [self wantsSeconds: [sender state]];
- return self;
- }
-
-
- - takeWantsDateFlagFrom: sender;
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (state)]) [self wantsDate: [sender state]];
- return self;
- }
-
-
- - takeWantsMilitaryTimeFlagFrom: sender;
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (state)]) [self wantsMilitaryTime: [sender state]];
- return self;
- }
-
-
- - takeIsDraggableFlagFrom: sender;
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (state)]) [self isDraggable: [sender state]];
- return self;
- }
-
-
- - takeWillAcceptDropFlagFrom: sender;
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (state)]) [self willAcceptDrop: [sender state]];
- return self;
- }
-
-
- - takeEnableAlarmFlagFrom: sender
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (state)]) [self enableAlarm: [sender state]];
- return self;
- }
-
-
- - takeWantsAlarmIndicatorFlagFrom: sender
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (state)]) [self wantsAlarmIndicator: [sender state]];
- return self;
- }
-
-
- - takeBackgroundColorFrom: sender
- {
- if ([sender respondsTo: @selector (color)]) [self backgroundColor: [sender color]];
- return self;
- }
-
-
- - takeClockSecondIntValueFrom: sender
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (intValue)]) [self clockSecond: [sender intValue]];
- [[self _nextText: sender] update];
- return self;
- }
-
-
- - takeClockMinuteIntValueFrom: sender
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (intValue)]) [self clockMinute: [sender intValue]];
- [[self _nextText: sender] update];
- return self;
- }
-
-
- - takeClockHourIntValueFrom: sender
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (intValue)]) [self clockHour: [sender intValue]];
- [[self _nextText: sender] update];
- return self;
- }
-
-
- - takeClockDayIntValueFrom: sender
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (intValue)]) [self clockDay: [sender intValue]];
- [[self _nextText: sender] update];
- return self;
- }
-
-
- - takeClockMonthIntValueFrom: sender
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (intValue)]) [self clockMonth: [sender intValue]];
- [[self _nextText: sender] update];
- return self;
- }
-
-
- - takeClockYearIntValueFrom: sender
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (intValue)]) [self clockYear: [sender intValue]];
- [[self _nextText: sender] update];
- return self;
- }
-
-
- - takeClockWeekdayIntValueFrom: sender
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (intValue)]) [self clockWeekday: [sender intValue]];
- [[self _nextText: sender] update];
- return self;
- }
-
-
- - takeAlarmSecondIntValueFrom: sender
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (intValue)]) [self alarmSecond: [sender intValue]];
- [[self _nextText: sender] update];
- return self;
- }
-
-
- - takeAlarmMinuteIntValueFrom: sender
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (intValue)]) [self alarmMinute: [sender intValue]];
- [[self _nextText: sender] update];
- return self;
- }
-
-
- - takeAlarmHourIntValueFrom: sender
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (intValue)]) [self alarmHour: [sender intValue]];
- [[self _nextText: sender] update];
- return self;
- }
-
-
- - takeAlarmDayIntValueFrom: sender
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (intValue)]) [self alarmDay: [sender intValue]];
- [[self _nextText: sender] update];
- return self;
- }
-
-
- - takeAlarmMonthIntValueFrom: sender
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (intValue)]) [self alarmMonth: [sender intValue]];
- [[self _nextText: sender] update];
- return self;
- }
-
-
- - takeAlarmYearIntValueFrom: sender
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (intValue)]) [self alarmYear: [sender intValue]];
- [[self _nextText: sender] update];
- return self;
- }
-
-
- - takeAlarmWeekdayIntValueFrom: sender
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (intValue)]) [self alarmWeekday: [sender intValue]];
- [[self _nextText: sender] update];
- return self;
- }
-
-
- - takeAlarmModeIntValueFrom: sender
- {
- if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
- if ([sender respondsTo: @selector (tag)]) privateFlags.alarmMode = [sender tag];
- return self;
- }
-
-
- - incrementClockSecond: sender
- {
- [self clockSecond: [self clockSecond] + 1];
- [self showClockTime: nil];
- return self;
- }
-
-
- - incrementClockMinute: sender
- {
- [self clockMinute: [self clockMinute] + 1];
- [self showClockTime: nil];
- return self;
- }
-
-
- - incrementClockHour: sender
- {
- [self clockHour: [self clockHour] + 1];
- [self showClockTime: nil];
- return self;
- }
-
-
- - incrementClockDay: sender
- {
- [self clockDay: [self clockDay] + 1];
- [self showClockTime: nil];
- return self;
- }
-
-
- - incrementClockMonth: sender
- {
- [self clockMonth: [self clockMonth] + 1];
- [self showClockTime: nil];
- return self;
- }
-
-
- - incrementClockYear: sender
- {
- [self clockYear: [self clockYear] + 1];
- [self showClockTime: nil];
- return self;
- }
-
-
- - incrementClockWeekday: sender
- {
- [self clockWeekday: [self clockWeekday] + 1];
- [self showClockTime: nil];
- return self;
- }
-
-
- - decrementClockSecond: sender
- {
- [self clockSecond: [self clockSecond] - 1];
- [self showClockTime: nil];
- return self;
- }
-
-
- - decrementClockMinute: sender
- {
- [self clockMinute: [self clockMinute] - 1];
- [self showClockTime: nil];
- return self;
- }
-
-
- - decrementClockHour: sender
- {
- [self clockHour: [self clockHour] - 1];
- [self showClockTime: nil];
- return self;
- }
-
-
- - decrementClockDay: sender
- {
- [self clockDay: [self clockDay] - 1];
- [self showClockTime: nil];
- return self;
- }
-
-
- - decrementClockMonth: sender
- {
- [self clockMonth: [self clockMonth] - 1];
- [self showClockTime: nil];
- return self;
- }
-
-
- - decrementClockYear: sender
- {
- [self clockYear: [self clockYear] - 1];
- [self showClockTime: nil];
- return self;
- }
-
-
- - decrementClockWeekday: sender
- {
- [self clockWeekday: [self clockWeekday] - 1];
- [self showClockTime: nil];
- return self;
- }
-
-
-
- - incrementAlarmSecond: sender
- {
- [self alarmSecond: [self alarmSecond] + 1];
- [self showAlarmTime: nil];
- return self;
- }
-
-
- - incrementAlarmMinute: sender
- {
- [self alarmMinute: [self alarmMinute] + 1];
- [self showAlarmTime: nil];
- return self;
- }
-
-
- - incrementAlarmHour: sender
- {
- [self alarmHour: [self alarmHour] + 1];
- [self showAlarmTime: nil];
- return self;
- }
-
-
- - incrementAlarmDay: sender
- {
- [self alarmDay: [self alarmDay] + 1];
- [self showAlarmTime: nil];
- return self;
- }
-
-
- - incrementAlarmMonth: sender
- {
- [self alarmMonth: [self alarmMonth] + 1];
- [self showAlarmTime: nil];
- return self;
- }
-
-
- - incrementAlarmYear: sender
- {
- [self alarmYear: [self alarmYear] + 1];
- [self showAlarmTime: nil];
- return self;
- }
-
-
- - incrementAlarmWeekday: sender
- {
- [self alarmWeekday: [self alarmWeekday] + 1];
- [self showAlarmTime: nil];
- return self;
- }
-
-
- - decrementAlarmSecond: sender
- {
- [self alarmSecond: [self alarmSecond] - 1];
- [self showAlarmTime: nil];
- return self;
- }
-
-
- - decrementAlarmMinute: sender
- {
- [self alarmMinute: [self alarmMinute] - 1];
- [self showAlarmTime: nil];
- return self;
- }
-
-
- - decrementAlarmHour: sender
- {
- [self alarmHour: [self alarmHour] - 1];
- [self showAlarmTime: nil];
- return self;
- }
-
-
- - decrementAlarmDay: sender
- {
- [self alarmDay: [self alarmDay] - 1];
- [self showAlarmTime: nil];
- return self;
- }
-
-
- - decrementAlarmMonth: sender
- {
- [self alarmMonth: [self alarmMonth] - 1];
- [self showAlarmTime: nil];
- return self;
- }
-
-
- - decrementAlarmYear: sender
- {
- [self alarmYear: [self alarmYear] - 1];
- [self showAlarmTime: nil];
- return self;
- }
-
-
- - decrementAlarmWeekday: sender
- {
- [self alarmWeekday: [self alarmWeekday] - 1];
- [self showAlarmTime: nil];
- return self;
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Draw Methods
- //----------------------------------------------------------------------------------------------------
- -drawSelf: (const NXRect *)rects :(int)rectCount
- {
- // Manage display as appropriate. Subclasses implement drawing
- // specific to their graphical representation.
-
- if (flags.wantsDisplay)
- {
- [self drawBackground];
- [self drawClockFace];
- [self drawAlarmIndicator];
- [self drawTime];
- [self drawDate];
- }
-
- return self;
- }
-
-
- - drawBackground
- {
- // Fill background with image (scaled) or background color.
- if (privateFlags.backgroundIsColor)
- {
- NXSetColor (backgroundColor);
- NXRectFill (&bounds);
- return self;
- }
-
- [backgroundImage setSize: &bounds.size];
- [backgroundImage composite: NX_SOVER toPoint: &bounds.origin];
-
- return self;
- }
-
-
- - drawClockFace
- {
- // Center clockFace image in bounds rect.
-
- NXPoint compositePoint = [self _compositePointForImage:clockFace];
- [clockFace composite: NX_SOVER toPoint: &compositePoint];
- return self;
- }
-
-
- - drawTime
- {
- return self;
- }
-
-
- - drawDate
- {
- return self;
- }
-
-
- - drawAlarmIndicator
- {
- // Visible indicator that alarm is set and enabled.
-
- if (flags.isAlarmEnabled && flags.wantsAlarmIndicator)
- {
- id font = [Font newFont:"Times-Roman" size:12 style:0 matrix:NX_IDENTITYMATRIX];
- NXSetColor (NX_COLORRED);
- [font set];
- PSmoveto (2.0, 0.0);
- PSshow ("•");
- [font free];
- }
-
- return self;
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Dragging Support
- //----------------------------------------------------------------------------------------------------
- - isDraggable: (BOOL) aFlag
- {
- flags.isDraggable = aFlag;
- return self;
- }
-
-
- - willAcceptDrop: (BOOL) aFlag;
- {
- const char* dragTypes[] = {ClockPboardType, NULL};
-
- flags.willAcceptDrop = aFlag;
-
- if (flags.willAcceptDrop)
- [self registerForDraggedTypes:dragTypes count:1];
- else
- [self unregisterDraggedTypes];
-
- return self;
- }
-
-
- - (BOOL) isDraggable
- {
- return flags.isDraggable;
- }
-
-
- - (BOOL) willAcceptDrop
- {
- return flags.willAcceptDrop;
- }
-
-
- - (BOOL)acceptsFirstMouse
- {
- return flags.isDraggable;
- }
-
-
- - mouseDown: (NXEvent*) theEvent
- {
- // If draggable, initiate drag sequence on mouse-drag...
-
- int originalEventMask;
- NXEvent originalEvent = *theEvent;
- NXEvent nextEvent;
-
- if (! flags.isDraggable) return self;
-
- [NXApp preventWindowOrdering];
-
- originalEventMask = [window addToEventMask: NX_LMOUSEDRAGGEDMASK];
-
- nextEvent = *( [NXApp getNextEvent: (NX_LMOUSEUPMASK |
- NX_LMOUSEDRAGGEDMASK)] );
-
- switch (nextEvent.type)
- {
- case NX_LMOUSEDRAGGED:
- [self beginDragOperationFor: &originalEvent nextEvent: &nextEvent];
-
- case NX_LMOUSEUP:
- default:
- break;
- }
-
- [window setEventMask: originalEventMask];
- return self;
- }
-
-
- - beginDragOperationFor: (NXEvent*) originalEvent nextEvent: (NXEvent*) nextEvent
- {
- // Begin the drag sequence.
-
- NXPoint startingPoint = { 0.0, 0.0 };
- id dragImage = [self dragImage];
- id pasteboard = [Pasteboard newName: NXDragPboard];
-
- [self writeToPasteboard:pasteboard];
-
- [self dragImage: dragImage
- at: &startingPoint
- offset: &startingPoint
- event: originalEvent
- pasteboard: pasteboard
- source: self
- slideBack: YES];
-
- if (dragImage) [dragImage free];
- if (pasteboard) [pasteboard free];
-
- return self;
- }
-
-
- - (NXImage*) dragImage
- {
- id bitmap;
- id image = [[NXImage alloc] init];
-
- [self lockFocus];
- bitmap = [[NXBitmapImageRep alloc] initData: NULL fromRect: &bounds];
- [self lockFocus];
- [image useRepresentation: bitmap];
- return image;
- }
-
-
- - (BOOL) shouldDelayWindowOrderingForEvent: (NXEvent*) theEvent
- {
- // This allows you to drag a partially obscure object without making
- // the source window become main, and without making the source
- // application the current app.
-
- return YES;
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Dragging Source Protocol
- //----------------------------------------------------------------------------------------------------
- - (NXDragOperation) draggingSourceOperationMaskForLocal: (BOOL)aFlag;
- {
- return NX_DragOperationAll;
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Dragging Destination Protocol
- //----------------------------------------------------------------------------------------------------
- - (NXDragOperation)draggingEntered:dragSource
- {
- return [self draggingUpdated:dragSource];
- }
-
-
- - (NXDragOperation)draggingUpdated:dragSource
- {
- if ([dragSource draggingSource] == self) return NX_DragOperationNone;
-
- switch ([dragSource draggingSourceOperationMask])
- {
- case NX_DragOperationCopy:
- return NX_DragOperationCopy;
- case NX_DragOperationLink:
- return NX_DragOperationLink;
- case NX_DragOperationGeneric:
- case NX_DragOperationAll:
- default:
- return NX_DragOperationGeneric;
- }
- }
-
-
- - (BOOL)prepareForDragOperation:dragSource
- {
- return YES;
- }
-
-
- - (BOOL)performDragOperation:dragSource
- {
- id pasteboardClock = [self readFromPasteboard: [dragSource draggingPasteboard]];
-
- switch ([dragSource draggingSourceOperationMask])
- {
- case NX_DragOperationCopy:
- [self dragOperationCopy: pasteboardClock];
- break;
- case NX_DragOperationLink:
- [self dragOperationLink: pasteboardClock];
- break;
- case NX_DragOperationGeneric:
- case NX_DragOperationAll:
- default:
- [self dragOperationGeneric: pasteboardClock];
- break;
- }
-
- [pasteboardClock free];
- return YES;
- }
-
-
- - concludeDragOperation:dragSource
- {
- return self;
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Clock Drag Operations
- //----------------------------------------------------------------------------------------------------
- - dragOperationCopy: pasteboardClock
- {
- // User is holding Alternate key down while dropping, copy
- // only Alarm information.
-
- [self alarmTimeAndDate: [pasteboardClock alarmTimeAndDate]];
- [self enableAlarm: [pasteboardClock isAlarmEnabled]];
- [self wantsAlarmIndicator: [pasteboardClock wantsAlarmIndicator]];
- privateFlags.alarmMode = [pasteboardClock _alarmMode];
- privateFlags.alarmSleep = NO;
- [self update];
- return self;
- }
-
-
- - dragOperationLink: pasteboardClock
- {
- // User is holding the Control key down while dropping, copy
- // only Clock information.
-
- [self clockTimeAndDate: [pasteboardClock clockTimeAndDate]];
-
- if ([pasteboardClock activateOnAwake])
- if ([pasteboardClock _timerMode] == TIMER_REALTIME)
- [self startFromSystem: nil];
- else
- {
- [self startFromSelf: nil];
- privateFlags.initRelativeTimerMode = NO;
- previousClock = [pasteboardClock _previousClock];
- }
- else
- [self stop: nil];
-
- [self update];
- return self;
- }
-
-
- - dragOperationGeneric: pasteboardClock
- {
- // User is holding Command (or no) key down while dropping, copy
- // both Clock and Alarm information.
-
- [self dragOperationCopy: pasteboardClock];
- [self dragOperationLink: pasteboardClock];
- [self update];
- return self;
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Pasteboard Methods
- //----------------------------------------------------------------------------------------------------
- - writeToPasteboard: aPasteboard
- {
- // Only tricky thing here is to make sure the pasteboard object will not
- // begin a timed entry in the awake method when it is readFromPasteboard.
-
- int length;
- int maxLength;
- char* data;
- NXStream* aStream = NXOpenMemory (NULL, 0, NX_WRITEONLY);
- NXTypedStream* aTypedStream = NXOpenTypedStream (aStream, NX_WRITEONLY);
-
- if ([self isClockRunning]) flags.activateOnAwake = AWAKE_PREVENT;
-
- NXWriteRootObject (aTypedStream, self);
- NXGetMemoryBuffer(aStream, &data, &length, &maxLength);
- [aPasteboard declareTypes: &ClockPboardType num:1 owner: self];
- [aPasteboard writeType:ClockPboardType data:data length:length];
-
- flags.activateOnAwake = [self isClockRunning];
-
- NXCloseTypedStream (aTypedStream);
- NXClose (aStream);
- return self;
- }
-
-
- - readFromPasteboard: aPasteboard
- {
- NXStream* aStream = [aPasteboard readTypeToStream:ClockPboardType];
- NXTypedStream* aTypedStream = NXOpenTypedStream (aStream, NX_READONLY);
-
- id pasteboardClock = NXReadObject (aTypedStream);
-
- NXCloseTypedStream (aTypedStream);
- NXClose (aStream);
- return pasteboardClock;
- }
-
-
- //----------------------------------------------------------------------------------------------------
- // Archiving Methods
- //----------------------------------------------------------------------------------------------------
- - read: (NXTypedStream*) stream
- {
- [super read: stream];
- NXReadType (stream, "{iiiiiii}", &clockTimeAndDate);
- NXReadType (stream, "{iiiiiii}", &alarmTimeAndDate);
- NXReadType (stream, "s", (short*)&flags);
- NXReadType (stream, "s", (short*)&privateFlags);
- backgroundColor = NXReadColor (stream);
- NXReadType (stream, "@", &backgroundImage);
- NXReadType (stream, "@", &clockFace);
- NXReadType (stream, "@", &alarmSound);
- NXReadType (stream, "i", &previousClock);
- return self;
- }
-
-
- - write: (NXTypedStream*) stream
- {
- [super write: stream];
- NXWriteType (stream, "{iiiiiii}", &clockTimeAndDate);
- NXWriteType (stream, "{iiiiiii}", &alarmTimeAndDate);
- NXWriteType (stream, "s", (short*)&flags);
- NXWriteType (stream, "s", (short*)&privateFlags);
- NXWriteColor (stream, backgroundColor);
- NXWriteType (stream, "@", &backgroundImage);
- NXWriteType (stream, "@", &clockFace);
- NXWriteType (stream, "@", &alarmSound);
- NXWriteType (stream, "i", &previousClock);
- return self;
- }
-
-
- - awake
- {
- // Clock awakes displaying clock time and starts timer if appropriate.
-
- [self willAcceptDrop: flags.willAcceptDrop];
-
- privateFlags.displayMode = DISPLAY_CLOCK;
- displayTimeAndDate = &clockTimeAndDate;
-
- if (flags.activateOnAwake != AWAKE_RUNNING) return self;
-
- if (privateFlags.timerMode == TIMER_REALTIME)
- [self startFromSystem: nil];
- else
- [self startFromSelf: nil];
-
- return self;
- }
-
-
- @end