home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 007.lha / settime / timeset.c < prev    next >
C/C++ Source or Header  |  1986-11-10  |  18KB  |  600 lines

  1. /* This file, along with several ancillary functions in another */
  2. /* function file, lets you set the date and time using requesters. */
  3. /* The actual setting takes place via the AmigaDos call Date, */
  4. /* accessed by the AmigaDos function Execute(). */
  5.  
  6. /* If someone knows how to write the date and time 'directly' */
  7. /* to the machine, I'd like to know.  The date and time info */
  8. /* must be stored at some memory location, after all!! */
  9.  
  10. /* Some include files... */
  11. #include <exec/types.h>
  12. #include <exec/exec.h>
  13. #include <intuition/intuition.h>
  14. #include <libraries/dos.h>
  15. #include <lattice/stdio.h> 
  16.  
  17. /* Gadget ID numbers... */
  18. #define IDMINUTE 0
  19. #define IDHOUR 1
  20. #define IDYEAR 2
  21. #define IDDAY 3
  22. #define IDMONTH 4
  23. #define IDSETTIME 5
  24.  
  25. /* Some time zero values... */
  26. #define BASEYEAR 1986
  27.  
  28. /* Maximum of number years spanned by the year gadget. */
  29. #define MAXYEARS 30
  30.  
  31. /* The library base addresses for Intuition's magic... */
  32. int *GfxBase;
  33. struct IntuitionBase *IntuitionBase;
  34.  
  35. /* A lookup table of month names... */
  36. static char *MName[]={"January","February","March","April","May","June",
  37.   "July","August","September","October","November","December"};
  38.  
  39. /* Intuition functions used elsewhere, declared external here to */
  40. /* keep the compiler happy about returned types. */
  41. struct Window *SetWindow;
  42. struct IntuiMessage *GetMsg(),*IDCMPmesg;
  43. struct Window *OpenWindow(),*CloseWindow();
  44. struct MenuItem *ItemAddress();
  45.  
  46. /* User functions defined in Date.C and used here. */
  47. void FromDosDate(),ToDosDate();
  48. int LegalDays();
  49.  
  50. /* Some AmigaDos functions... */
  51. int Execute(); 
  52. void DateStamp();
  53.  
  54. /* Text used to identify the various gadgets in the requester. */
  55. static struct IntuiText MinuteText = {0,1,JAM2,0,-8,NULL,"Minute Select",NULL};
  56. static struct IntuiText HourText = {0,1,JAM2,0,-8,NULL,"Hour Select",NULL};
  57. static struct IntuiText YearText = {0,1,JAM2,0,-8,NULL,"Year Select",NULL};
  58. static struct IntuiText DayText = {0,1,JAM2,0,-8,NULL,"Day Select",NULL};
  59. static struct IntuiText MonthText = {0,1,JAM2,0,-8,NULL,"Month Select",NULL};
  60. static struct IntuiText SetTimeText = {0,1,JAM2,0,-8,NULL,"Set Time and Date",NULL};
  61.  
  62. /* When using the Pot(entiometer) gadgets (I call them sliders) */
  63. /* you need to give Intuition data areas in which to draw the   */
  64. /* default knobs.  You could define your own image to be used   */
  65. /* as a knob, but I'm too lazy for that. */
  66. static struct Image Knob1,Knob2,Knob3,Knob4,Knob5;
  67.  
  68. /* The set requester uses one boolean gadget (to actually SET the */
  69. /* time).  Here are the relative x,y coordinate pairs that define */
  70. /* the size and shape of the box enclosing the select region.     */
  71. static USHORT BoxData[] = {
  72.    0,0,
  73.    0,10,
  74.    30,10,
  75.    30,0,
  76.    0,0
  77.   };
  78.  
  79. /* Here is Border structure that makes the border implied by BoxData */
  80. /* meaningful to Intuition.  COMPLEMENT is a flag which forces the   */
  81. /* border to be drawn by complementing the color at each point the   */
  82. /* border passes through. */  
  83. static struct Border Box1 = {
  84.    0,0,
  85.    2,2,COMPLEMENT,
  86.    5,
  87.    &BoxData,
  88.    NULL
  89.   };
  90.  
  91. /* These next structures define the visual characteristics of the */
  92. /* various sliders.  The '0,0' datapair is, as I recall, where the */
  93. /* initial position and percent of full scale occupied by the slider */
  94. /* is specified.  The actual values are set later on in the program. */
  95. static struct PropInfo MinuteInfo = {
  96.    AUTOKNOB | FREEHORIZ ,
  97.    0,0,
  98.    NULL,NULL,
  99.    NULL,NULL,NULL,NULL,NULL,NULL
  100.   };
  101.  
  102. static struct PropInfo HourInfo = {
  103.    AUTOKNOB | FREEHORIZ ,
  104.    0,0,
  105.    NULL,NULL,
  106.    NULL,NULL,NULL,NULL,NULL,NULL
  107.   };
  108.  
  109. static struct PropInfo YearInfo = {
  110.    AUTOKNOB | FREEHORIZ ,
  111.    0,0,
  112.    NULL,NULL,
  113.    NULL,NULL,NULL,NULL,NULL,NULL
  114.   };
  115.  
  116. static struct PropInfo DayInfo = {
  117.    AUTOKNOB | FREEHORIZ ,
  118.    0,0,
  119.    NULL,NULL,
  120.    NULL,NULL,NULL,NULL,NULL,NULL
  121.   };
  122.  
  123. static struct PropInfo MonthInfo = {
  124.    AUTOKNOB | FREEHORIZ ,
  125.    0,0,
  126.    NULL,NULL,
  127.    NULL,NULL,NULL,NULL,NULL,NULL
  128.   };
  129.  
  130. /* These next structures define the various gadgets.  Note that all */
  131. /* of the sliders -- but not the boolean gadget -- are set to       */
  132. /* follow mouse events and to immediately notify the program when   */
  133. /* they are selected by the user.  The follow function is needed    */
  134. /* because we want to continuously update the displayed date and    */
  135. /* time to give feedback.  Please note that the gadgets are linked */
  136. /* together as a list. */
  137. static struct Gadget MinuteGadget = {
  138.    NULL,
  139.    5,20,360,10,
  140.    GADGHNONE | GADGIMAGE,
  141.    GADGIMMEDIATE | FOLLOWMOUSE ,
  142.    PROPGADGET | REQGADGET,
  143.    (APTR)&Knob1 ,
  144.    NULL,
  145.    &MinuteText,
  146.    NULL,
  147.    (APTR)&MinuteInfo,
  148.    IDMINUTE,
  149.    NULL
  150.   };
  151.  
  152. static struct Gadget HourGadget = {
  153.    &MinuteGadget,
  154.    5,40,360,10,
  155.    GADGHNONE | GADGIMAGE,
  156.    GADGIMMEDIATE | FOLLOWMOUSE ,
  157.    PROPGADGET | REQGADGET,
  158.    (APTR)&Knob2 ,
  159.    NULL,
  160.    &HourText,
  161.    NULL,
  162.    (APTR)&HourInfo,
  163.    IDHOUR,
  164.    NULL
  165.   };
  166.  
  167. static struct Gadget YearGadget = {
  168.    &HourGadget,
  169.    5,60,360,10,
  170.    GADGHNONE | GADGIMAGE,
  171.    GADGIMMEDIATE | FOLLOWMOUSE ,
  172.    PROPGADGET | REQGADGET,
  173.    (APTR)&Knob3 ,
  174.    NULL,
  175.    &YearText,
  176.    NULL,
  177.    (APTR)&YearInfo,
  178.    IDYEAR,
  179.    NULL
  180.   };
  181.  
  182. static struct Gadget DayGadget = {
  183.    &YearGadget,
  184.    5,80,372,10,
  185.    GADGHNONE | GADGIMAGE,
  186.    GADGIMMEDIATE | FOLLOWMOUSE ,
  187.    PROPGADGET | REQGADGET,
  188.    (APTR)&Knob4 ,
  189.    NULL,
  190.    &DayText,
  191.    NULL,
  192.    (APTR)&DayInfo,
  193.    IDDAY,
  194.    NULL
  195.   };
  196.  
  197. static struct Gadget MonthGadget = {
  198.    &DayGadget,
  199.    5,100,360,10,
  200.    GADGHNONE | GADGIMAGE,
  201.    GADGIMMEDIATE | FOLLOWMOUSE ,
  202.    PROPGADGET | REQGADGET,
  203.    (APTR)&Knob5 ,
  204.    NULL,
  205.    &MonthText,
  206.    NULL,
  207.    (APTR)&MonthInfo,
  208.    IDMONTH,
  209.    NULL
  210.   };
  211.  
  212. /* This gadget differs from the above because it is a boolean */
  213. /* gadget and not a slider.  Note that it has a flag which    */
  214. /* tells Intuition to get rid of the requester. */
  215. static struct Gadget SetTime = {
  216.    &MonthGadget,
  217.    5,120,30,10,
  218.    GADGHCOMP ,
  219.    GADGIMMEDIATE | ENDGADGET ,
  220.    BOOLGADGET | REQGADGET,
  221.    (APTR)&Box1 ,
  222.    NULL,
  223.    &SetTimeText,
  224.    NULL,
  225.    NULL,
  226.    IDSETTIME,
  227.    NULL
  228.   };
  229.  
  230. /* Here is the requester data structure.  Note that it 'stores' the */
  231. /* gadgets defined above by pointing to the start of the linked list */
  232. /* of gadgets. */
  233. static struct Requester SetReq= {
  234.    NULL,
  235.    5,40,
  236.    390,140,
  237.    NULL,NULL,
  238.    &SetTime,
  239.    NULL,
  240.    NULL,
  241.    NULL,
  242.    0,
  243.    NULL,
  244.    {NULL},
  245.    {NULL},
  246.    NULL,
  247.    {NULL}
  248.   };
  249.  
  250. /* This function takes the current settings of the date/time */
  251. /* variables and formats/displays the information at the top */
  252. /* of the window in which the requester appears. */
  253. void DisplayDateTime(Month,Day,Year,Hour,Minute)
  254.   int Month,Day,Year,Hour,Minute;
  255.   {
  256.    /* We need to reserve space for the sprintf() function to */
  257.    /* write into. */
  258.  
  259.    static char DispString[]="                                ";
  260.    char *DayModifier="th",*HalfDay="a.m.";
  261.  
  262.    /* This section of code assigns the correct ending to the */
  263.    /* day number (e.g., '1st', '2nd', etc.). */
  264.  
  265.    if(Day>=10 && Day<20)
  266.      DayModifier="th";
  267.    else
  268.      {
  269.       switch(Day%10)
  270.         {
  271.          case 1:
  272.            DayModifier="st";
  273.            break;
  274.          case 2:
  275.            DayModifier="nd";
  276.            break;
  277.          case 3:
  278.            DayModifier="rd";
  279.            break;
  280.          default:
  281.            DayModifier="th";
  282.            break;
  283.        }
  284.      }
  285.  
  286.    /* Here we set the a.m./p.m. 'flag'.  Note that we adjust */
  287.    /* the value of Hour, which arrives in 24 hour military   */
  288.    /* format, to be consistent with a 12 hour a.m./p.m. format. */
  289.  
  290.    if((Hour>=0 && Hour<12) || Hour==24)
  291.      {
  292.       HalfDay="a.m.";
  293.       if(Hour==0 || Hour==24)
  294.         Hour=12;
  295.      }
  296.    else
  297.      {
  298.       HalfDay="p.m.";
  299.       if(Hour!=12)
  300.         Hour-=12;
  301.      }
  302.  
  303.    /* Here's where we glom all the info together to form a string. */
  304.    /* Note that the string is then padded to always make it the same */
  305.    /* length.  This makes sure you always completely write-over */
  306.    /* whatever stuff you wrote previously. */
  307.  
  308.    sprintf(&DispString,"%s %d%s, %d  %d:%02d %s",MName[Month],Day,DayModifier,Year,Hour,Minute,HalfDay);
  309.    while(strlen(&DispString)<32)
  310.      strcat(&DispString," ");
  311.  
  312.    /* Here's where we actually write the string to the window. */
  313.    Move(SetWindow->RPort,5,20);
  314.    Text(SetWindow->RPort,&DispString,32);
  315.   }
  316.  
  317. /* This function returns a value meaningful to humans from whatever */
  318. /* unsigned 16 bit value is sent by Intuition to describe the current */
  319. /* location of the slider. */
  320. int GetPotVal(PickedGadget)
  321.   struct Gadget *PickedGadget;
  322.   {
  323.    static int PotMult[]={60,24,MAXYEARS,31,12};
  324.    int temp;
  325.    USHORT PotVal;
  326.    struct PropInfo *PickedProp;
  327.    
  328.    /* Here we get a pointer to the currently selected gadget. */
  329.    /* I tried to do this all in one step but for some reason  */
  330.    /* it didn't work... */
  331.    PickedProp=(struct PropInfo *)PickedGadget->SpecialInfo;
  332.    
  333.    /* The unsigned value representing the gadget's location. */
  334.    PotVal=(PickedProp->HorizPot);
  335.    
  336.    /* This converts the unsigned value to meaningful data. */
  337.    temp=(PotVal*PotMult[PickedGadget->GadgetID])>>16;
  338.    return(temp);
  339.   }
  340.  
  341. /* This function lets us exit gracefully, with some indication */
  342. /* of what went wrong (if anything did).  Normally I wouldn't  */
  343. /* include this, since printf's expand a program file a LOT,   */
  344. /* but I used sprintf() up above so why not...                 */
  345. void Cleanup(Level)
  346.   int Level;
  347.   {
  348.    /* Level is an error code.  See main() for context. */
  349.    if(Level>3)
  350.      CloseWindow(SetWindow);
  351.    if(Level>2)
  352.      CloseLibrary(IntuitionBase);
  353.    if(Level>1)
  354.      CloseLibrary(GfxBase);
  355.    switch(Level)
  356.      {
  357.       case 1:
  358.         printf("Graphics library would not open.\n");
  359.         break;
  360.       case 2:
  361.         printf("Intuition library would not open.\n");
  362.         break;
  363.       case 3:
  364.         printf("Window would not open.\n");
  365.         break;
  366.       case 4:
  367.         printf("Requester would not open.\n");
  368.         break;
  369.      }
  370.    exit(0);
  371.   }
  372.   
  373. /* The main banana. */
  374. main()
  375.   {
  376.    int temp,*ChgVal,Minute,Hour,Year,Day,Month;
  377.    static char SetCmd[]="                ";
  378.    ULONG class;
  379.    struct Gadget *CurGadget;
  380.    
  381.    /* Information needed by Intuition to open the window in which */
  382.    /* the requester appears.  Note that you also need to set the  */
  383.    /* window to pass mouse motion and gadget selection reports.   */
  384.    /* REQCLEAR means 'Hey, Intuition, tell us when the requester  */
  385.    /* got sent away', i.e., when user wants to set date/time.*/
  386.  
  387.    static struct NewWindow newSetWindow = {
  388.       10,10,
  389.       500,180,
  390.       0,1,
  391.       GADGETDOWN | MOUSEMOVE | REQCLEAR,
  392.       WINDOWDRAG | SMART_REFRESH | NOCAREREFRESH | ACTIVATE, 
  393.       NULL,
  394.       NULL,
  395.       "AmigaDOS Time and Date Setting Screen",
  396.       NULL,
  397.       NULL,
  398.       NULL,NULL,
  399.       NULL,NULL,
  400.       WBENCHSCREEN
  401.      };
  402.  
  403.    /* A data structure needed by the AmigaDos date/time function */
  404.  
  405.    struct DateStamp DosDate;
  406.  
  407.    /* Here we open the various libraries.  Note error codes passed */
  408.    /* to Cleanup() if something goes wrong. */
  409.  
  410.    if((GfxBase=(int *)OpenLibrary("graphics.library",1))==NULL)
  411.      Cleanup(1);
  412.    if((IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",1))==NULL)
  413.      Cleanup(2);
  414.    if((SetWindow=OpenWindow(&newSetWindow))==NULL)
  415.      Cleanup(3);
  416.  
  417.    /* Get the current date and time from AmigaDos.  Unfortunately, */
  418.    /* it comes back in a very unuseful form.  So we pass it through */
  419.    /* the FromDosDate function, which converts it into a more useful */
  420.    /* format.  Afterwards, we subtract one from the month number */
  421.    /* because the MName array expects a value range of 0..11 */
  422.  
  423.    DateStamp(&DosDate);
  424.    FromDosDate(&DosDate,&Month,&Day,&Year,&Hour,&Minute,&temp);
  425.    --Month;
  426.  
  427.    /* Bump the minute counter if we are more than 30 seconds into */
  428.    /* the current minute. */
  429.   
  430.    if(temp>=30)
  431.      ++Minute;
  432.    
  433.    /* Here we set the size of the slider controls. */
  434.  
  435.    MinuteInfo.HorizBody=0xFFFF/60;
  436.    HourInfo.HorizBody=0xFFFF/24;
  437.    YearInfo.HorizBody=0xFFFF/30;
  438.    DayInfo.HorizBody=0xFFFF/31;
  439.    MonthInfo.HorizBody=0xFFFF/12;
  440.  
  441.    /* Here we set the current date and time into the sliders so */   
  442.    /* that they will start out in the 'correct' positions. */
  443.  
  444.    MinuteInfo.HorizPot=MinuteInfo.HorizBody*Minute;
  445.    HourInfo.HorizPot=HourInfo.HorizBody*Hour;
  446.    YearInfo.HorizPot=YearInfo.HorizBody*(Year-BASEYEAR);
  447.    DayInfo.HorizPot=DayInfo.HorizBody*Day;
  448.    MonthInfo.HorizPot=MonthInfo.HorizBody*Month;
  449.  
  450.    /* Before going into the event processing loop, show the */   
  451.    /* date and time as returned by AmigaDos */
  452.  
  453.    DisplayDateTime(Month,Day,Year,Hour,Minute);
  454.  
  455.    /* Here we try and set up the requester. */
  456.  
  457.    if(Request(&SetReq,SetWindow)==FALSE)
  458.      Cleanup(4);
  459.  
  460.    /* The event processing loop.  We run it forever.  Actually, */
  461.    /* only until the requester goes away. */
  462.  
  463.    for(;;)
  464.      {
  465.  
  466.       /* Put the program to bed until Intuition sends us a message. */
  467.       /* That funny argument in the function says 'wait until a     */
  468.       /* certain bit in the message area turns on' (which signifies */
  469.       /* a message).  The particular bit -- the Intuition Direct    */
  470.       /* Communication Message Port bit (I did NOT make up that name)*/
  471.       /* -- is mp_SigBit's into the (32?) bit message area.  You    */
  472.       /* get the value of mp_SigBit, which is set by Intuition when */
  473.       /* it opens your window, from a data structure pointed to by  */
  474.       /* the window data structure. */
  475.       
  476.       Wait(1<<SetWindow->UserPort->mp_SigBit);
  477.       
  478.       /* Here we process messages so long as they continue to arrive. */
  479.       /* After that, we go back to sleep. */
  480.  
  481.       while(IDCMPmesg=GetMsg(SetWindow->UserPort))
  482.         {
  483.         
  484.          /* Messages come in different classes -- and you need to */ 
  485.          /* reply to them ASAP, particularly mouse movement       */
  486.          /* messages, because Intuition holds onto all messages   */
  487.          /* until you reply to them.  Which can burn up a LOT of  */
  488.          /* memory.  Actually, I think there are some occasions   */
  489.          /* where you can not reply -- but I KNOW there are also  */
  490.          /* some where not replying calls in the Guru! */
  491.  
  492.          class=IDCMPmesg->Class;
  493.          ReplyMsg(IDCMPmesg);
  494.          
  495.          /* We have only 2 classes of events -- but Intuition views */
  496.          /* them as three.  The 2 which are one so far as this      */
  497.          /* program is concerned are 'gadget picked' and 'mouse     */
  498.          /* moved'.  The reason these are the 'same' class here is  */
  499.          /* that whenever the mouse moves we want to see if we need */
  500.          /* to update the displayed date/time (i.e., the user may   */
  501.          /* have dragged the slider. */
  502.         
  503.          if(class==GADGETDOWN || class==MOUSEMOVE)
  504.            {
  505.             if(class==GADGETDOWN)
  506.                CurGadget=(struct Gadget *)(IDCMPmesg->IAddress);
  507.                
  508.             /* Ignore the message that the user wants to set date */
  509.             /* and time, since it is also heralded by a 'requester */
  510.             /* went away' message. */
  511.            
  512.             if(CurGadget->GadgetID<IDSETTIME || class==MOUSEMOVE)
  513.               {
  514.               
  515.                /* Otherwise, get the current setting and do whatever */
  516.                /* special processing is needed.  We store the setting */
  517.                /* in ChgVal so that we can compare it to the last    */
  518.                /* similar setting -- thus avoiding writing to the    */
  519.                /* screen except when absolutely necessary.  This     */
  520.                /* reduces flicker. 'ChgVal' is the base value which */
  521.                /* we will be comparing to.value.  'Temp' is the     */
  522.                /* <possibly> changed value just returned. */
  523.  
  524.                temp=GetPotVal(CurGadget);
  525.                switch(CurGadget->GadgetID)
  526.                  {
  527.                   case IDMINUTE:
  528.                     ChgVal=&Minute;
  529.                     break;
  530.                   case IDHOUR:
  531.                     ChgVal=&Hour;
  532.                     break;
  533.                   case IDYEAR:
  534.                     ChgVal=&Year;
  535.                     
  536.                     /* We need to add BASEYEAR to the returned value. */
  537.  
  538.                     temp+=BASEYEAR;
  539.                     
  540.                     /* If the year changed, get the current day setting */
  541.                     /* and see if we need to adjust for leap years. */
  542.  
  543.                     if(temp!=Year)
  544.                       {
  545.                        Day=GetPotVal(&DayGadget)+1;
  546.                        Day=LegalDays(Month,Day,temp);
  547.                       }
  548.                     break;
  549.                   case IDDAY:
  550.                     ChgVal=&Day;
  551.                     temp+=1;
  552.                     
  553.                     /* Make sure we 'max out' in 28/29/30 day months. */
  554.  
  555.                     temp=LegalDays(Month,temp,Year);
  556.                     break;
  557.                   case IDMONTH:
  558.                     ChgVal=&Month;
  559.                     
  560.                     /* If the month changed, we need to make sure we */
  561.                     /* don't have to change the displayed day due to */
  562.                     /* the different lengths of months. */
  563.  
  564.                     if(temp!=Month)
  565.                       {
  566.                        Day=GetPotVal(&DayGadget)+1;
  567.                        Day=LegalDays(temp,Day,Year);
  568.                       }
  569.                     break;
  570.                  }
  571.                  
  572.                /* Only display date and time if something changed. */
  573.  
  574.                if(*ChgVal!=temp)
  575.                  {
  576.                   *ChgVal=temp;
  577.                   DisplayDateTime(Month,Day,Year,Hour,Minute);
  578.                  }
  579.               }
  580.            }
  581.            
  582.          /* If the requester went away, set the date and time and */
  583.          /* end the program. */
  584.  
  585.          if(class==REQCLEAR)
  586.            {
  587.  
  588.             /* Build the command string... */
  589.  
  590.             sprintf(&SetCmd,"date %.2d-%.3s-%d %d:%02d",Day,MName[Month],Year%100,Hour,Minute); 
  591.  
  592.             /* and Execute() it! */
  593.  
  594.             Execute(&SetCmd,0,0);
  595.             Cleanup(5);
  596.            }
  597.         } /* End of handling IDCMP message */
  598.      } /* End of set event processing */               
  599.   }
  600.