home *** CD-ROM | disk | FTP | other *** search
/ Nebula / nebula.bin / SourceCode / Palettes / Clocks / Clock.m < prev    next >
Text File  |  1992-12-09  |  41KB  |  1,812 lines

  1. //----------------------------------------------------------------------------------------------------
  2. //
  3. //    Clock
  4. //
  5. //    Inherits From:        Control
  6. //
  7. //    Declared In:        Clock.h
  8. //
  9. //    Disclaimer
  10. //
  11. //        You may freely copy, distribute and reuse this software and its
  12. //        associated documentation. I disclaim any warranty of any kind, 
  13. //        expressed or implied, as to its fitness for any particular use.
  14. //
  15. //----------------------------------------------------------------------------------------------------
  16. #import "Clock.h"
  17.  
  18.  
  19. static const char*  ClockPboardType = "ClockPboardType";
  20.  
  21. #define    TIMER_RELATIVE            0x0        //  compute relative time values.
  22. #define    TIMER_REALTIME        0x1        //  stay synced with system time.
  23.  
  24. #define    DISPLAY_CLOCK            0x0        //  display clock time
  25. #define    DISPLAY_ALARM            0x1        //  display alarm time
  26. #define    DISPLAY_OTHER            0x2        //  display user specified time
  27.  
  28. #define    ALARM_STOPWATCH        0x0        //  execute after fixed time
  29. #define    ALARM_TIME            0x1        //  match on time
  30. #define    ALARM_TIMEDATE        0x2        //  match on time and date
  31. #define    ALARM_TIMEWEEKDAY    0x4        //  match on time and weekday
  32.  
  33. #define    AWAKE_STOPPED        0x0        //  no timed entry on awake
  34. #define    AWAKE_RUNNING        0x1        //  add timed entry on awake
  35. #define    AWAKE_PREVENT        0x2        //  should but don't (for pboard)
  36.  
  37.  
  38. @implementation Clock
  39.  
  40. //----------------------------------------------------------------------------------------------------
  41. //    Private Methods
  42. //----------------------------------------------------------------------------------------------------
  43. - (int) _timerMode
  44. {
  45.     return privateFlags.timerMode;
  46. }
  47.  
  48.  
  49. - (int) _alarmMode
  50. {
  51.     return privateFlags.alarmMode;
  52. }
  53.  
  54.  
  55. - (int) _displayMode
  56. {
  57.     return privateFlags.displayMode;
  58. }
  59.  
  60.  
  61. - (BOOL) _backgroundIsColor
  62. {
  63.     return privateFlags.backgroundIsColor;
  64. }
  65.  
  66.  
  67. - _backgroundIsColor: (BOOL)aFlag
  68. {
  69.     privateFlags.backgroundIsColor = aFlag;
  70.     [self update];
  71.     return self;
  72. }
  73.  
  74.  
  75. - _alarmMode: (int) aMode
  76. {
  77.     privateFlags.alarmMode = aMode;
  78.     return self;
  79. }
  80.  
  81.  
  82. - _timerMode: (int) aMode
  83. {
  84.     privateFlags.timerMode = aMode;
  85.     return self;
  86. }
  87.  
  88.  
  89. - (int) _previousClock
  90. {
  91.     return previousClock;
  92. }
  93.  
  94.  
  95. - (struct tm*) _systemTime
  96. {
  97.         struct  timeval greenwich;
  98.     struct  tm*    currentTime;
  99.         
  100.         gettimeofday (&greenwich, NULL);
  101.         currentTime = (localtime (&(greenwich.tv_sec)));
  102.     return currentTime;
  103. }
  104.  
  105.  
  106. - (int) _lastDayOfMonth: (struct tm*) aTime
  107. {
  108.     int    lastDayOfMonth[] = { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  109.     
  110.     if (MONTH (aTime) == 1) lastDayOfMonth[1] = (YEAR (aTime) % 4 ? 28 : 29);
  111.     return lastDayOfMonth[MONTH (aTime)];
  112. }
  113.  
  114.  
  115. - _addDayToClockTime
  116. {
  117.     //  Increment current clockTimeAndDate by one day.
  118.     
  119.     ++DAY(&clockTimeAndDate);
  120.     
  121.     if (DAY(&clockTimeAndDate) >  [self _lastDayOfMonth:&clockTimeAndDate])
  122.         {
  123.         DAY(&clockTimeAndDate) = 1;
  124.         if (++MONTH (&clockTimeAndDate) > 11)
  125.             {
  126.             MONTH (&clockTimeAndDate) = 0;
  127.             YEAR (&clockTimeAndDate) =
  128.                  (++YEAR (&clockTimeAndDate) > 1999 ? 0 : YEAR (&clockTimeAndDate));
  129.             }
  130.         }
  131.         
  132.     WEEKDAY(&clockTimeAndDate) = [self weekDay: &clockTimeAndDate];
  133.     return self;
  134. }
  135.     
  136.  
  137. - (struct tm*) _computeClockTimeRelativeTo: (struct tm*) aTime
  138. {
  139.     //  User has manually set time, now increment based on system clock delta.
  140.     //  (i.e. if it changed by 2 seconds, increment user time by 2 seconds.)
  141.     
  142.     int    newClock;
  143.     
  144.     previousClock = (privateFlags.initRelativeTimerMode ? SECONDS (aTime) : previousClock);
  145.     newClock = SECONDS (&clockTimeAndDate) + (SECONDS (aTime) - previousClock);
  146.     previousClock = SECONDS (aTime);
  147.     privateFlags.initRelativeTimerMode = NO;
  148.     
  149.     HOUR (&clockTimeAndDate) = newClock / 3600;
  150.     if (HOUR (&clockTimeAndDate) == 24) 
  151.         {
  152.         HOUR (&clockTimeAndDate) = 0;
  153.         [self _addDayToClockTime];
  154.         }
  155.     MINUTE (&clockTimeAndDate) = (newClock % 3600) / 60;
  156.     SECOND (&clockTimeAndDate) = ((newClock % 3600) % 60);
  157.  
  158.     return &clockTimeAndDate;
  159. }
  160.  
  161.  
  162. - _updateClockTime
  163. {
  164.     //  Update the clock time as appropriate (REALTIME stays synced with system
  165.     //  clock, RELATIVE computes based on system clock delta).
  166.     
  167.     if (privateFlags.timerMode == TIMER_REALTIME)
  168.         [self clockTimeAndDate: [self _systemTime]];
  169.     else
  170.         [self  _computeClockTimeRelativeTo: [self _systemTime]];
  171.  
  172.     return self;
  173. }
  174.  
  175.  
  176. - _checkAlarm
  177. {
  178.     //  Check for match of current Clock time and Alarm time. Seconds will be checked
  179.     //  within some tolerance (current time + tolerance) in case timed entry was delayed.  
  180.     //  Check date or day of week if appropriate.
  181.     
  182.     int    alarmSeconds = SECONDS (&alarmTimeAndDate);
  183.     int    clockSeconds = SECONDS (&clockTimeAndDate);
  184.     
  185.     if (clockSeconds < alarmSeconds || clockSeconds - 10 > alarmSeconds)
  186.         {
  187.         privateFlags.alarmSleep = NO;
  188.         return self;
  189.         }
  190.  
  191.     if (privateFlags.alarmSleep) return self;
  192.     privateFlags.alarmSleep = YES;
  193.  
  194.     if (privateFlags.alarmMode == ALARM_TIMEDATE)
  195.         {
  196.         if (DAY(&alarmTimeAndDate) != DAY(&clockTimeAndDate)) return self;
  197.         if (MONTH(&alarmTimeAndDate) != MONTH(&clockTimeAndDate)) return self;
  198.         if (YEAR(&alarmTimeAndDate) != YEAR(&clockTimeAndDate)) return self;
  199.         }
  200.     else if (privateFlags.alarmMode == ALARM_TIMEWEEKDAY)
  201.         if (WEEKDAY(&alarmTimeAndDate) != WEEKDAY(&clockTimeAndDate)) return self;
  202.  
  203.     [self executeAlarmAction: nil];
  204.     return self;
  205. }
  206.  
  207.  
  208. void Tick (timedEntry, now, self)
  209.     DPSTimedEntry    timedEntry;
  210.     double            now;
  211.     void*            self;
  212. {
  213.     // Callback function for DPS timed entry.
  214.         
  215.     struct  _clock{ @defs (Clock) } *clock = (struct _clock*) self;
  216.     [(id)self _updateClockTime];
  217.     if (clock->flags.isAlarmEnabled && clock->privateFlags.alarmMode) [(id)self _checkAlarm];
  218.     if (clock->flags.wantsDisplay && clock->privateFlags.displayMode == DISPLAY_CLOCK)
  219.         {
  220.         clock->displayTimeAndDate = &clock->clockTimeAndDate;
  221.         [(id)self  display];
  222.         }
  223. }
  224.  
  225.  
  226. - _addTimedEntry
  227. {
  228.         timedEntry = DPSAddTimedEntry(1.0, Tick, (void*) self, NX_MODALRESPTHRESHOLD);
  229.     flags.activateOnAwake = YES;
  230.         NXPing();
  231.         return self;
  232. }
  233.  
  234.  
  235. - _removeTimedEntry
  236. {
  237.     DPSRemoveTimedEntry (timedEntry);
  238.     timedEntry = 0;
  239.     flags.activateOnAwake = NO;
  240.     return self;
  241. }
  242.  
  243.  
  244. - (NXPoint) _compositePointForImage: anImage
  245. {
  246.     NXSize    iconSize;
  247.  
  248.     [anImage getSize: &iconSize];
  249.     
  250.     if  ( iconSize.width < NX_WIDTH (&bounds) ) 
  251.         NX_X (&bounds) += (NX_WIDTH (&bounds) - iconSize.width ) / 2.0;
  252.     
  253.     if  ( iconSize.height < NX_HEIGHT (&bounds) ) 
  254.         NX_Y (&bounds) += (NX_HEIGHT (&bounds) - iconSize.width ) / 2.0;
  255.  
  256.     return bounds.origin;
  257. }
  258.  
  259.  
  260. - _nextText: sender
  261. {
  262.     //  This method will allow an action to be sent and nextText to be selected when 
  263.     //  'return' is entered.  Only works with TextFields and TextField subclasses. Used by     //  'takeIntValueFrom'  methods.
  264.  
  265.     if ([sender isKindOf: [TextField class]]) 
  266.         if ([[sender nextText] respondsTo: @selector(selectText:)])
  267.             [[sender nextText] selectText:nil];
  268.  
  269.     return self;
  270. }
  271.  
  272.  
  273. //----------------------------------------------------------------------------------------------------
  274. //    Initialization and Freeing
  275. //----------------------------------------------------------------------------------------------------
  276. - initFrame: (const NXRect *)aRect
  277. {
  278.     [super initFrame:aRect];
  279.     
  280.     [self setCell: [[ActionCell allocFromZone:[self zone]] init]];
  281.     [self setDisplayEnabled: YES];
  282.     [self wantsMilitaryTime: NO];
  283.     [self wantsSeconds: YES];
  284.     [self wantsDate: YES];
  285.     [self isDraggable: YES];
  286.     [self willAcceptDrop: YES];
  287.     [self enableAlarm: NO];
  288.     [self wantsAlarmIndicator: NO];
  289.     [self backgroundColor: NX_COLORLTGRAY];
  290.     [self clockTimeAndDate: [self _systemTime]];
  291.     [self alarmTimeAndDate: &clockTimeAndDate];
  292.  
  293.     flags.activateOnAwake = AWAKE_STOPPED;
  294.     privateFlags.displayMode = DISPLAY_CLOCK;
  295.     privateFlags.timerMode = TIMER_REALTIME;
  296.     privateFlags.alarmMode = ALARM_TIME;
  297.     displayTimeAndDate = &clockTimeAndDate;
  298.  
  299.     return self;
  300. }
  301.  
  302.  
  303. - free
  304. {
  305.     [self stop:nil];
  306.     if (clockFace) [clockFace free];
  307.     if (backgroundImage) [backgroundImage free];
  308.     if (alarmSound) [alarmSound free];
  309.     return [super free];
  310. }
  311.  
  312.  
  313. //----------------------------------------------------------------------------------------------------
  314. //    Accessing Display
  315. //----------------------------------------------------------------------------------------------------
  316. - backgroundImage: (NXImage*) anImage
  317. {
  318.     //  Background images will be scaled to fit.
  319.     
  320.     if ( (backgroundImage) && (backgroundImage != anImage) ) [backgroundImage free];
  321.     backgroundImage = [anImage copyFromZone: [self zone]];
  322.     privateFlags.backgroundIsColor = NO;
  323.     [backgroundImage setScalable:YES];
  324.     [self update];
  325.     return self;
  326. }
  327.     
  328.     
  329. - backgroundColor: (NXColor) aColor
  330. {
  331.     privateFlags.backgroundIsColor = YES;
  332.     backgroundColor = aColor;
  333.     [self update];
  334.     return self;
  335. }
  336.  
  337.  
  338. - clockFace: (NXImage*) anImage
  339. {
  340.     //  ClockFace images will be centered.
  341.     
  342.     if ( (clockFace) && (clockFace != anImage) ) [clockFace free];
  343.     clockFace = [anImage copyFromZone: [self zone]];
  344.     [self update];
  345.     return self;
  346. }
  347.  
  348.  
  349. - (NXImage*) backgroundImage
  350. {
  351.     return backgroundImage;
  352. }
  353.  
  354.  
  355. - (NXColor) backgroundColor
  356. {
  357.     return backgroundColor;
  358. }
  359.  
  360.  
  361. - (NXImage*) clockFace
  362. {
  363.     return clockFace;
  364. }
  365.  
  366.  
  367. - setDisplayEnabled: (BOOL) aFlag;
  368. {
  369.     flags.wantsDisplay = aFlag;
  370.     [self update];
  371.     return self;
  372. }
  373.  
  374.  
  375. - wantsMilitaryTime: (BOOL) aFlag
  376. {
  377.     flags.wantsMilitaryTime = aFlag;
  378.     [self update];
  379.     return self;
  380. }
  381.  
  382.  
  383. - wantsDate: (BOOL) aFlag
  384. {
  385.     flags.wantsDate = aFlag;
  386.     [self update];
  387.     return self;
  388. }
  389.  
  390.  
  391. - wantsSeconds: (BOOL) aFlag
  392. {
  393.     flags.wantsSeconds = aFlag;
  394.     [self update];
  395.     return self;
  396. }
  397.  
  398.  
  399. - (BOOL) isDisplayEnabled
  400. {
  401.     return flags.wantsDisplay;
  402. }
  403.  
  404.  
  405. - (BOOL) wantsMilitaryTime
  406. {
  407.     return flags.wantsMilitaryTime;
  408. }
  409.  
  410.  
  411. - (BOOL) wantsDate
  412. {
  413.     return flags.wantsDate;
  414. }
  415.  
  416.  
  417. - (BOOL) wantsSeconds
  418. {
  419.     return flags.wantsSeconds;
  420. }
  421.  
  422.  
  423. //----------------------------------------------------------------------------------------------------
  424. //    Accessing Clock Time and Date
  425. //----------------------------------------------------------------------------------------------------
  426. - clockTimeAndDate: (struct tm*) theClockTimeAndDate
  427. {
  428.  
  429.     memcpy (&clockTimeAndDate,  theClockTimeAndDate, sizeof (struct tm));
  430.     return self;
  431. }
  432.  
  433.  
  434. - clockSecond: (int) theSecond
  435. {
  436.     if (theSecond < 0) theSecond = 0; else if (theSecond > 59) theSecond = 59;
  437.     SECOND(&clockTimeAndDate) = theSecond;
  438.     return self;
  439. }
  440.  
  441.  
  442. - clockMinute: (int) theMinute
  443. {
  444.     if (theMinute < 0) theMinute = 0; else if (theMinute > 59) theMinute = 59;
  445.     MINUTE(&clockTimeAndDate) = theMinute;
  446.     return self;
  447. }
  448.  
  449.  
  450. - clockHour: (int) theHour
  451. {
  452.     if (theHour < 0) theHour = 0; else if (theHour > 23) theHour = 23;
  453.     HOUR(&clockTimeAndDate) = theHour;
  454.     return self;
  455. }
  456.  
  457. - clockDay: (int) theDay
  458. {
  459.     if (theDay < 1) 
  460.         theDay = 1; 
  461.     else if (theDay > [self _lastDayOfMonth:&clockTimeAndDate]) 
  462.         theDay =  [self _lastDayOfMonth:&clockTimeAndDate];
  463.  
  464.     DAY(&clockTimeAndDate) = theDay;
  465.     WEEKDAY(&clockTimeAndDate) = [self weekDay: &clockTimeAndDate];
  466.     return self;
  467. }
  468.  
  469.  
  470. - clockMonth: (int) theMonth
  471. {
  472.     if (theMonth < 0) theMonth = 0; else if (theMonth > 11) theMonth = 11;
  473.     MONTH(&clockTimeAndDate) = theMonth;
  474.     WEEKDAY(&clockTimeAndDate) = [self weekDay: &clockTimeAndDate];
  475.     [self clockDay: [self clockDay]];
  476.     return self;
  477. }
  478.  
  479.  
  480. - clockYear: (int) theYear
  481. {
  482.     if (theYear < 0) theYear = 0; else if (theYear > 99) theYear = 99;
  483.     YEAR(&clockTimeAndDate) = theYear;
  484.     WEEKDAY(&clockTimeAndDate) = [self weekDay: &clockTimeAndDate];
  485.     [self clockDay: [self clockDay]];
  486.     return self;
  487. }
  488.  
  489.  
  490. - clockWeekday: (int) theWeekday
  491. {
  492.     if (theWeekday < 0) theWeekday = 0; else if (theWeekday > 6) theWeekday = 6;
  493.     WEEKDAY(&clockTimeAndDate) = theWeekday;
  494.     return self;
  495. }
  496.  
  497.  
  498. - (struct tm*) clockTimeAndDate
  499. {
  500.     return &clockTimeAndDate;
  501. }
  502.  
  503.  
  504. - (int) clockSecond
  505. {
  506.     return SECOND(&clockTimeAndDate);
  507. }
  508.  
  509.  
  510. - (int) clockMinute
  511. {
  512.     return MINUTE(&clockTimeAndDate);
  513. }
  514.  
  515.  
  516. - (int) clockHour
  517. {
  518.     return HOUR(&clockTimeAndDate);
  519. }
  520.  
  521.  
  522. - (int) clockDay
  523. {
  524.     return DAY(&clockTimeAndDate);
  525. }
  526.  
  527.  
  528. - (int) clockMonth
  529. {
  530.     return MONTH(&clockTimeAndDate);
  531. }
  532.  
  533.  
  534. - (int) clockYear
  535. {
  536.     return YEAR(&clockTimeAndDate);
  537. }
  538.  
  539.  
  540. - (int) clockWeekday
  541. {
  542.     return WEEKDAY(&clockTimeAndDate);
  543. }
  544.  
  545.  
  546. //----------------------------------------------------------------------------------------------------
  547. //    Setting. Enabling And Executing the Alarm
  548. //----------------------------------------------------------------------------------------------------
  549. - enableAlarm: (BOOL) aFlag
  550. {
  551.     //  Alarm must be activated (and clock running) before it will execute.  
  552.     //  Merely setting the alarm will not activate it.
  553.     
  554.     flags.isAlarmEnabled = aFlag;
  555.     privateFlags.alarmSleep = NO;
  556.     return self;
  557. }
  558.  
  559.  
  560. - (BOOL) isAlarmEnabled
  561. {
  562.     return flags.isAlarmEnabled;
  563. }
  564.  
  565.  
  566. - wantsAlarmIndicator: (BOOL) aFlag
  567. {
  568.     //  Displays a visible indicater if the alarm is enabled and this flag is YES.
  569.     
  570.     flags.wantsAlarmIndicator = aFlag;
  571.     [self update];
  572.     return self;
  573. }
  574.  
  575.  
  576. - (BOOL) wantsAlarmIndicator
  577. {
  578.     return flags.wantsAlarmIndicator;
  579. }
  580.  
  581.  
  582. - setAlarmTime: (struct tm*) theTime
  583. {
  584.     //  Sets alarm time to hour, minute, and second values of theTime.  All
  585.     //  other values will be ignored.  Alarm will execute if a match of the specified
  586.     //   time occurs. The setTimeAndDate method is helpful in filling a tm struct.
  587.         
  588.     [self alarmTimeAndDate: theTime];
  589.     [self enableAlarm: YES];
  590.     privateFlags.alarmMode = ALARM_TIME;
  591.     return self;
  592. }
  593.  
  594.     
  595. - setAlarmTimeAndDate: (struct tm*) theTimeAndDate;
  596. {
  597.     //  Sets alarm time and date to the hour, minute, second, day, month, and
  598.     //  year values of theTimeAndDate.  All other values will be ignored.  
  599.     //  Alarm will execute if a match on the specified time and date 
  600.     //  occurs. The setTimeAndDate method is helpful in filling a tm struct.
  601.  
  602.     [self alarmTimeAndDate: theTimeAndDate];
  603.     [self enableAlarm: YES];
  604.     privateFlags.alarmMode = ALARM_TIMEDATE;
  605.     return self;
  606. }
  607.  
  608.     
  609. - setAlarmTimeAndWeekday: (struct tm*) theTimeAndWeekday;
  610. {
  611.     //  Sets alarm time and weekday to the hour, minute, second, and weekday
  612.     //  values of theTimeAndWeekday.  All other values will be ignored.  
  613.     //  Alarm will execute if a match on the specified time and weekday 
  614.     //  occurs. For example, every Monday at 12:00. The setTimeAndDate
  615.     //  method is helpful in filling a tm struct.
  616.     
  617.     [self alarmTimeAndDate: theTimeAndWeekday];
  618.     [self enableAlarm: YES];
  619.     privateFlags.alarmMode = ALARM_TIMEWEEKDAY;
  620.     return self;
  621. }
  622.  
  623.  
  624. - executeAlarmAction: sender
  625. {
  626.     //  Called if match on alarm.
  627.     
  628.     if (alarmSound) [alarmSound play];
  629.     
  630.     if ([self target])
  631.         if ([[self target] respondsTo: [self action]])
  632.             [[self target] perform:[self action] with:self];
  633.             
  634.     return self;
  635. }
  636.             
  637.             
  638. //----------------------------------------------------------------------------------------------------
  639. //    Accessing Alarm Time and Date
  640. //----------------------------------------------------------------------------------------------------
  641. - alarmTimeAndDate: (struct tm*) theAlarmTimeAndDate
  642. {
  643.     memcpy (&alarmTimeAndDate,  theAlarmTimeAndDate, sizeof (struct tm));
  644.     return self;
  645. }
  646.  
  647.  
  648. - alarmSecond: (int) theSecond
  649. {
  650.     if (theSecond < 0) theSecond = 0; else if (theSecond > 59) theSecond = 59;
  651.     SECOND(&alarmTimeAndDate) = theSecond;
  652.     return self;
  653. }
  654.  
  655.  
  656. - alarmMinute: (int) theMinute
  657. {
  658.     if (theMinute < 0) theMinute = 0; else if (theMinute > 59) theMinute = 59;
  659.     MINUTE(&alarmTimeAndDate) = theMinute;
  660.     return self;
  661. }
  662.  
  663.  
  664. - alarmHour: (int) theHour
  665. {
  666.     if (theHour < 0) theHour = 0; else if (theHour > 23) theHour = 23;
  667.     HOUR(&alarmTimeAndDate) = theHour;
  668.     return self;
  669. }
  670.  
  671. - alarmDay: (int) theDay
  672. {
  673.     if (theDay < 1) 
  674.         theDay = 1; 
  675.     else if (theDay > [self _lastDayOfMonth:&alarmTimeAndDate]) 
  676.         theDay = [self _lastDayOfMonth:&alarmTimeAndDate];
  677.  
  678.     DAY(&alarmTimeAndDate) = theDay;
  679.     WEEKDAY(&alarmTimeAndDate) = [self weekDay: &alarmTimeAndDate];
  680.     return self;
  681. }
  682.  
  683.  
  684. - alarmMonth: (int) theMonth
  685. {
  686.     if (theMonth < 0) theMonth = 0; else if (theMonth > 11) theMonth = 11;
  687.     MONTH(&alarmTimeAndDate) = theMonth;
  688.     WEEKDAY(&alarmTimeAndDate) = [self weekDay: &alarmTimeAndDate];
  689.     [self alarmDay: [self alarmDay]];
  690.     return self;
  691. }
  692.  
  693.  
  694. - alarmYear: (int) theYear
  695. {
  696.     if (theYear < 0) theYear = 0; else if (theYear > 99) theYear = 99;
  697.     YEAR(&alarmTimeAndDate) = theYear;
  698.     WEEKDAY(&alarmTimeAndDate) = [self weekDay: &alarmTimeAndDate];
  699.     [self alarmDay: [self alarmDay]];
  700.     return self;
  701. }
  702.  
  703.  
  704. - alarmWeekday: (int) theWeekday
  705. {
  706.     if (theWeekday < 0) theWeekday = 0; else if (theWeekday > 6) theWeekday = 6;
  707.     WEEKDAY(&alarmTimeAndDate) = theWeekday;
  708.     return self;
  709. }
  710.  
  711.  
  712. - (struct tm*) alarmTimeAndDate
  713. {
  714.     return &alarmTimeAndDate;
  715. }
  716.  
  717.  
  718. - (int) alarmSecond
  719. {
  720.     return SECOND(&alarmTimeAndDate);
  721. }
  722.  
  723.  
  724. - (int) alarmMinute
  725. {
  726.     return MINUTE(&alarmTimeAndDate);
  727. }
  728.  
  729.  
  730. - (int) alarmHour
  731. {
  732.     return HOUR(&alarmTimeAndDate);
  733. }
  734.  
  735.  
  736. - (int) alarmDay
  737. {
  738.     return DAY(&alarmTimeAndDate);
  739. }
  740.  
  741.  
  742. - (int) alarmMonth
  743. {
  744.     return MONTH(&alarmTimeAndDate);
  745. }
  746.  
  747.  
  748. - (int) alarmYear
  749. {
  750.     return YEAR(&alarmTimeAndDate);
  751. }
  752.  
  753.  
  754. - (int) alarmWeekday
  755. {
  756.     return WEEKDAY(&alarmTimeAndDate);
  757. }
  758.  
  759.  
  760. //----------------------------------------------------------------------------------------------------
  761. //    Accessing Alarm Sound
  762. //----------------------------------------------------------------------------------------------------
  763. - alarmSound: aSound
  764. {
  765.     //  Audible notification of alarm match (in addition to action send to target).
  766.  
  767.     if (! alarmSound) alarmSound = [[Sound alloc] init];
  768.     [alarmSound copySound: aSound];
  769.     return self;
  770. }
  771.  
  772.  
  773. - alarmSound
  774. {
  775.     return alarmSound;
  776. }
  777.  
  778.  
  779. //----------------------------------------------------------------------------------------------------
  780. //    Starting and Stopping the Clock
  781. //----------------------------------------------------------------------------------------------------
  782. - startFromSystem: sender
  783. {
  784.     //  Clock starts (and stays synced) with system time.
  785.     
  786.     privateFlags.timerMode = TIMER_REALTIME;
  787.     [self clockTimeAndDate: [self _systemTime]];
  788.     if (! [self isClockRunning]) [self _addTimedEntry];
  789.     return self;
  790. }
  791.  
  792.  
  793. - startFromSelf: sender
  794. {
  795.     //  Clock starts from current setting.
  796.     
  797.     privateFlags.timerMode = TIMER_RELATIVE;
  798.     privateFlags.initRelativeTimerMode = YES;
  799.     if (! [self isClockRunning]) [self _addTimedEntry];
  800.     return self;
  801. }
  802.  
  803.  
  804. - startFromTime: (struct tm*) theTime
  805. {
  806.     //  Clock sets time and date to theTime and starts timer from this time.
  807.     
  808.     [self clockTimeAndDate: theTime];
  809.     return [self startFromSelf: nil];
  810. }
  811.  
  812.  
  813. - stop: sender
  814. {
  815.     if ([self isClockRunning]) [self _removeTimedEntry];
  816.     return self;
  817. }
  818.  
  819.  
  820. - activateOnAwake: (int) aFlag;
  821. {
  822.     //  If YES, timer will begin when unarchived.
  823.     
  824.     flags.activateOnAwake = aFlag;
  825.     return self;
  826. }
  827.  
  828.  
  829. - (int) activateOnAwake;
  830. {
  831.     return flags.activateOnAwake;
  832. }
  833.  
  834.  
  835. //----------------------------------------------------------------------------------------------------
  836. //    Timer Status
  837. //----------------------------------------------------------------------------------------------------
  838. - (BOOL) isClockRunning
  839. {
  840.     return (timedEntry ? YES : NO);
  841. }
  842.  
  843.  
  844. //----------------------------------------------------------------------------------------------------
  845. //    Utility Methods
  846. //----------------------------------------------------------------------------------------------------
  847. + setTimeAndDate:(struct tm*)time :(int)hour :(int)minute :(int)second :(int)month :(int)day :(int)year;
  848. {
  849.     //  Returns by reference the tm struct time.  Struct values are filled with any valid 
  850.     //  arguments (ranges are checked).  Weekday (tm_wday) is calculated based
  851.     //  on the date values passed.  Other struct members use current system defaults.
  852.     
  853.     if (! time) return self;
  854.     memcpy (time,  [self _systemTime], sizeof (struct tm));
  855.     SECOND(time) = (second < 0 || second > 59) ? 0 : second;
  856.     MINUTE(time) = (minute < 0 || minute > 59) ? 0 : minute;
  857.     HOUR(time) = (hour < 0 || hour > 23) ? 0 : hour;
  858.     DAY(time) = (day < 1 || day > 31) ? 1 : day;
  859.     MONTH(time) = (month < 0 || month > 11) ? 0 : month;
  860.     YEAR(time) = (year < 0 || year > 99) ? 0 : year;
  861.     WEEKDAY(time) = [self weekDay: time];
  862.     return self;
  863. }
  864.  
  865.  
  866. - setTimeAndDate:(struct tm*)time :(int)hour :(int)minute :(int)second :(int)month :(int)day :(int)year;
  867. {
  868.     return [Clock setTimeAndDate: time :hour :minute :second :month :day :year];
  869. }
  870.  
  871.  
  872. - (int) weekDay: (struct tm*) aTime
  873. {
  874.     //  Determine the day of week based on date info in aTime.  Calculated
  875.     //  in Julian format, return value 0 - 6, where 0 = Sunday.
  876.     
  877.     int        day = DAY (aTime);
  878.     int        month = MONTH (aTime) +1;
  879.     int        year = YEAR (aTime) + 1900;
  880.     int        weekDay;
  881.     int         offset;
  882.     long     julian;
  883.  
  884.     if (month <= 2) { year--; month += 12;}
  885.     offset = (2 - (year / 100)) + ((year / 100) / 4);
  886.     julian = (365.25 * year);
  887.     julian += (long) (30.6001 * (month +1));
  888.     julian += (long) day;
  889.     julian += 1720994L;
  890.     julian += (long) offset;
  891.  
  892.     weekDay = (int) ((julian + 2) % 7);
  893.     return (weekDay < 0 || weekDay > 6 ? 0 : weekDay);
  894. }
  895.  
  896.  
  897. //----------------------------------------------------------------------------------------------------
  898. //    Display Methods
  899. //----------------------------------------------------------------------------------------------------
  900. - showClockTime: sender
  901. {
  902.     //  Shows current time and date setting. Will not disturb current timer.
  903.     
  904.     displayTimeAndDate = &clockTimeAndDate;
  905.     privateFlags.displayMode = DISPLAY_OTHER;
  906.     [self update];
  907.     return self;
  908. }
  909.  
  910.  
  911. - showSystemTime: sender
  912. {
  913.     //   Displays system time. Will not disturb current timer.
  914.     
  915.     displayTimeAndDate = [self _systemTime];
  916.     privateFlags.displayMode = DISPLAY_OTHER;
  917.     [self update];
  918.     return self;
  919. }
  920.  
  921.  
  922. - showAlarmTime: sender
  923. {
  924.     //  Displays current alarm time and date. Will not disturb current timer.
  925.     
  926.     displayTimeAndDate = &alarmTimeAndDate;
  927.     privateFlags.displayMode = DISPLAY_ALARM;
  928.     [self update];
  929.     return self;
  930. }
  931.  
  932.  
  933. - showTime: (struct tm*) aTime
  934. {
  935.     //   Displays system time. Will not disturb current timer.
  936.     
  937.     displayTimeAndDate = aTime;
  938.     privateFlags.displayMode = DISPLAY_OTHER;
  939.     [self update];
  940.     return self;
  941. }
  942.  
  943.  
  944. - resumeClockDisplay: sender
  945. {
  946.     //  Invoke this to resume display of current clock time.
  947.     
  948.     displayTimeAndDate = &clockTimeAndDate;
  949.     privateFlags.displayMode = DISPLAY_CLOCK;
  950.     [self update];
  951.     return self;
  952. }    
  953.  
  954.  
  955. //----------------------------------------------------------------------------------------------------
  956. //    IB Action Methods
  957. //----------------------------------------------------------------------------------------------------
  958. - takeDisplayEnabledFlagFrom: sender;
  959. {
  960.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  961.     if ([sender respondsTo: @selector (state)]) [self setDisplayEnabled: [sender state]];
  962.     return self;
  963. }
  964.  
  965.  
  966. - takeWantsSecondsFlagFrom: sender
  967. {
  968.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  969.     if ([sender respondsTo: @selector (state)]) [self wantsSeconds: [sender state]];
  970.     return self;
  971. }
  972.  
  973.  
  974. - takeWantsDateFlagFrom: sender;
  975. {
  976.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  977.     if ([sender respondsTo: @selector (state)]) [self wantsDate: [sender state]];
  978.     return self;
  979. }
  980.  
  981.  
  982. - takeWantsMilitaryTimeFlagFrom: sender;
  983. {
  984.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  985.     if ([sender respondsTo: @selector (state)]) [self wantsMilitaryTime: [sender state]];
  986.     return self;
  987. }
  988.  
  989.  
  990. - takeIsDraggableFlagFrom: sender;
  991. {
  992.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  993.     if ([sender respondsTo: @selector (state)]) [self isDraggable: [sender state]];
  994.     return self;
  995. }
  996.  
  997.  
  998. - takeWillAcceptDropFlagFrom: sender;
  999. {
  1000.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  1001.     if ([sender respondsTo: @selector (state)]) [self willAcceptDrop: [sender state]];
  1002.     return self;
  1003. }
  1004.  
  1005.  
  1006. - takeEnableAlarmFlagFrom: sender
  1007. {
  1008.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  1009.     if ([sender respondsTo: @selector (state)]) [self enableAlarm: [sender state]];
  1010.     return self;
  1011. }
  1012.  
  1013.  
  1014. - takeWantsAlarmIndicatorFlagFrom: sender
  1015. {
  1016.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  1017.     if ([sender respondsTo: @selector (state)]) [self wantsAlarmIndicator: [sender state]];
  1018.     return self;
  1019. }
  1020.  
  1021.  
  1022. - takeBackgroundColorFrom: sender
  1023. {
  1024.     if ([sender respondsTo: @selector (color)]) [self backgroundColor: [sender color]];
  1025.     return self;
  1026. }
  1027.  
  1028.  
  1029. - takeClockSecondIntValueFrom: sender
  1030. {
  1031.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  1032.     if ([sender respondsTo: @selector (intValue)]) [self clockSecond: [sender intValue]];
  1033.     [[self _nextText: sender] update];
  1034.     return self;
  1035. }
  1036.  
  1037.  
  1038. - takeClockMinuteIntValueFrom: sender
  1039. {
  1040.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  1041.     if ([sender respondsTo: @selector (intValue)]) [self clockMinute: [sender intValue]];
  1042.     [[self _nextText: sender] update];
  1043.     return self;
  1044. }
  1045.  
  1046.  
  1047. - takeClockHourIntValueFrom: sender
  1048. {
  1049.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  1050.     if ([sender respondsTo: @selector (intValue)]) [self clockHour: [sender intValue]];
  1051.     [[self _nextText: sender] update];
  1052.     return self;
  1053. }
  1054.  
  1055.  
  1056. - takeClockDayIntValueFrom: sender
  1057. {
  1058.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  1059.     if ([sender respondsTo: @selector (intValue)]) [self clockDay: [sender intValue]];
  1060.     [[self _nextText: sender] update];
  1061.     return self;
  1062. }
  1063.  
  1064.  
  1065. - takeClockMonthIntValueFrom: sender
  1066. {
  1067.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  1068.     if ([sender respondsTo: @selector (intValue)]) [self clockMonth: [sender intValue]];
  1069.     [[self _nextText: sender] update];
  1070.     return self;
  1071. }
  1072.  
  1073.  
  1074. - takeClockYearIntValueFrom: sender
  1075. {
  1076.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  1077.     if ([sender respondsTo: @selector (intValue)]) [self clockYear: [sender intValue]];
  1078.     [[self _nextText: sender] update];
  1079.     return self;
  1080. }
  1081.  
  1082.  
  1083. - takeClockWeekdayIntValueFrom: sender
  1084. {
  1085.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  1086.     if ([sender respondsTo: @selector (intValue)]) [self clockWeekday: [sender intValue]];
  1087.     [[self _nextText: sender] update];
  1088.     return self;
  1089. }
  1090.  
  1091.  
  1092. - takeAlarmSecondIntValueFrom: sender
  1093. {
  1094.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  1095.     if ([sender respondsTo: @selector (intValue)]) [self alarmSecond: [sender intValue]];
  1096.     [[self _nextText: sender] update];
  1097.     return self;
  1098. }
  1099.  
  1100.  
  1101. - takeAlarmMinuteIntValueFrom: sender
  1102. {
  1103.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  1104.     if ([sender respondsTo: @selector (intValue)]) [self alarmMinute: [sender intValue]];
  1105.     [[self _nextText: sender] update];
  1106.     return self;
  1107. }
  1108.  
  1109.  
  1110. - takeAlarmHourIntValueFrom: sender
  1111. {
  1112.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  1113.     if ([sender respondsTo: @selector (intValue)]) [self alarmHour: [sender intValue]];
  1114.     [[self _nextText: sender] update];
  1115.     return self;
  1116. }
  1117.  
  1118.  
  1119. - takeAlarmDayIntValueFrom: sender
  1120. {
  1121.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  1122.     if ([sender respondsTo: @selector (intValue)]) [self alarmDay: [sender intValue]];
  1123.     [[self _nextText: sender] update];
  1124.     return self;
  1125. }
  1126.  
  1127.  
  1128. - takeAlarmMonthIntValueFrom: sender
  1129. {
  1130.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  1131.     if ([sender respondsTo: @selector (intValue)]) [self alarmMonth: [sender intValue]];
  1132.     [[self _nextText: sender] update];
  1133.     return self;
  1134. }
  1135.  
  1136.  
  1137. - takeAlarmYearIntValueFrom: sender
  1138. {
  1139.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  1140.     if ([sender respondsTo: @selector (intValue)]) [self alarmYear: [sender intValue]];
  1141.     [[self _nextText: sender] update];
  1142.     return self;
  1143. }
  1144.  
  1145.  
  1146. - takeAlarmWeekdayIntValueFrom: sender
  1147. {
  1148.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  1149.     if ([sender respondsTo: @selector (intValue)]) [self alarmWeekday: [sender intValue]];
  1150.     [[self _nextText: sender] update];
  1151.     return self;
  1152. }
  1153.  
  1154.  
  1155. - takeAlarmModeIntValueFrom: sender
  1156. {
  1157.     if ([sender isKindOf: [Matrix class]]) sender = [sender selectedCell];
  1158.     if ([sender respondsTo: @selector (tag)]) privateFlags.alarmMode = [sender tag];
  1159.     return self;
  1160. }
  1161.  
  1162.  
  1163. - incrementClockSecond: sender
  1164. {
  1165.     [self clockSecond: [self clockSecond] + 1];
  1166.     [self showClockTime: nil];
  1167.     return self;
  1168. }
  1169.  
  1170.  
  1171. - incrementClockMinute: sender
  1172. {
  1173.     [self clockMinute: [self clockMinute] + 1];
  1174.     [self showClockTime: nil];
  1175.     return self;
  1176. }
  1177.  
  1178.  
  1179. - incrementClockHour: sender
  1180. {
  1181.     [self clockHour: [self clockHour] + 1];
  1182.     [self showClockTime: nil];
  1183.     return self;
  1184. }
  1185.  
  1186.  
  1187. - incrementClockDay: sender
  1188. {
  1189.     [self clockDay: [self clockDay] + 1];
  1190.     [self showClockTime: nil];
  1191.     return self;
  1192. }
  1193.  
  1194.  
  1195. - incrementClockMonth: sender
  1196. {
  1197.     [self clockMonth: [self clockMonth] + 1];
  1198.     [self showClockTime: nil];
  1199.     return self;
  1200. }
  1201.  
  1202.  
  1203. - incrementClockYear: sender
  1204. {
  1205.     [self clockYear: [self clockYear] + 1];
  1206.     [self showClockTime: nil];
  1207.     return self;
  1208. }
  1209.  
  1210.  
  1211. - incrementClockWeekday: sender
  1212. {
  1213.     [self clockWeekday: [self clockWeekday] + 1];
  1214.     [self showClockTime: nil];
  1215.     return self;
  1216. }
  1217.  
  1218.  
  1219. - decrementClockSecond: sender
  1220. {
  1221.     [self clockSecond: [self clockSecond] - 1];
  1222.     [self showClockTime: nil];
  1223.     return self;
  1224. }
  1225.  
  1226.  
  1227. - decrementClockMinute: sender
  1228. {
  1229.     [self clockMinute: [self clockMinute] - 1];
  1230.     [self showClockTime: nil];
  1231.     return self;
  1232. }
  1233.  
  1234.  
  1235. - decrementClockHour: sender
  1236. {
  1237.     [self clockHour: [self clockHour] - 1];
  1238.     [self showClockTime: nil];
  1239.     return self;
  1240. }
  1241.  
  1242.  
  1243. - decrementClockDay: sender
  1244. {
  1245.     [self clockDay: [self clockDay] - 1];
  1246.     [self showClockTime: nil];
  1247.     return self;
  1248. }
  1249.  
  1250.  
  1251. - decrementClockMonth: sender
  1252. {
  1253.     [self clockMonth: [self clockMonth] - 1];
  1254.     [self showClockTime: nil];
  1255.     return self;
  1256. }
  1257.  
  1258.  
  1259. - decrementClockYear: sender
  1260. {
  1261.     [self clockYear: [self clockYear] - 1];
  1262.     [self showClockTime: nil];
  1263.     return self;
  1264. }
  1265.  
  1266.  
  1267. - decrementClockWeekday: sender
  1268. {
  1269.     [self clockWeekday: [self clockWeekday] - 1];
  1270.     [self showClockTime: nil];
  1271.     return self;
  1272. }
  1273.  
  1274.  
  1275.  
  1276. - incrementAlarmSecond: sender
  1277. {
  1278.     [self alarmSecond: [self alarmSecond] + 1];
  1279.     [self showAlarmTime: nil];
  1280.     return self;
  1281. }
  1282.  
  1283.  
  1284. - incrementAlarmMinute: sender
  1285. {
  1286.     [self alarmMinute: [self alarmMinute] + 1];
  1287.     [self showAlarmTime: nil];
  1288.     return self;
  1289. }
  1290.  
  1291.  
  1292. - incrementAlarmHour: sender
  1293. {
  1294.     [self alarmHour: [self alarmHour] + 1];
  1295.     [self showAlarmTime: nil];
  1296.     return self;
  1297. }
  1298.  
  1299.  
  1300. - incrementAlarmDay: sender
  1301. {
  1302.     [self alarmDay: [self alarmDay] + 1];
  1303.     [self showAlarmTime: nil];
  1304.     return self;
  1305. }
  1306.  
  1307.  
  1308. - incrementAlarmMonth: sender
  1309. {
  1310.     [self alarmMonth: [self alarmMonth] + 1];
  1311.     [self showAlarmTime: nil];
  1312.     return self;
  1313. }
  1314.  
  1315.  
  1316. - incrementAlarmYear: sender
  1317. {
  1318.     [self alarmYear: [self alarmYear] + 1];
  1319.     [self showAlarmTime: nil];
  1320.     return self;
  1321. }
  1322.  
  1323.  
  1324. - incrementAlarmWeekday: sender
  1325. {
  1326.     [self alarmWeekday: [self alarmWeekday] + 1];
  1327.     [self showAlarmTime: nil];
  1328.     return self;
  1329. }
  1330.  
  1331.  
  1332. - decrementAlarmSecond: sender
  1333. {
  1334.     [self alarmSecond: [self alarmSecond] - 1];
  1335.     [self showAlarmTime: nil];
  1336.     return self;
  1337. }
  1338.  
  1339.  
  1340. - decrementAlarmMinute: sender
  1341. {
  1342.     [self alarmMinute: [self alarmMinute] - 1];
  1343.     [self showAlarmTime: nil];
  1344.     return self;
  1345. }
  1346.  
  1347.  
  1348. - decrementAlarmHour: sender
  1349. {
  1350.     [self alarmHour: [self alarmHour] - 1];
  1351.     [self showAlarmTime: nil];
  1352.     return self;
  1353. }
  1354.  
  1355.  
  1356. - decrementAlarmDay: sender
  1357. {
  1358.     [self alarmDay: [self alarmDay] - 1];
  1359.     [self showAlarmTime: nil];
  1360.     return self;
  1361. }
  1362.  
  1363.  
  1364. - decrementAlarmMonth: sender
  1365. {
  1366.     [self alarmMonth: [self alarmMonth] - 1];
  1367.     [self showAlarmTime: nil];
  1368.     return self;
  1369. }
  1370.  
  1371.  
  1372. - decrementAlarmYear: sender
  1373. {
  1374.     [self alarmYear: [self alarmYear] - 1];
  1375.     [self showAlarmTime: nil];
  1376.     return self;
  1377. }
  1378.  
  1379.  
  1380. - decrementAlarmWeekday: sender
  1381. {
  1382.     [self alarmWeekday: [self alarmWeekday] - 1];
  1383.     [self showAlarmTime: nil];
  1384.     return self;
  1385. }
  1386.  
  1387.  
  1388. //----------------------------------------------------------------------------------------------------
  1389. //    Draw Methods
  1390. //----------------------------------------------------------------------------------------------------
  1391. -drawSelf: (const NXRect *)rects :(int)rectCount
  1392. {
  1393.     //  Manage display as appropriate.  Subclasses implement drawing
  1394.     //  specific to their graphical representation.
  1395.  
  1396.     if (flags.wantsDisplay)
  1397.         {
  1398.         [self drawBackground];
  1399.         [self drawClockFace];
  1400.         [self drawAlarmIndicator];
  1401.         [self drawTime];
  1402.         [self drawDate];
  1403.         }
  1404.  
  1405.     return self;
  1406. }
  1407.  
  1408.  
  1409. - drawBackground
  1410. {
  1411.     //  Fill background with image (scaled) or background color.     
  1412.     if (privateFlags.backgroundIsColor)
  1413.         {
  1414.         NXSetColor (backgroundColor);
  1415.         NXRectFill (&bounds);
  1416.         return self;
  1417.         }
  1418.         
  1419.     [backgroundImage setSize: &bounds.size];
  1420.     [backgroundImage composite: NX_SOVER toPoint: &bounds.origin];
  1421.  
  1422.     return self;
  1423. }
  1424.         
  1425.  
  1426. - drawClockFace
  1427. {
  1428.     //  Center clockFace image in bounds rect.
  1429.     
  1430.     NXPoint    compositePoint = [self _compositePointForImage:clockFace];
  1431.     [clockFace composite: NX_SOVER toPoint: &compositePoint];
  1432.     return self;
  1433. }
  1434.  
  1435.  
  1436. - drawTime
  1437. {
  1438.     return self;
  1439. }
  1440.  
  1441.  
  1442. - drawDate
  1443. {
  1444.     return self;
  1445. }
  1446.  
  1447.  
  1448. - drawAlarmIndicator
  1449. {
  1450.     //  Visible indicator that alarm is set and enabled.
  1451.     
  1452.     if (flags.isAlarmEnabled && flags.wantsAlarmIndicator) 
  1453.         {
  1454.             id font = [Font newFont:"Times-Roman" size:12 style:0 matrix:NX_IDENTITYMATRIX];
  1455.         NXSetColor (NX_COLORRED);
  1456.         [font set];
  1457.         PSmoveto (2.0, 0.0);
  1458.         PSshow ("•");
  1459.         [font free];
  1460.         }
  1461.         
  1462.     return self;
  1463. }
  1464.  
  1465.  
  1466. //----------------------------------------------------------------------------------------------------
  1467. //    Dragging Support
  1468. //----------------------------------------------------------------------------------------------------
  1469. - isDraggable: (BOOL) aFlag
  1470. {
  1471.     flags.isDraggable = aFlag;
  1472.     return self;
  1473. }
  1474.  
  1475.  
  1476. - willAcceptDrop: (BOOL) aFlag;
  1477. {
  1478.     const char*    dragTypes[] = {ClockPboardType, NULL};
  1479.  
  1480.     flags.willAcceptDrop = aFlag;
  1481.     
  1482.     if (flags.willAcceptDrop)
  1483.         [self registerForDraggedTypes:dragTypes count:1];
  1484.     else
  1485.         [self unregisterDraggedTypes];
  1486.         
  1487.     return self;
  1488. }
  1489.  
  1490.  
  1491. - (BOOL) isDraggable
  1492. {
  1493.     return flags.isDraggable;
  1494. }
  1495.  
  1496.  
  1497. - (BOOL) willAcceptDrop
  1498. {
  1499.     return flags.willAcceptDrop;
  1500. }
  1501.  
  1502.  
  1503. - (BOOL)acceptsFirstMouse
  1504. {
  1505.         return flags.isDraggable;
  1506. }
  1507.  
  1508.  
  1509. - mouseDown: (NXEvent*) theEvent
  1510. {
  1511.     //  If draggable, initiate drag sequence on mouse-drag...
  1512.     
  1513.     int            originalEventMask;
  1514.     NXEvent        originalEvent = *theEvent;
  1515.     NXEvent        nextEvent;
  1516.  
  1517.     if (! flags.isDraggable) return self;
  1518.  
  1519.         [NXApp preventWindowOrdering];
  1520.  
  1521.     originalEventMask = [window addToEventMask: NX_LMOUSEDRAGGEDMASK];
  1522.  
  1523.     nextEvent = *( [NXApp getNextEvent: (NX_LMOUSEUPMASK | 
  1524.                                          NX_LMOUSEDRAGGEDMASK)] );
  1525.  
  1526.     switch (nextEvent.type)
  1527.         {
  1528.         case NX_LMOUSEDRAGGED:
  1529.             [self beginDragOperationFor: &originalEvent  nextEvent: &nextEvent];
  1530.             
  1531.         case NX_LMOUSEUP:
  1532.         default:
  1533.             break;
  1534.         }
  1535.     
  1536.     [window setEventMask: originalEventMask];
  1537.         return self;
  1538. }
  1539.  
  1540.  
  1541. - beginDragOperationFor: (NXEvent*) originalEvent  nextEvent: (NXEvent*) nextEvent
  1542. {
  1543.     //  Begin the drag sequence.  
  1544.     
  1545.     NXPoint    startingPoint = { 0.0, 0.0 };
  1546.     id        dragImage = [self dragImage];    
  1547.     id         pasteboard = [Pasteboard newName: NXDragPboard];
  1548.         
  1549.     [self writeToPasteboard:pasteboard];
  1550.     
  1551.     [self dragImage: dragImage
  1552.         at: &startingPoint
  1553.         offset: &startingPoint 
  1554.         event: originalEvent 
  1555.         pasteboard: pasteboard 
  1556.         source: self
  1557.         slideBack: YES];
  1558.         
  1559.     if (dragImage) [dragImage free];
  1560.     if (pasteboard) [pasteboard free];
  1561.  
  1562.     return self;
  1563. }
  1564.             
  1565.  
  1566. - (NXImage*) dragImage
  1567. {
  1568.     id    bitmap;
  1569.     id    image = [[NXImage alloc] init];
  1570.  
  1571.     [self lockFocus];
  1572.     bitmap = [[NXBitmapImageRep alloc] initData: NULL fromRect: &bounds];
  1573.     [self lockFocus];
  1574.     [image useRepresentation: bitmap];
  1575.     return image;
  1576. }
  1577.  
  1578.  
  1579. - (BOOL) shouldDelayWindowOrderingForEvent: (NXEvent*) theEvent
  1580. {
  1581.      //  This allows you to drag a partially obscure object without making 
  1582.     //  the source window become main, and without making the source 
  1583.     //  application the current app.
  1584.  
  1585.         return YES;
  1586. }
  1587.  
  1588.  
  1589. //----------------------------------------------------------------------------------------------------
  1590. //    Dragging Source Protocol
  1591. //----------------------------------------------------------------------------------------------------
  1592. - (NXDragOperation) draggingSourceOperationMaskForLocal: (BOOL)aFlag;
  1593. {    
  1594.     return NX_DragOperationAll;
  1595. }
  1596.  
  1597.  
  1598. //----------------------------------------------------------------------------------------------------
  1599. //    Dragging Destination Protocol
  1600. //----------------------------------------------------------------------------------------------------
  1601. - (NXDragOperation)draggingEntered:dragSource
  1602. {
  1603.         return [self draggingUpdated:dragSource];
  1604. }
  1605.  
  1606.  
  1607. - (NXDragOperation)draggingUpdated:dragSource
  1608. {
  1609.     if ([dragSource draggingSource] == self) return NX_DragOperationNone; 
  1610.  
  1611.     switch ([dragSource draggingSourceOperationMask])
  1612.         {
  1613.         case NX_DragOperationCopy:
  1614.             return NX_DragOperationCopy;
  1615.         case NX_DragOperationLink:
  1616.             return NX_DragOperationLink;
  1617.         case NX_DragOperationGeneric:
  1618.         case NX_DragOperationAll:
  1619.         default:
  1620.             return NX_DragOperationGeneric;
  1621.         }
  1622. }
  1623.  
  1624.  
  1625. - (BOOL)prepareForDragOperation:dragSource
  1626. {
  1627.     return YES;
  1628. }
  1629.  
  1630.  
  1631. - (BOOL)performDragOperation:dragSource
  1632. {
  1633.     id pasteboardClock = [self readFromPasteboard: [dragSource draggingPasteboard]];
  1634.  
  1635.     switch ([dragSource draggingSourceOperationMask])
  1636.         {
  1637.         case NX_DragOperationCopy:
  1638.             [self dragOperationCopy: pasteboardClock];
  1639.             break;
  1640.         case NX_DragOperationLink:
  1641.             [self dragOperationLink: pasteboardClock];
  1642.             break;
  1643.         case NX_DragOperationGeneric:
  1644.         case NX_DragOperationAll:
  1645.         default:
  1646.             [self dragOperationGeneric: pasteboardClock];
  1647.             break;
  1648.         }
  1649.  
  1650.     [pasteboardClock free];
  1651.     return YES;
  1652. }
  1653.  
  1654.  
  1655. - concludeDragOperation:dragSource
  1656. {
  1657.     return self;
  1658. }
  1659.  
  1660.  
  1661. //----------------------------------------------------------------------------------------------------
  1662. //    Clock Drag Operations
  1663. //----------------------------------------------------------------------------------------------------
  1664. - dragOperationCopy: pasteboardClock
  1665. {
  1666.     //  User is holding Alternate key down while dropping, copy
  1667.     //  only Alarm information.
  1668.     
  1669.     [self alarmTimeAndDate: [pasteboardClock alarmTimeAndDate]];
  1670.     [self enableAlarm: [pasteboardClock isAlarmEnabled]];
  1671.     [self wantsAlarmIndicator: [pasteboardClock wantsAlarmIndicator]];
  1672.     privateFlags.alarmMode = [pasteboardClock _alarmMode];
  1673.     privateFlags.alarmSleep = NO;
  1674.     [self update];
  1675.     return self;
  1676. }
  1677.  
  1678.     
  1679. - dragOperationLink: pasteboardClock
  1680. {
  1681.     //  User is holding the Control key down while dropping, copy 
  1682.     //  only Clock information.
  1683.  
  1684.     [self clockTimeAndDate: [pasteboardClock clockTimeAndDate]];
  1685.  
  1686.     if ([pasteboardClock activateOnAwake])
  1687.         if ([pasteboardClock _timerMode] == TIMER_REALTIME)
  1688.             [self startFromSystem: nil];
  1689.         else
  1690.             {
  1691.             [self startFromSelf: nil];
  1692.             privateFlags.initRelativeTimerMode = NO;
  1693.             previousClock = [pasteboardClock _previousClock];
  1694.             }
  1695.     else
  1696.         [self stop: nil];
  1697.             
  1698.     [self update];
  1699.     return self;
  1700. }
  1701.  
  1702.  
  1703. - dragOperationGeneric: pasteboardClock
  1704. {
  1705.     //  User is holding Command (or no) key down while dropping, copy
  1706.     //  both Clock and Alarm information.
  1707.     
  1708.     [self dragOperationCopy: pasteboardClock];
  1709.     [self dragOperationLink: pasteboardClock];
  1710.     [self update];
  1711.     return self;
  1712. }
  1713.  
  1714.  
  1715. //----------------------------------------------------------------------------------------------------
  1716. //    Pasteboard Methods
  1717. //----------------------------------------------------------------------------------------------------
  1718. - writeToPasteboard: aPasteboard
  1719. {
  1720.     //  Only tricky thing here is to make sure the pasteboard object will not 
  1721.     //  begin a timed entry in the awake method when it is readFromPasteboard.
  1722.         
  1723.     int                 length; 
  1724.     int                maxLength;
  1725.     char*            data;
  1726.     NXStream*        aStream = NXOpenMemory (NULL, 0, NX_WRITEONLY);
  1727.     NXTypedStream*    aTypedStream = NXOpenTypedStream (aStream, NX_WRITEONLY);
  1728.     
  1729.     if ([self isClockRunning]) flags.activateOnAwake = AWAKE_PREVENT;
  1730.  
  1731.     NXWriteRootObject (aTypedStream, self);
  1732.     NXGetMemoryBuffer(aStream, &data, &length, &maxLength);
  1733.         [aPasteboard declareTypes: &ClockPboardType num:1 owner: self];
  1734.     [aPasteboard writeType:ClockPboardType data:data length:length];
  1735.  
  1736.     flags.activateOnAwake = [self isClockRunning];
  1737.  
  1738.     NXCloseTypedStream (aTypedStream);
  1739.     NXClose (aStream);
  1740.     return self;
  1741. }
  1742.  
  1743.  
  1744. - readFromPasteboard: aPasteboard
  1745. {
  1746.     NXStream*        aStream = [aPasteboard readTypeToStream:ClockPboardType];
  1747.     NXTypedStream*    aTypedStream = NXOpenTypedStream (aStream, NX_READONLY);
  1748.  
  1749.     id  pasteboardClock = NXReadObject (aTypedStream);
  1750.  
  1751.     NXCloseTypedStream (aTypedStream);
  1752.     NXClose (aStream);
  1753.     return pasteboardClock;
  1754. }
  1755.  
  1756.  
  1757. //----------------------------------------------------------------------------------------------------
  1758. //    Archiving Methods
  1759. //----------------------------------------------------------------------------------------------------
  1760. - read: (NXTypedStream*) stream
  1761. {
  1762.     [super read: stream];
  1763.     NXReadType (stream, "{iiiiiii}", &clockTimeAndDate);
  1764.     NXReadType (stream, "{iiiiiii}", &alarmTimeAndDate);
  1765.     NXReadType (stream, "s", (short*)&flags);
  1766.     NXReadType (stream, "s", (short*)&privateFlags);
  1767.     backgroundColor = NXReadColor (stream);
  1768.     NXReadType (stream, "@", &backgroundImage);
  1769.     NXReadType (stream, "@", &clockFace);
  1770.     NXReadType (stream, "@", &alarmSound);
  1771.     NXReadType (stream, "i", &previousClock);
  1772.     return self;
  1773. }
  1774.  
  1775.  
  1776. - write: (NXTypedStream*) stream
  1777. {
  1778.     [super write: stream];
  1779.     NXWriteType (stream, "{iiiiiii}", &clockTimeAndDate);
  1780.     NXWriteType (stream, "{iiiiiii}", &alarmTimeAndDate);
  1781.     NXWriteType (stream, "s", (short*)&flags);
  1782.     NXWriteType (stream, "s", (short*)&privateFlags);
  1783.     NXWriteColor (stream, backgroundColor);
  1784.     NXWriteType (stream, "@", &backgroundImage);
  1785.     NXWriteType (stream, "@", &clockFace);
  1786.     NXWriteType (stream, "@", &alarmSound);
  1787.     NXWriteType (stream, "i", &previousClock);
  1788.     return self;
  1789. }
  1790.  
  1791.  
  1792. - awake
  1793. {
  1794.     //  Clock awakes displaying clock time and starts timer if appropriate.
  1795.     
  1796.     [self willAcceptDrop: flags.willAcceptDrop];
  1797.     
  1798.     privateFlags.displayMode = DISPLAY_CLOCK;
  1799.     displayTimeAndDate = &clockTimeAndDate;
  1800.  
  1801.     if (flags.activateOnAwake != AWAKE_RUNNING) return self;
  1802.  
  1803.     if (privateFlags.timerMode == TIMER_REALTIME)
  1804.         [self startFromSystem: nil];
  1805.     else
  1806.         [self startFromSelf: nil];
  1807.  
  1808.     return self;
  1809. }
  1810.     
  1811.  
  1812. @end