
          [42m                                          [40m
          [42m     Remembering Tomorrow                 [40m
          [42m     One problem ... Two solutions ...    [40m
          [42m                                          [40m

                      [33;3mby John Collett[0m

        ----------------------------------------------------------
       |   This is either :  An ARexx tutorial dressed up         |
       |                     to look like something useful        |
       |                                                          |
       |               Or :  Something which could be useful      |
       |                     pretending to be an ARexx tutorial   |
        ----------------------------------------------------------


[32m   <> 34 <%> 34 <%> 34 <%> 34 <%> 34 <%> 34 <%> 34 <%> 34 <%> 34 <%> 34 <>
[0m

    [42m  The Problem  [40m

    I have tried programs such as 'Badger' and 'Nag', but have not adopted
    any of them as a permanent feature of my setup because they don't
    provide exactly what I want. I normally use my Amiga every day, at any
    time of the day, but when, at certain times of the year, the workload
    in my regular employment gets heavier than average, it may well be the
    evening before I get round to switching on the machine.  In the busy
    season, it is tomorrow rather than today that I need to be reminded
    about.  One clumsy method of achieving that is to write entries in the
    data file in such a way that they always refer to the next day.  In the
    end, I decided to write my own program, one that would :

         1   Work at startup.
         2   Work only once a day.
         3   Remind me about today [4mand[0m tomorrow.
         4   Do nothing if the relevant file of reminders contained
             no entry for those days.
         5   Be readily available at all times (2 notwithstanding).
         6   Be easy to use.


   [42m  Two Solutions  [40m

    I've written two very similar versions, for non-owners and owners of
    HyperBook respectively.  The first is an ARexx program which can be run
    from startup and from CLI (or from an icon if that's how you do
    things).

    The second, written in ARexx and HML (HyperBook Macro Language), also
    runs at startup, or it can be run from a click in a menu list.
    This is the one I have adopted for regular use, because, as described
    in MD32, I always have HyperBook running as my custom-designed
    WorkBench equivalent.

    Before we look at the code in any detail, one or two preliminary
    observations may be helpful.

   [42m  Dates  [40m

    The date() function in ARexx can take up to three arguments.  For just
    the first argument (as in date('n'), which is the default), 12
    different values are possible : b, c, d, e, i, j, m, n, o, s, u, w.
    The letters stand for Base, Century, Days, European, Internal, Julian,
    Month, Normal, Ordered, Standard, USA, and Weekday - and that's all
    I'll say about most of them here.  The default 'n' for Normal yields dd
    mmm yyyy, as in 21 Sep 1993.  The only other one used in the coding
    below is 's' for Standard, that is, yyyymmdd, as in 19930921.

    The second and third arguments of the date() function need to be used
    if a date other than today is to be specified.  If the second argument
    is a date in standard format, then 's' is required as the third
    argument, and the function returns the requested format for that date.
    For example, [32mdate('n',19930921,'s')[31m yields 21 Sep 1993.

    Only 's' or the default value 'i' are allowed for the third argument,
    which means that you can specify a date other than today only in the
    'Standard' form as just described or as 'Internal' (the number of days
    since 01/01/1978 (?), the conventional Amiga start date).

    A lot more could be said about the versatile date() function, but the
    preceding lines are enough to explain the use we'll be making of it
    below.

    [42m  File 1 : To contain all your reminders  [40m

    An imaginatively named file, 'datelist', needs to be constructed to
    hold whatever it is you want to be reminded about.  I put mine in the
    'S:' directory, but one of the beauties about ARexx is the ease with
    which it can be adjusted.  You can easily name 'datelist' whatever you
    like and store it wherever you like, as long as your program specifies
    it accurately.

    In 'datelist', any line which starts with a four-character numeric
    string, mmdd, as in 0921, is the beginning of an entry for a date.
    That particular type of date entry has much to commend it, since we
    are interested in 'a date other than today', namely, tomorrow.
    To get at that, we need to use the three-argument version of the date()
    function, and in particular want to be able to 'add 1' to today's date,
    even if it's the last day of the month, and get a sensible value in
    return.

    This little patch, which adds five days, one at a time, starting at
    Feb 26, shows what I mean :
                                                    Its output
       [32mday = 19930225                  [31m       -->     0226
       [32mdo 5                            [31m      |        0227
       [32m  i = right(date('s',day,'s'),4)[31m      |        0228
       [32m  day = day + 1                 [31m      |        0301
       [32m  say i   [31m ---------------------------         0302
       [32m  end     [31m

    Add 1 to Feb 28, and (in 1993) you get March 1.  The year needn't
    bother us for our input and output (though I do use it in a cosmetic
    way in the program), but obviously the four-character mmdd entry and
    its ease of conversion are useful for a program which always wants to
    know about today's [4mand[0m tomorrow's date.

    The arrangement of entries in 'datelist' can be like this :

       [32m0921 This four-line note will appear on Sept 20 and 21.
       [32mOn its first appearance it will remind me about
       [32mwhat I have to remember for tomorrow.
       [32mOn its second, it will be about today.
       [32m1005 A reminder I need for October 5.
       [32mIt'll first appear on October 4.
       [32m1101 A single line dated November 1
       [32m1225 Xmas Day.

    If the file contains no relevant entries, the Reminder program exits
    without any visible effect.

    [42m  File 2 :  To inhibit further runs on a given day  [40m

    ARexx contains the statef() function, which returns
    this kind of string :
                                FILE 2853 3 ----RWED 5611 888 1457 com
                                 |    |   |     |     |    |   |   |
    Type (FILE or DIR) ----------     |   |     |     |    |   |   |
    Size in bytes --------------------    |     |     |    |   |   |
    Size in blocks -----------------------      |     |    |   |   |
    Protection bits ----------------------------      |    |   |   |
    Creation date in days since 'Internal' date ------     |   |   |
    Creation time in minutes since midnight ---------------    |   |
    Creation time in ticks (1/50 sec) within the minute -------    |
    File note, if any ---------------------------------------------

    I use this, parsing out the creation date element and ignoring the
    rest, to find out whether or not the Reminder program has already been
    used today.  Each time it runs, the program creates a tiny (empty) file
    's:today', but before it does that, it checks the creation date of any
    existing file of that name. If that date is today, the program exits
    (unless an additional argument has been used - see below).

    If the 'today' file does not exist (the first time used) then it is
    created, in 'S:', and this is the only demand the program imposes on
    your system other than the 'datelist' which you have to put there
    yourself.

    [42m  Availability after startup  [40m

    If installed, the program will run at startup, and exit immediately if
    it has already run today or if it has no entries for today or
    tomorrow.  What if you [4mwant[0m to run it again today?  From CLI,
    the command 'rx Reminder' (no quotes) will run it, and if you add
    [4many argument whatsoever[0m to that command, e.g. 'rx Reminder 1',
    then it will not exit, even if it has already run today.  It will
    still produce nothing, of course, if there are no relevant entries.

    [42m  Size and position of output  [40m

    The console window which this version produces will be wide enough to
    accept the longest line of its output (minimum 200 pixels, to
    accommodate the date heading), and deep enough to display everything it
    has to.  It will be centred horizontally, with its top at 60 pixels
    down, though it would be easy to centre it vertically if you wanted to.

    [42m  Removal  [40m

    When you have read your reminders, press Return or click on the
    window's close gadget.

    Here is the full text of the program, and a few explanatory comments.

  [42m  /* Reminder                                               */[40m
  [42m  /* Version 1  ARexx Program  Opens its own console window */[40m

   [32m /* Reasons to exit immediately :
   [32m           Store exists, and holds today's date
   [32m     And : No argument was added to the 'rx' command */
    store = 's:today'
    if exists(store) then do
      parse value statef(store) with a a a a day a a a
   [32m   /* The 'a's are dummies.  We only want 'day' */
      today = date('s')
      if ( date('s',day,'i') = today ) & (arg() = 0) then exit
    end

   [32m /* Recreate 'store', with today as creation date */
    op = open(td,store,'w') ; cl = close(td)

   [32m /* Set up four-char 'today' and 'tomorrow' variables  */
    today = right(date('s'),4)
    tomorrow = right(date('s',date('s')+1,'s'),4)

   [32m /* Initialisations */
    year = left(date('s'),4)
    longest = 200 ; linecount = 0 ; str1 = '' ; str2 = ''

   [32m /* Get both day's entries from 'datelist'  */
    op = open(dl,'s:datelist','r') ; if op = 0 then exit
    call DateEntry(today) ; if entry ~= '' then str1 = entry
    s = seek(dl,0,'b')        /* Back to start for second scan */
    call DateEntry(tomorrow) ; if entry ~= '' then str2 = entry
    cl = close(dl)

   [32m /* Work out window position and size */
    if str1 ~= '' | str2 ~= '' then do
      h = (linecount + 2) * 9 ; w = longest + 32 ;lft = (630 - w)%2
      params = lft ||'/60/' || w || '/'|| h

   [32m /* Open window.
   [32m    Display dates and entries for either or both days */
      window = open(con,'con:' || params ||'/Reminders/CLOSE')
      if str1 ~= '' then do
        t = writeln(con,'  Today    ' || date('n',year || today,'s'))
        t = writeln(con,'9b'x || '32m' || str1 || '9b'x || '31m')
        end
      if str2 ~= '' then do
        t = writeln(con,'  Tomorrow ' || date('n',year || tomorrow,'s'))
        t = writeln(con,'9b'x || '32m' || str2 || '9b'x || '31m')
        end

   [32m /* Wait for Return key or a click on Close gadget */
      out = readch(con)
      end                  /* end of "if str1 ~= '' | str2 ~= ''" */
    exit

   [32m /*  A function to obtain today's and tomorrow's entries */
    DateEntry:
      do until eof(dl)

   [32m    /* Look for dated entry in 'datelist' */
       entry = readln(dl)
       date = left(entry,4)
       if date = arg(1) then do

   [32m      /* Get at least the one line */
         linecount = linecount + 1 ; entry = substr(entry,6)
         longest = max(longest,length(entry)*8)
         more = ''
         do forever

   [32m        /* Until another dated line (or eof) is found */
           linecount = linecount + 1 ;  more = readln(dl)
           if ( datatype(left(more,4),n) | eof(dl) ) then leave
           longest = max(longest,length(more)*8)

   [32m        /* Concatenate into one string containing linefeeds */
           entry = entry || '0a'x || more
           end           /* of 'do forever' */
         leave
         end             /* of 'if date'    */
       end               /* of 'do until'   */
    return entry

                -----------------------------------

    [42m/* Reminder                                               */[40m
    [42m/* Version 2  ARexx and HyperBook                         */[40m

    The following description of the Hyperbook version of Reminder will
    cover only those aspects which are not the same as in Version 1.
    Only patches of code are provided here, but inserting them as required
    to replace parts of the above script is fairly straightforward.

    HyperBook scripts may contain macros.  Those macros may be activated
    by key or mouse actions, or by several other more subtle means.
    If there is a macro called 'PageEntryMacro' it will be executed
    whenever a new page is entered.  It can either carry out some action
    which you want to happen on every page, or it can check the page
    number concerned and be selective in what it does.  My version runs
    the Reminder program on page 1 only, under the same conditions as
    described for Version 1.

    Page 1 contains a 'List' which holds my day-to-day menu, and one of
    its entries is 'Reminder'.  If I click on that list item, the Reminder
    program will run irrespective of any earlier run the same day.

    [32mif CurrentPage() ~= '1:' then exit [31m

    [32m DoAnyWay = 0 ; it = initiator()
    [32m if it ~= '' then
    [32m DoAnyWay = (GetType(it) = 'Item') & (GetItemText(it) = 'Reminder')

    [31mAfter the 'today' check :
    [32m if ( date('s',day,'i') = today ) & (DoAnyWay = 0) then exit [31m

    Initializations and the reading-in of any entries via the DateEntry()
    function are all as in the CLI version. The parameters for the window
    become the width, height, and position for a HyperBook 'Note' which
    displays the reminder texts, and the 'Action' set for the 'Note' is to
    delete itself.  You just have to click on it when you've seen what you
    want to see, and it disappears.

    There are two approaches to the creation of the 'Note' in which the
    text is displayed.  If you use the CreateNote() function, the new
    note inherits the 'Text control' and 'Spacing' attributes of any
    previously made note, whatever they happen to be.  If, like me, you
    prefer to have tighter control over the details of the appearance of
    the reminder note, an alternative method is to store a sample note
    somewhere on page 1, and then make a clone from it:

     [32m   newnote = Clone(arg,'0:')  [31m

    I'll spell out in a bit more detail one way of doing that :

     - Make a HyperBook 'Note'
     - Put the word 'Sample' in it for easy identification
     - Ascertain its 'objnum' :  [32m  obj = SearchText(':','Sample') [31m
     - Using the built-in editors, set every detail of its appearance
       (colour, shadow, style, and spacing) exactly how you want them to
       be for your reminders.
     - Drag the 'Sample' note away into a corner, out of the way, and make
       it invisible :  [32mcall SetVisibility(obj,0) [31m
     - At any time you can make a Clone of that note (preferably in the
       bin) with :  [32m newnote = Clone(obj,'0:')  [31m

    The clone will have exactly the same attributes as the sample, and be
    ready for the macro to insert the required text and assign its size and
    position as required.  Unlike the '60 pixels down' of the CLI version,
    my HB version places the reminder note centrally at the foot of the
    screen.

    Instead of the "Open window" patch in Version 1, by which point,
    remember, the size and position parameters have been defined, the
    HyperBook version can have something like :

     [32m  obj = SearchText(':','Sample')
     [32m  note = Clone(obj,'0:')
     [32m  call ScaleToSize(note,w,h)
     [32m  call SetPosition(note,lft,245 - h)
     [32m  call InsertText(note,str1 || '0a'x || str2,0)
     [32m  call SetActionRexx(note,'call HML_Delete(initiator())')
     [32m  new = Relocate(note,':')   /* From the bin to the page */
     [32m  end
     [32mexit [31m

                    ---------------------------

    One year I forgot my wife's birthday.
    I think I have slightly reduced the chances of that happening again.


    [33;3mHamilton, New Zealand  May, 1993[0m

                    ---------------------------


[32m   <> 34 <%> 34 <%> 34 <%> 34 <%> 34 <%> 34 <%> 34 <%> 34 <%> 34 <%> 34 <>
[0m

