home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula
/
nebula.bin
/
SourceCode
/
Palettes
/
Clocks
/
Clock.m
< prev
next >
Wrap
Text File
|
1992-12-09
|
41KB
|
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