home *** CD-ROM | disk | FTP | other *** search
/ Dream 52 / Amiga_Dream_52.iso / Linux / Divers / remind-03.00.19.tgz / remind-03.00.19.tar / remind-03.00.19 / scripts / tkremind < prev   
Text File  |  1998-04-30  |  75KB  |  2,472 lines

  1. #!/bin/sh
  2. # -*-Mode: TCL;-*-
  3.  
  4. #--------------------------------------------------------------
  5. #   TKREMIND
  6. #
  7. #   A cheesy graphical front/back end for Remind using Tcl/Tk
  8. #
  9. #   This file is part of REMIND.
  10. #   Copyright (C) 1992-1998 by David F. Skoll
  11. #
  12. #--------------------------------------------------------------
  13.  
  14. # $Id: tkremind,v 1.20 1998/05/01 02:19:52 dfs Exp $
  15.  
  16. # the next line restarts using wish \
  17. exec wish "$0" "$@"
  18.  
  19. wm withdraw .
  20.  
  21. # Check that we have the right version of wish
  22. if {$tcl_version < 8.0} {
  23.     tk_dialog .error Error "You need wish version 8.0 or higher to run TkRemind; you have $tcl_version" error 0 OK
  24.     exit 1
  25. }
  26.  
  27. if {$tcl_platform(platform) == "windows"} {
  28.     tk_dialog .error Error "You are not allowed to run Remind under Windows" error 0 OK
  29.     exit 1
  30. }
  31. #---------------------------------------------------------------------------
  32. # GLOBAL VARIABLES
  33. #---------------------------------------------------------------------------
  34.  
  35. set Option(ConfirmQuit) 0
  36. set OptDescr(ConfirmQuit) "(0/1) If 1, TkRemind prompts you to confirm 'Quit' operation"
  37. set Option(AutoClose) 1
  38. set OptDescr(AutoClose) "(0/1) If 1, TkRemind automatically closes pop-up reminders after a minute"
  39. set Option(RingBell) 0
  40. set OptDescr(RingBell) "(0/1) If 1, TkRemind beeps the terminal when a pop-up reminder appears"
  41.  
  42. set Option(StartIconified) 0
  43. set OptDescr(StartIconified) "(0/1) If 1, TkRemind starts up in the iconified state"
  44.  
  45. set Option(Deiconify) 0
  46. set OptDescr(Deiconify) "(0/1) If 1, TkRemind deiconifies the calendar window when a reminder pops up"
  47.  
  48. set Option(RunCmd) ""
  49. set OptDescr(RunCmd) "(String) If non-blank, run specified command when a pop-up reminder appears"
  50. set Option(FeedReminder) 0
  51. set OptDescr(FeedReminder) "(0/1) If 1, feed the reminder to RunCmd on standard input (see RunCmd option)"
  52.  
  53. # Remind program to execute -- supply full path if you want
  54. set Remind "remind"
  55. #set Remind "/home/dfs/Remind/src/remind"
  56.  
  57. # Rem2PS program to execute -- supply full path if you want
  58. set Rem2PS "rem2ps"
  59.  
  60. # Reminder file to source -- default
  61. set ReminderFile {NOSUCHFILE}
  62. set ReminderFile [file nativename "~/.reminders"]
  63.  
  64. # Reminder file to append to -- default
  65. set AppendFile {NOSUCHFILE}
  66. catch {set AppendFile $ReminderFile}
  67.  
  68. #---------------- DON'T CHANGE STUFF BELOW HERE ------------------
  69.  
  70. # Is Monday in first column?
  71. set MondayFirst 0
  72.  
  73. # Month names in English
  74. set MonthNames {January February March April May June July August September October November December}
  75.  
  76. # Day names in Remind's pre-selected language
  77. set DayNames {}
  78.  
  79. # Day name in English
  80. set EnglishDayNames {Sunday Monday Tuesday Wednesday Thursday Friday Saturday}
  81.  
  82. # Current month and year -- will be set by Initialize procedure
  83. set CurMonth -1
  84. set CurYear -1
  85.  
  86. # Background reminder counter
  87. set BgCounter 0
  88.  
  89. # Absolutely today -- unlike the CurMonth and CurYear, these won't change
  90. set TodayMonth -1
  91. set TodayYear -1
  92. set TodayDay -1
  93.  
  94. # Reminder option types and skip types
  95. set OptionType 1
  96. set SkipType 1
  97.  
  98. # Remind command line
  99. set CommandLine {}
  100. set PSCmd {}
  101.  
  102. # Print options -- destination file; letter-size; landscape; fill page
  103. set PrintDest file
  104. set PrintSize letter
  105. set PrintOrient landscape
  106. set PrintFill 1
  107.  
  108. # Highest tag seen so far.  Array of tags is stored in ReminderTags()
  109. set HighestTagSoFar 0
  110.  
  111. #***********************************************************************
  112. # %PROCEDURE: Initialize
  113. # %ARGUMENTS:
  114. #  None
  115. # %RETURNS:
  116. #  Nothing
  117. # %DESCRIPTION:
  118. #  Initializes TkRemind -- sets day names, Remind command line,
  119. #  MondayFirst flag, current date, etc.
  120. #***********************************************************************
  121. proc Initialize {} {
  122.  
  123.     global DayNames argc argv CommandLine ReminderFile AppendFile Remind PSCmd
  124.     global MondayFirst
  125.  
  126.     set CommandLine "|$Remind -itkremind=1 -p"
  127.     set PSCmd "$Remind -p"
  128.     set i 0
  129.     while {$i < $argc} {
  130.     if {[regexp -- {-[bgxim].*} [lindex $argv $i]]} {
  131.         append CommandLine " [lindex $argv $i]"
  132.         append PSCmd " [lindex $argv $i]"
  133.         if {[regexp -- {m} [lindex $argv $i]]} {
  134.         set MondayFirst 1
  135.         }
  136.     } else {
  137.         break
  138.     }
  139.     incr i
  140.     }
  141.     if {$i < $argc} {
  142.     set ReminderFile [lindex $argv $i]
  143.     set AppendFile $ReminderFile
  144.     incr i
  145.     if {$i < $argc} {
  146.         set AppendFile [lindex $argv $i]
  147.         incr i
  148.     }
  149.     }
  150.  
  151.     # Check system sanity
  152.     if {! [file readable $ReminderFile]} {
  153.     set ans [tk_dialog .error "TkRemind: Warning" "Can't read reminder file `$ReminderFile'" warning 0 "Create it and continue" "Exit"]
  154.     if {$ans != 0} {
  155.         exit 1
  156.     }
  157.     catch {close [open "$ReminderFile" w]}
  158.     }
  159.     if {! [file readable $ReminderFile]} {
  160.     tk_dialog .error "TkRemind: Error" "Could not create reminder file `$ReminderFile'" error 0 "Exit"
  161.     exit 1
  162.     }
  163.  
  164.     if {! [file writable $AppendFile]} {
  165.     tk_dialog .error Error "Can't write reminder file `$AppendFile'" error 0 Ok
  166.     exit 1
  167.     }
  168.  
  169.     append CommandLine " $ReminderFile"
  170.     append PSCmd " $ReminderFile"
  171.     set DayNames [GetWeekdayNames]
  172. #   puts "CommandLine: $CommandLine"
  173. }
  174.  
  175. #---------------------------------------------------------------------------
  176. # GetWeekdayNames - Spawn a remind process and get the names of the weekdays
  177. # Also sets CurMonth and CurYear.
  178. #---------------------------------------------------------------------------
  179. proc GetWeekdayNames {} {
  180.     global CurMonth CurYear TodayYear TodayMonth TodayDay Remind
  181.     set f [open "|$Remind - 2>/dev/null" r+]
  182.     puts $f "banner %"
  183.     set i 0
  184.     while { $i < 7 } {
  185.     puts $f "msg \[wkday($i)\]%"
  186.     incr i
  187.     }
  188.  
  189.     # Get current month and year as long as we're running Remind
  190.     puts $f "msg %n%"
  191.     puts $f "msg %y%"
  192.     puts $f "msg %d%"
  193.     puts $f "FLUSH"
  194.     flush $f
  195.     set ans {}
  196.     set i 0
  197.     while { $i < 7 } {
  198.     lappend ans [gets $f]
  199.     incr i
  200.     }
  201.     set CurMonth [expr [gets $f] - 1]
  202.     set CurYear [gets $f]
  203.     set TodayDay [gets $f]
  204.     set TodayMonth $CurMonth
  205.     set TodayYear $CurYear
  206.     close $f
  207.     return $ans
  208. }
  209.  
  210. #***********************************************************************
  211. # %PROCEDURE: CalEntryOffset
  212. # %ARGUMENTS:
  213. #  firstDay -- first day of month (0=Sunday, 6=Saturday)
  214. # %RETURNS:
  215. #  Offset mapping day numbers (1-31) to window numbers (0-41)
  216. # %DESCRIPTION:
  217. #  Computes offset from day number to window number
  218. #***********************************************************************
  219. proc CalEntryOffset { firstDay } {
  220.     global MondayFirst
  221.     if {$MondayFirst} {
  222.     incr firstDay -1
  223.     if {$firstDay < 0} {
  224.         set firstDay 6
  225.     }
  226.     }
  227.     return [expr $firstDay-1]
  228. }
  229.  
  230. #***********************************************************************
  231. # %PROCEDURE: CreateCalFrame
  232. # %ARGUMENTS:
  233. #  w -- name of frame window
  234. #  dayNames -- names of weekdays
  235. # %RETURNS:
  236. #  Nothing
  237. # %DESCRIPTION:
  238. #  Creates a frame holding a grid of labels and a grid of text entries
  239. #***********************************************************************
  240. proc CreateCalFrame { w dayNames } {
  241.     global MondayFirst
  242.     frame $w
  243.     for {set i 0} {$i < 7} {incr i} {
  244.     if {$MondayFirst} {
  245.         set index [expr ($i+1)%7]
  246.     } else {
  247.         set index $i
  248.     }
  249.         
  250.     label $w.day$i -text [lindex $dayNames $index] -justify center
  251.     grid configure $w.day$i -row 0 -column $i -sticky ew
  252.     }
  253.     for {set i 0} {$i < 6} {incr i} {
  254.     set n [expr $i*7]
  255.     for {set j 0} {$j < 7} {incr j} {
  256.         set f [expr $n+$j]
  257.         button $w.l$f -text "" -justify center -command "" \
  258.             -state disabled -relief flat
  259.         text $w.t$f -width 12 -height 5 -wrap word -relief flat \
  260.             -state disabled -takefocus 0 -cursor {}
  261.         $w.t$f tag bind TAGGED <Enter> "TaggedEnter $w.t$f"
  262.         $w.t$f tag bind TAGGED <Leave> "TaggedLeave $w.t$f"
  263.         $w.t$f tag bind TAGGED <ButtonPress-1> "EditTaggedReminder $w.t$f"
  264.         grid configure $w.l$f -row [expr $i*2+1] -column $j -sticky ew
  265.         grid configure $w.t$f -row [expr $i*2+2] -column $j -sticky nsew
  266.     }
  267.     }
  268.  
  269.     for {set i 0} {$i < 7} {incr i} {
  270.     grid columnconfigure $w $i -weight 1
  271.     }
  272.     for {set i 2} {$i < 14} {incr i 2} {
  273.     grid rowconfigure $w $i -weight 1
  274.     }
  275. }
  276.  
  277. #***********************************************************************
  278. # %PROCEDURE: ConfigureCalFrame
  279. # %ARGUMENTS:
  280. #  w -- window name of calendar frame
  281. #  firstDay -- first weekday of month
  282. #  numDays -- number of days in month
  283. # %RETURNS:
  284. #  Nothing
  285. # %DESCRIPTION:
  286. #  Sets up button labels; configures text justification
  287. #***********************************************************************
  288. proc ConfigureCalFrame { w firstDay numDays } {
  289.     global CurMonth CurYear TodayMonth TodayYear TodayDay
  290.     set offset [CalEntryOffset $firstDay]
  291.     set first [expr $offset+1]
  292.     set last [expr $offset+$numDays]
  293.  
  294.     for {set i 0} {$i < $first} {incr i} {
  295.     grid $w.l$i $w.t$i
  296.     $w.l$i configure -text "" -command "" -state disabled -relief flat
  297.     $w.t$i configure -relief flat -takefocus 0 -state normal
  298.     $w.t$i delete 1.0 end
  299.     $w.t$i configure -state disabled
  300.     $w.t$i configure -background [lindex [$w.t$i configure -background] 3]
  301.     $w.l$i configure -background [lindex [$w.l$i configure -background] 3]
  302.     }
  303.     for {set i $first} {$i <= $last} {incr i} {
  304.     grid $w.l$i $w.t$i
  305.     set d [expr $i-$first+1]
  306.     $w.l$i configure -text $d -state normal -relief flat \
  307.         -command "ModifyDay $d $firstDay"
  308.     $w.t$i configure -relief sunken -takefocus 1 -state normal
  309.     $w.t$i delete 1.0 end
  310.     $w.t$i configure -state disabled
  311.     $w.t$i configure -background [lindex [$w.t$i configure -background] 3]
  312.     $w.l$i configure -background [lindex [$w.l$i configure -background] 3]
  313.     }
  314.     set forgetIt 0
  315.     for {set i [expr $last+1]} {$i < 42} {incr i} {
  316.     if {$i%7 == 0} {
  317.         set forgetIt 1
  318.     }
  319.     set row [expr ($i/7)*2+1]
  320.     if {$forgetIt} {
  321.         grid remove $w.l$i $w.t$i
  322.         grid rowconfigure $w $row -weight 0
  323.         grid rowconfigure $w [expr $row+1] -weight 0
  324.     } else {
  325.         grid rowconfigure $w [expr $row+1] -weight 1
  326.     }
  327.     $w.l$i configure -text "" -command "" -state disabled -relief flat
  328.     $w.t$i configure -relief flat -takefocus 0 -state normal
  329.     $w.t$i delete 1.0 end
  330.     $w.t$i configure -state disabled
  331.     $w.t$i configure -background [lindex [$w.t$i configure -background] 3]
  332.     $w.l$i configure -background [lindex [$w.l$i configure -background] 3]
  333.     }
  334.     if { $CurMonth == $TodayMonth && $CurYear == $TodayYear } {
  335.     set n [expr $TodayDay + $offset]
  336.     $w.l$n configure -background "#00c0c0"
  337.     }
  338. }
  339.  
  340. #---------------------------------------------------------------------------
  341. # CreateCalWindow -- create the calendar window.
  342. # Arguments:
  343. #   dayNames -- names of weekdays in current language {Sun .. Sat}
  344. #---------------------------------------------------------------------------
  345. proc CreateCalWindow { dayNames } {
  346.     global Option
  347.     frame .h
  348.     label .h.title -text "" -justify center -pady 2 -relief raised
  349.     pack .h.title -side top -fill x
  350.     pack .h -side top -expand 0 -fill x
  351.  
  352.     CreateCalFrame .cal $dayNames
  353.     pack .cal -side top -fill both -expand 1
  354.  
  355.     frame .b
  356.     button .b.prev -text {<-} -command {MoveMonth -1}
  357.     button .b.this -text {Today} -command {ThisMonth}
  358.     button .b.next -text {->} -command {MoveMonth 1}
  359.     button .b.goto -text {Go To Date...} -command {GotoDialog}
  360.     button .b.print -text {Print...} -command {DoPrint}
  361.     button .b.quit -text {Quit} -command {Quit}
  362.     button .b.options -text {Options...} -command EditOptions
  363.     label .b.status -text "" -width 25 -relief sunken
  364.     label .b.nqueued -text "" -width 20 -relief sunken
  365.     pack .b.prev .b.this .b.next .b.goto .b.print .b.options .b.quit -side left -fill x
  366.     pack .b.status -side left -fill x -expand 1
  367.     pack .b.nqueued -side left -fill x
  368.     pack .b -side top -fill x -expand 0
  369.     wm title . "TkRemind"
  370.     wm iconname . ""
  371.     wm protocol . WM_DELETE_WINDOW Quit
  372.     wm deiconify .
  373.     if {$Option(StartIconified)} {
  374.     wm iconify .
  375.     }
  376.     update
  377.     grid propagate .cal 0
  378. }
  379.  
  380. #***********************************************************************
  381. # %PROCEDURE: EditOptions
  382. # %ARGUMENTS:
  383. #  None
  384. # %RETURNS:
  385. #  Nothing
  386. # %DESCRIPTION:
  387. #  Lets user edit options
  388. #***********************************************************************
  389. proc EditOptions {} {
  390.     global Option tmpOpt
  391.  
  392.     # Make a working copy of current option set
  393.     foreach name [array names Option] {
  394.     set tmpOpt($name) $Option($name)
  395.     }
  396.     
  397.     set w .opt
  398.     catch { destroy $w }
  399.     toplevel $w
  400.     wm title $w "TkRemind Options"
  401.     wm iconname $w "Options"
  402.     frame $w.f
  403.     frame $w.b
  404.     pack $w.f -side top -expand 1 -fill both
  405.     pack $w.b -side top -expand 0 -fill x
  406.  
  407.     # Start iconified
  408.     checkbutton $w.startIconified -text "Start up Iconified" \
  409.         -anchor w -justify left \
  410.         -variable tmpOpt(StartIconified)
  411.  
  412.     # Confirm quit
  413.     checkbutton $w.confirmQuit -text "Confirm Quit" -anchor w -justify left \
  414.         -variable tmpOpt(ConfirmQuit)
  415.  
  416.     # Bring down reminder windows after one minute
  417.     checkbutton $w.bringDown \
  418.         -text "Automatically close pop-up reminders after a minute" \
  419.         -anchor w -justify left -variable tmpOpt(AutoClose)
  420.  
  421.     # Ring bell when popping up reminder
  422.     checkbutton $w.ring -text "Beep terminal when popping up a reminder" \
  423.         -anchor w -justify left -variable tmpOpt(RingBell)
  424.  
  425.     checkbutton $w.deic -text "Deiconify calendar window when popping up a reminder" \
  426.         -anchor w -justify left -variable tmpOpt(Deiconify)
  427.  
  428.     # Run command when popping up reminder
  429.     frame $w.rf
  430.     label $w.rl -text "Run command when popping up reminder:" -anchor w \
  431.         -justify left
  432.     entry $w.cmd -width 30
  433.     pack $w.rl -in $w.rf -side left -expand 0 -fill none
  434.     pack $w.cmd -in $w.rf -side left -expand 1 -fill x
  435.     $w.cmd insert 0 $tmpOpt(RunCmd)
  436.  
  437.     frame $w.sep1 -border 1 -relief sunken
  438.     frame $w.sep2 -border 1 -relief sunken
  439.  
  440.     checkbutton $w.feed \
  441.         -text "Feed popped-up reminder to command's standard input" \
  442.         -variable tmpOpt(FeedReminder) -anchor w -justify left
  443.  
  444.     pack $w.startIconified -in $w.f -side top -expand 0 -fill x
  445.     pack $w.confirmQuit -in $w.f -side top -expand 0 -fill x
  446.     pack $w.bringDown -in $w.f -side top -expand 0 -fill x
  447.     pack $w.ring -in $w.f -side top -expand 0 -fill x
  448.     pack $w.deic -in $w.f -side top -expand 0 -fill x
  449.     pack $w.sep1 -in $w.f -side top -expand 0 -fill x -ipady 1
  450.     pack $w.rf -in $w.f -side top -expand 0 -fill x
  451.     pack $w.feed -in $w.f -side top -expand 0 -fill x
  452.     pack $w.sep2 -in $w.f -side top -expand 0 -fill x -ipady 1
  453.  
  454.     button $w.apply -text "Apply Options" -command "ApplyOptions $w; destroy $w"
  455.     button $w.save -text "Save Options" -command "SaveOptions $w; destroy $w"
  456.     button $w.cancel -text "Cancel" -command "destroy $w"
  457.  
  458.     pack $w.apply $w.save $w.cancel -in $w.b -side left -expand 0 -fill x
  459.     CenterWindow $w
  460. }
  461.  
  462. #***********************************************************************
  463. # %PROCEDURE: ApplyOptions
  464. # %ARGUMENTS:
  465. #  w -- edit options window path
  466. # %RETURNS:
  467. #  Nothing
  468. # %DESCRIPTION:
  469. #  Applies options set in the edit options box.
  470. #***********************************************************************
  471. proc ApplyOptions { w } {
  472.     global Option tmpOpt
  473.     set tmpOpt(RunCmd) [$w.cmd get]
  474.     # Copy working copy to real option set
  475.     foreach name [array names tmpOpt] {
  476.     set Option($name) $tmpOpt($name)
  477.     }
  478. }
  479.  
  480. #***********************************************************************
  481. # %PROCEDURE: SaveOptions
  482. # %ARGUMENTS:
  483. #  w -- edit options window path
  484. # %RETURNS:
  485. #  Nothing
  486. # %DESCRIPTION:
  487. #  Saves options in $HOME/.tkremindrc
  488. #***********************************************************************
  489. proc SaveOptions { w } {
  490.     global Option OptDescr
  491.     ApplyOptions $w
  492.  
  493.     set problem [catch {set f [open ~/.tkremindrc "w"]} err]
  494.     if {$problem} {
  495.     tk_dialog .error Error "Can't write ~/.tkremindrc: $err" 0 OK
  496.     return
  497.     }
  498.  
  499.     puts $f "# TkRemind option file -- created automatically"
  500.     puts $f "# [clock format [clock seconds]]"
  501.     puts $f "# Format of each line is 'key value' where 'key'"
  502.     puts $f "# specifies the option name, and 'value' is a"
  503.     puts $f "# *legal Tcl list element* specifying the option value."
  504.     foreach name [lsort [array names Option]] {
  505.     puts $f ""
  506.     puts $f "# $OptDescr($name)"
  507.     puts $f [list $name $Option($name)]
  508.     }
  509.     close $f
  510. }
  511.  
  512. #***********************************************************************
  513. # %PROCEDURE: LoadOptions
  514. # %ARGUMENTS:
  515. #  None
  516. # %RETURNS:
  517. #  Nothing
  518. # %DESCRIPTION:
  519. #  Loads options from ~/.tkremindrc
  520. #***********************************************************************
  521. proc LoadOptions {} {
  522.     global Option
  523.     set problem [catch {set f [open "~/.tkremindrc" "r"]}]
  524.     if {$problem} {
  525.     return
  526.     }
  527.     while {[gets $f line] >= 0} {
  528.     if {[string match "#*" $line]} { continue }
  529.     if {$line == ""} { continue }
  530.     foreach {key val} $line {}
  531.     if {![info exists Option($key)]} {
  532.         puts "Unknown option in ~/.tkremindrc: $key"
  533.         continue
  534.     }
  535.     set Option($key) $val
  536.     }
  537.     close $f
  538. }
  539.  
  540.  
  541.  
  542. #***********************************************************************
  543. # %PROCEDURE: ConfigureCalWindow
  544. # %ARGUMENTS:
  545. #  month -- month name
  546. #  year -- the year
  547. #  firstDay -- first day in month
  548. #  numDays -- number of days in month
  549. # %RETURNS:
  550. #  Nothing
  551. # %DESCRIPTION:
  552. #  Configures the calendar window for a month and year
  553. # %PRECONDITIONS:
  554. #  Any preconditions
  555. # %POSTCONDITIONS:
  556. #  Any postconditions
  557. # %SIDE EFFECTS:
  558. #  Any side effects
  559. #***********************************************************************
  560. proc ConfigureCalWindow { month year firstDay numDays } {
  561.     .h.title configure -text "$month $year"
  562.     wm title . "TkRemind - $month $year"
  563.     wm iconname . "$month $year"
  564.     ConfigureCalFrame .cal $firstDay $numDays
  565. }
  566.  
  567. #---------------------------------------------------------------------------
  568. # FillCalWindow -- Fill in the calendar for global CurMonth and CurYear.
  569. #---------------------------------------------------------------------------
  570. proc FillCalWindow {} {
  571.     global DayNames CurYear CurMonth MonthNames CommandLine
  572.  
  573.     Status "Firing off Remind..."
  574.     set month [lindex $MonthNames $CurMonth]
  575.  
  576.     set file [open "$CommandLine $month $CurYear" r]
  577.     # Look for # rem2ps begin line
  578.     while { [gets $file line] >= 0 } {
  579.     if { [string compare "$line" "# rem2ps begin"] == 0 } { break }
  580.     }
  581.  
  582.     if { [string compare "$line" "# rem2ps begin"] != 0 } { 
  583.     Status "Problem reading results from Remind!"
  584.     after 5000 DisplayTime
  585.     catch { close $file }
  586.     return 0
  587.     }
  588.  
  589.     # Read month name, year, number of days in month, first weekday, Mon flag
  590.     gets $file line
  591.     regexp {^([^ ]*) ([0-9][0-9][0-9][0-9]) ([0-9][0-9]?) ([0-9]) ([0-9])} $line dummy monthName year daysInMonth firstWkday mondayFirst
  592.  
  593.     # Skip day names -- we already have them
  594.     gets $file line
  595.     ConfigureCalWindow $monthName $year $firstWkday $daysInMonth
  596.     set offset [CalEntryOffset $firstWkday]
  597.     while { [gets $file line] >= 0 } {
  598.     if { [regexp {^([0-9][0-9][0-9][0-9])/([0-9][0-9])/([0-9][0-9]) +([^ ]+) +([^ ]+) +[^ ]+ +[^ ]+(.*)} $line all year month day type tag stuff] == 0 } {
  599.         continue
  600.     }
  601.     set day [string trimleft $day 0]
  602.     set n [expr $day+$offset]
  603.     set month [string trimleft $month 0]
  604.     switch -exact -- $type {
  605.         "SHADE" {
  606.         DoShadeSpecial $n $stuff
  607.         continue
  608.         }
  609.         "MOON" {
  610.         DoMoonSpecial $n $stuff
  611.         continue
  612.         }
  613.     }
  614.     if { $type != "*"} {
  615.         continue
  616.     }
  617.     .cal.t$n configure -state normal
  618.     if { [string length [string trim [.cal.t$n get 1.0]]] != 0} {
  619.         .cal.t$n insert end " .....\n"
  620.     }
  621.     if {[regexp {TKTAG([0-9]+)} $tag all tagno]} {
  622.         .cal.t$n insert end [string trim $stuff] "TAGGED TKTAG$tagno"
  623.     } else {
  624.         .cal.t$n insert end [string trim $stuff]
  625.     }
  626.     .cal.t$n insert end "\n"
  627.     .cal.t$n configure -state disabled
  628.     
  629.     }
  630.     set problem [catch { close $file } errmsg]
  631.     if {$problem} {
  632.     tk_dialog .error Error "There was a problem running Remind: $errmsg" error 0 OK
  633.     }
  634.     DisplayTime
  635. }
  636.  
  637. #---------------------------------------------------------------------------
  638. # MoveMonth -- move by +1 or -1 months
  639. # Arguments:
  640. #    delta -- +1 or -1 -- months to move.
  641. #---------------------------------------------------------------------------
  642. proc MoveMonth {delta} {
  643.     global CurMonth CurYear
  644.     set CurMonth [expr $CurMonth + $delta]
  645.     if {$CurMonth < 0} {
  646.     set CurMonth 11
  647.     set CurYear [expr $CurYear-1]
  648.     }
  649.  
  650.     if {$CurMonth > 11} {
  651.     set CurMonth 0
  652.     incr CurYear
  653.     }
  654.  
  655.     FillCalWindow
  656. }
  657.  
  658. #---------------------------------------------------------------------------
  659. # ThisMonth -- move to current month
  660. #---------------------------------------------------------------------------
  661. proc ThisMonth {} {
  662.     global CurMonth CurYear TodayMonth TodayYear
  663.  
  664.     # Do nothing if already there
  665.     if { $CurMonth == $TodayMonth && $CurYear == $TodayYear } {
  666.     return 0;
  667.     }
  668.     set CurMonth $TodayMonth
  669.     set CurYear $TodayYear
  670.     FillCalWindow
  671. }
  672.  
  673. #---------------------------------------------------------------------------
  674. # Status -- set status string
  675. # Arguments:
  676. #   stuff -- what to set string to.
  677. #---------------------------------------------------------------------------
  678. proc Status { stuff } {
  679.     catch { .b.status configure -text $stuff }
  680.     update idletasks
  681. }
  682.  
  683. #---------------------------------------------------------------------------
  684. # DoPrint -- print a calendar
  685. # Arguments:
  686. #   None
  687. #---------------------------------------------------------------------------
  688. proc DoPrint {} {
  689.     global PrintDest PrintSize PrintOrient PrintFill PrintStatus Rem2PS PSCmd
  690.     global CurMonth CurYear MonthNames
  691.     catch {destroy .p}
  692.     toplevel .p
  693.     wm title .p "TkRemind Print..."
  694.     wm iconname .p "Print..."
  695.     frame .p.f1 -relief sunken -border 2
  696.     frame .p.f11
  697.     frame .p.f12
  698.     frame .p.f2 -relief sunken -border 2
  699.     frame .p.f3 -relief sunken -border 2
  700.     frame .p.f4
  701.  
  702.     radiobutton .p.tofile -text "To file: " -variable PrintDest -value file
  703.     entry .p.filename
  704.     button .p.browse -text "Browse..." -command PrintFileBrowse
  705.     radiobutton .p.tocmd -text "To command: " -variable PrintDest -value command
  706.     entry .p.command
  707.     .p.command insert end "lpr"
  708.  
  709.     label .p.size -text "Paper Size:"
  710.     radiobutton .p.letter -text "Letter" -variable PrintSize -value letter
  711.     radiobutton .p.a4 -text "A4" -variable PrintSize -value a4
  712.  
  713.     label .p.orient -text "Orientation:"
  714.     radiobutton .p.landscape -text "Landscape" -variable PrintOrient -value landscape
  715.     radiobutton .p.portrait -text "Portrait" -variable PrintOrient -value portrait
  716.  
  717.     checkbutton .p.fill -text "Fill page" -variable PrintFill
  718.  
  719.     button .p.print -text "Print" -command {set PrintStatus print}
  720.     button .p.cancel -text "Cancel" -command {set PrintStatus cancel}
  721.  
  722.     pack .p.f1 .p.f2 .p.f3  -side top -fill both -expand 1 -anchor w
  723.     pack .p.fill -side top -anchor w -fill none -expand 0
  724.     pack .p.f4 -side top -fill both -expand 1 -anchor w
  725.     pack .p.f11 .p.f12 -in .p.f1 -side top -fill none -expand 0 -anchor w
  726.     pack .p.tofile .p.filename .p.browse -in .p.f11 -side left -fill none -expand 0 -anchor w
  727.     pack .p.tocmd .p.command -in .p.f12 -side left -fill none -expand 0 -anchor w
  728.     pack .p.size .p.letter .p.a4 -in .p.f2 -side top -fill none -expand 0 -anchor w
  729.     pack .p.orient .p.landscape .p.portrait -in .p.f3 -side top -fill none -expand 0 -anchor w
  730.     pack .p.print .p.cancel -in .p.f4 -side left -fill none -expand 0
  731.  
  732.     bind .p <KeyPress-Escape> ".p.cancel flash; .p.cancel invoke"
  733.     bind .p <KeyPress-Return> ".p.print flash; .p.print invoke"
  734.     set PrintStatus 2
  735.     CenterWindow .p
  736.     tkwait visibility .p
  737.     set oldFocus [focus]
  738.     focus .p.filename
  739.     grab .p
  740.     tkwait variable PrintStatus
  741.     catch {focus $oldFocus}
  742.     set fname [.p.filename get]
  743.     set cmd [.p.command get]
  744.     destroy .p
  745.     if {$PrintStatus == "cancel"} {
  746.     return
  747.     }
  748.     if {$PrintDest == "file"} {
  749.     if {$fname == ""} {
  750.         tk_dialog .error Error "No filename specified" error 0 Ok
  751.         return
  752.     }
  753.     if {[file isdirectory $fname]} {
  754.         tk_dialog .error Error "$fname is a directory" error 0 Ok
  755.         return
  756.     }
  757.     if {[file readable $fname]} {
  758.         set ans [tk_dialog .error Overwrite? "Overwrite $fname?" question 0 No Yes]
  759.         if {$ans == 0} {
  760.         return
  761.         }
  762.     }
  763.     set fname "> $fname"
  764.     } else {
  765.     set fname "| $cmd"
  766.     }
  767.  
  768.     # Build the command line
  769.     set cmd "$PSCmd 1 [lindex $MonthNames $CurMonth] $CurYear | $Rem2PS -c3"
  770.     if {$PrintSize == "letter"} {
  771.     append cmd " -m Letter"
  772.     } else {
  773.     append cmd " -m A4"
  774.     }
  775.  
  776.     if {$PrintOrient == "landscape"} {
  777.     append cmd " -l"
  778.     }
  779.  
  780.     if {$PrintFill} {
  781.     append cmd " -e"
  782.     }
  783.  
  784.     append cmd " $fname"
  785.     Status "Printing..."
  786.     if {[catch {eval "exec $cmd"} err]} {
  787.     tk_dialog .error Error "Error during printing: $err" error 0 Ok
  788.     }
  789.     DisplayTime
  790. }
  791.  
  792. #---------------------------------------------------------------------------
  793. # PrintFileBrowse -- browse for a filename for Print dialog
  794. # Arguments: none
  795. #---------------------------------------------------------------------------
  796. proc PrintFileBrowse {} {
  797.     set ans [BrowseForFile .filebrowse "Print to file..." "Ok" 0 "*.ps"]
  798.     if {$ans != ""} {
  799.     .p.filename delete 0 end
  800.     .p.filename insert end $ans
  801.     .p.filename icursor end
  802.     .p.filename xview end
  803.     }
  804. }
  805.  
  806. #---------------------------------------------------------------------------
  807. # GotoDialog -- Do the "Goto..." dialog
  808. #---------------------------------------------------------------------------
  809. proc GotoDialog {} {
  810.     global CurMonth MonthNames CurYear
  811.     catch { destroy .g }
  812.  
  813.     set month [lindex $MonthNames $CurMonth]
  814.     toplevel .g
  815.     wm title .g "Go To Date"
  816.     menubutton .g.mon -text "$month" -menu .g.mon.menu -relief raised
  817.     menu .g.mon.menu -tearoff 0
  818.  
  819.     foreach m $MonthNames {
  820.     .g.mon.menu add command -label $m -command ".g.mon configure -text $m"
  821.     }
  822.  
  823.     frame .g.y
  824.     label .g.y.lab -text "Year: "
  825.     entry .g.y.e -width 4
  826.     .g.y.e insert end $CurYear
  827.     bind .g.y.e <Return> ".g.b.go flash; .g.b.go invoke"
  828.     frame .g.b
  829.     button .g.b.go -text "Go" -command {DoGoto}
  830.     button .g.b.cancel -text "Cancel" -command { destroy .g }
  831.     pack .g.b.go .g.b.cancel -expand 1 -fill x -side left
  832.     pack .g.mon -fill x -expand 1
  833.  
  834.     pack .g.y.lab -side left
  835.     pack .g.y.e -side left -fill x -expand 1
  836.     pack .g.y -expand 1 -fill x
  837.     pack .g.b -expand 1 -fill x
  838.     bind .g <KeyPress-Escape> ".g.b.cancel flash; .g.b.cancel invoke"
  839.     CenterWindow .g
  840.     set oldFocus [focus]
  841.     grab .g
  842.     focus .g.y.e
  843.     tkwait window .g
  844.     catch {focus $oldFocus}
  845. }
  846.  
  847. #---------------------------------------------------------------------------
  848. # DoGoto -- go to specified date
  849. #---------------------------------------------------------------------------
  850. proc DoGoto {} {
  851.     global CurYear CurMonth MonthNames
  852.     set year [.g.y.e get]
  853.     if { ! [regexp {^[0-9]+$} $year] } {
  854.     tk_dialog .error Error {Illegal year specified (1990-2078)} error 0 Ok
  855.     return
  856.     }
  857.     if { $year < 1990 || $year > 2078 } {
  858.     tk_dialog .error Error {Illegal year specified (1990-2078)} error 0 Ok
  859.     return
  860.     }
  861.     set month [lsearch -exact $MonthNames [.g.mon cget -text]]
  862.     set CurMonth $month
  863.     set CurYear $year
  864.     destroy .g
  865.     FillCalWindow
  866. }
  867.  
  868. #---------------------------------------------------------------------------
  869. # Quit -- handle the Quit button
  870. #---------------------------------------------------------------------------
  871. proc Quit {} {
  872.     global Option
  873.     if { !$Option(ConfirmQuit) } {
  874.     destroy .
  875.     StopBackgroundRemindDaemon
  876.     exit
  877.     }
  878.     if { [tk_dialog .question "Confirm..." {Really quit?} question 0 No Yes] } {
  879.     destroy .
  880.     StopBackgroundRemindDaemon
  881.     exit
  882.     }
  883. }
  884.  
  885. #---------------------------------------------------------------------------
  886. # CreateModifyDialog -- create dialog for adding a reminder
  887. # Arguments:
  888. #    w -- path of parent window
  889. #    day -- day number of month
  890. #    firstDay -- day number of first day of month
  891. #    args -- buttons to add to bottom frame.  First sets result to 1, next
  892. #            to 2, and so on.  FIRST BUTTON MUST BE "Cancel"
  893. #---------------------------------------------------------------------------
  894. proc CreateModifyDialog {w day firstDay args} {
  895.  
  896.     # Set up: Year, Month, Day, WeekdayName
  897.     global CurYear CurMonth EnglishDayNames MonthNames OptionType SkipType
  898.     global ModifyDialogResult
  899.  
  900.     set OptionType 1
  901.     set SkipType 1
  902.  
  903.     set year $CurYear
  904.     set month [lindex $MonthNames $CurMonth]
  905.     set wkday [lindex $EnglishDayNames [expr ($day+$firstDay-1) % 7]]
  906.  
  907.     frame $w.o -border 4 -relief ridge
  908.     frame $w.o1 -border 4
  909.     frame $w.o2 -border 4
  910.     frame $w.o3 -border 4
  911.     frame $w.exp -border 4
  912.     frame $w.adv -border 4
  913.     frame $w.weekend -border 4
  914.     frame $w.time -border 4
  915.     frame $w.hol -border 4
  916.     frame $w.msg
  917.     frame $w.buttons
  918.     pack $w.o1 $w.o2 $w.o3  -side top -anchor w -in $w.o
  919.     pack $w.o $w.exp $w.adv $w.weekend $w.time $w.hol $w.msg -side top -anchor w -pady 4 -expand 1 -fill both
  920.     pack $w.buttons -side top -anchor w -pady 4 -expand 1 -fill x
  921.  
  922.     # TYPE 1 REMINDER
  923.     radiobutton $w.type1 -variable OptionType -value 1
  924.     menubutton $w.day1 -text $day -relief raised -menu $w.day1.menu
  925.     CreateDayMenu $w.day1
  926.     menubutton $w.mon1 -text $month -relief raised -menu $w.mon1.menu
  927.     CreateMonthMenu $w.mon1
  928.     menubutton $w.year1 -text $year -relief raised -menu $w.year1.menu
  929.     CreateYearMenu $w.year1
  930.     checkbutton $w.repbut -text "and repeating every"
  931.     $w.repbut deselect
  932.     menubutton $w.repdays -text 1 -relief raised -menu $w.repdays.menu
  933.     CreateDayMenu $w.repdays 1 28 0
  934.     label $w.label1a -text "day(s) thereafter"
  935.     pack $w.type1 $w.day1 $w.mon1 $w.year1 $w.repbut $w.repbut $w.repdays $w.label1a -side left -anchor w -in $w.o1
  936.  
  937.     # TYPE 2 REMINDER
  938.     radiobutton $w.type2 -variable OptionType -value 2
  939.     label $w.label2a -text First
  940.     menubutton $w.wkday2 -text $wkday -relief raised -menu $w.wkday2.menu
  941.     CreateWeekdayMenu $w.wkday2
  942.     label $w.label2b -text "on or after"
  943.     menubutton $w.day2 -text $day -relief raised -menu $w.day2.menu
  944.     CreateDayMenu $w.day2 1 31 0
  945.     menubutton $w.mon2 -text $month -relief raised -menu $w.mon2.menu
  946.     CreateMonthMenu $w.mon2
  947.     menubutton $w.year2 -text $year -relief raised -menu $w.year2.menu
  948.     CreateYearMenu $w.year2
  949.     pack $w.type2 $w.label2a $w.wkday2 $w.label2b $w.day2 $w.mon2 $w.year2 -side left -anchor w -in $w.o2
  950.  
  951.     # TYPE 3 REMINDER
  952.     if { $day <= 7 } {
  953.     set which "First"
  954.     } elseif {$day <= 14} {
  955.     set which "Second"
  956.     } elseif {$day <= 21} {
  957.     set which "Third"
  958.     } elseif {$day <= 28} {
  959.     set which "Fourth"
  960.     } else {
  961.     set which "Last"
  962.     }
  963.     radiobutton $w.type3 -variable OptionType -value 3
  964.     menubutton $w.ordinal -text $which -relief raised -menu $w.ordinal.menu
  965.     menu $w.ordinal.menu -tearoff 0
  966.     $w.ordinal.menu add command -label "First" -command "$w.ordinal configure -text First"
  967.     $w.ordinal.menu add command -label "Second" -command "$w.ordinal configure -text Second"
  968.     $w.ordinal.menu add command -label "Third" -command "$w.ordinal configure -text Third"
  969.     $w.ordinal.menu add command -label "Fourth" -command "$w.ordinal configure -text Fourth"
  970.     $w.ordinal.menu add command -label "Last" -command "$w.ordinal configure -text Last"
  971.     $w.ordinal.menu add command -label "Every" -command "$w.ordinal configure -text Every"
  972.     menubutton $w.wkday3 -text $wkday -relief raised -menu $w.wkday3.menu
  973.     CreateWeekdayMenu $w.wkday3
  974.     label $w.label3 -text "in"
  975.     menubutton $w.mon3 -text $month -relief raised -menu $w.mon3.menu
  976.     CreateMonthMenu $w.mon3
  977.     menubutton $w.year3 -text $year -relief raised -menu $w.year3.menu
  978.     CreateYearMenu $w.year3
  979.     pack $w.type3 $w.ordinal $w.wkday3 $w.label3 $w.mon3 $w.year3 -side left -anchor w -in $w.o3
  980.  
  981.     # EXPIRY DATE
  982.     checkbutton $w.expbut -text "Expire after"
  983.     $w.expbut deselect
  984.     menubutton $w.expday -text $day -relief raised -menu $w.expday.menu
  985.     CreateDayMenu $w.expday 1 31 0
  986.     menubutton $w.expmon -text $month -relief raised -menu $w.expmon.menu
  987.     CreateMonthMenu $w.expmon 0
  988.     menubutton $w.expyear -text $year -relief raised -menu $w.expyear.menu
  989.     CreateYearMenu $w.expyear 0
  990.  
  991.     pack $w.expbut $w.expday $w.expmon $w.expyear -side left -anchor w -in $w.exp
  992.  
  993.     # ADVANCE NOTICE
  994.     checkbutton $w.advbut -text "Issue"
  995.     $w.advbut deselect
  996.     menubutton $w.advdays -text 3 -menu $w.advdays.menu -relief raised
  997.     CreateDayMenu $w.advdays 1 10 0
  998.     label $w.advlab -text "day(s) in advance"
  999.     checkbutton $w.advcount -text "not counting holidays/weekend"
  1000.     $w.advcount select
  1001.     pack $w.advbut $w.advdays $w.advlab $w.advcount -side left -anchor w -in $w.adv
  1002.  
  1003.     # WEEKEND
  1004.     label $w.weeklab -text "Weekend is: "
  1005.     pack $w.weeklab -side left -anchor w -in $w.weekend
  1006.     foreach d $EnglishDayNames {
  1007.     checkbutton $w.d$d -text $d
  1008.     $w.d$d deselect
  1009.     pack $w.d$d -side left -anchor w -in $w.weekend
  1010.     }
  1011.     $w.dSaturday select
  1012.     $w.dSunday select
  1013.  
  1014.     # TIMED REMINDER
  1015.     checkbutton $w.timebut -text "Timed reminder at"
  1016.     $w.timebut deselect
  1017.     menubutton $w.timehour -text "12" -menu $w.timehour.menu -relief raised
  1018.     CreateDayMenu $w.timehour 1 12 0
  1019.     menubutton $w.timemin -text "00" -menu $w.timemin.menu -relief raised
  1020.     menu $w.timemin.menu -tearoff 0
  1021.     $w.timemin.menu add command -label "00" -command "$w.timemin configure -text {00}"
  1022.     $w.timemin.menu add command -label "15" -command "$w.timemin configure -text {15}"
  1023.     $w.timemin.menu add command -label "30" -command "$w.timemin configure -text {30}"
  1024.     $w.timemin.menu add command -label "45" -command "$w.timemin configure -text {45}"
  1025.  
  1026.     menubutton $w.ampm -text "PM" -menu $w.ampm.menu -relief raised
  1027.     menu $w.ampm.menu -tearoff 0
  1028.     $w.ampm.menu add command -label "AM" -command "$w.ampm configure -text {AM}"
  1029.     $w.ampm.menu add command -label "PM" -command "$w.ampm configure -text {PM}"
  1030.  
  1031.     checkbutton $w.timeadvbut -text "with"
  1032.     $w.timeadvbut deselect
  1033.     menubutton $w.timeadv -text "15" -menu $w.timeadv.menu -relief raised
  1034.     menu $w.timeadv.menu -tearoff 0
  1035.     foreach i {5 10 15 30 45 60} {
  1036.     $w.timeadv.menu add command -label $i -command "$w.timeadv configure -text $i"
  1037.     }
  1038.     label $w.timelab1 -text "minutes advance notice"
  1039.  
  1040.     checkbutton $w.timerepbut -text "repeated every"
  1041.     $w.timerepbut deselect
  1042.     menubutton $w.timerep -text "5" -menu $w.timerep.menu -relief raised
  1043.     menu $w.timerep.menu -tearoff 0
  1044.     foreach i {3 5 10 15 30} {
  1045.     $w.timerep.menu add command -label $i -command "$w.timerep configure -text $i"
  1046.     }
  1047.     label $w.timelab2 -text "minutes"
  1048.     pack $w.timebut $w.timehour $w.timemin $w.ampm $w.timeadvbut $w.timeadv $w.timelab1 $w.timerepbut $w.timerep $w.timelab2 -side left -anchor w -in $w.time
  1049.  
  1050.     # SKIP TYPE
  1051.     label $w.labhol -text "On holidays or weekends:"
  1052.     radiobutton $w.issue -variable SkipType -value 1 -text "Issue reminder as usual"
  1053.     radiobutton $w.skip -variable SkipType -value 2 -text "Skip reminder"
  1054.     radiobutton $w.before -variable SkipType -value 3 -text "Move reminder before holiday or weekend"
  1055.     radiobutton $w.after -variable SkipType -value 4 -text "Move reminder after holiday or weekend"
  1056.     pack $w.labhol $w.issue $w.skip $w.before $w.after -side top -anchor w -in $w.hol
  1057.  
  1058.     # TEXT ENTRY
  1059.     label $w.msglab -text "Body:"
  1060.     entry $w.entry
  1061.     pack $w.msglab -side left -anchor w -in $w.msg
  1062.     pack $w.entry -side left -anchor w -expand 1 -fill x -in $w.msg
  1063.  
  1064.     # BUTTONS
  1065.     set nbut 0
  1066.     foreach but $args {
  1067.     incr nbut
  1068.     button $w.but$nbut -text $but -command "set ModifyDialogResult $nbut"
  1069.     pack $w.but$nbut -side left -anchor w -in $w.buttons -expand 1 -fill x
  1070.     }
  1071.  
  1072.     bind $w <KeyPress-Escape> "$w.but1 invoke"
  1073.     set ModifyDialogResult 0
  1074.  
  1075.     # Center the window on the root
  1076.     CenterWindow $w
  1077. }
  1078.  
  1079. #***********************************************************************
  1080. # %PROCEDURE: RemindDialogToOptions
  1081. # %ARGUMENTS:
  1082. #  w -- dialog window
  1083. # %RETURNS:
  1084. #  A list of flag/value pairs representing the current state of
  1085. #  the "create reminder" dialog.
  1086. #***********************************************************************
  1087. proc RemindDialogToOptions { w } {
  1088.     global OptionType SkipType repbut expbut advbut advcount
  1089.     global timebut timeadvbut timerepbut
  1090.     global dSaturday dSunday dMonday dTuesday dWednesday dThursday dFriday
  1091.     set ans {}
  1092.     lappend ans "-global-OptionType" $OptionType
  1093.     lappend ans "-global-SkipType" $SkipType
  1094.     foreach win [winfo children $w] {
  1095.     set winstem [winfo name $win]
  1096.     switch -exact -- [winfo class $win] {
  1097.         "Menubutton" {
  1098.         lappend ans "-text-$winstem" [$win cget -text]
  1099.         }
  1100.         "Checkbutton" {
  1101.         lappend ans "-global-$winstem" [eval set $winstem]
  1102.         }
  1103.         "Entry" {
  1104.         lappend ans "-entry-$winstem" [$win get]
  1105.         }
  1106.     }
  1107.     }
  1108.     return $ans
  1109. }
  1110.  
  1111. #***********************************************************************
  1112. # %PROCEDURE: OptionsToRemindDialog
  1113. # %ARGUMENTS:
  1114. #  w -- Remind dialog window
  1115. #  opts -- option list set by RemindDialogToOptions
  1116. # %RETURNS:
  1117. #  Nothing
  1118. # %DESCRIPTION:
  1119. #  Sets parameters in the dialog box according to saved options.
  1120. #***********************************************************************
  1121. proc OptionsToRemindDialog { w opts } {
  1122.     global OptionType SkipType repbut expbut advbut advcount
  1123.     global timebut timeadvbut timerepbut
  1124.     global dSaturday dSunday dMonday dTuesday dWednesday dThursday dFriday
  1125.     foreach {flag value} $opts {
  1126.     switch -glob -- $flag {
  1127.         "-text-*" {
  1128.         set win [string range $flag 6 end]
  1129.         $w.$win configure -text $value
  1130.         }
  1131.         "-global-*" {
  1132.         set win [string range $flag 8 end]
  1133.         set $win $value
  1134.         }
  1135.         "-entry-*" {
  1136.         set win [string range $flag 7 end]
  1137.         $w.$win delete 0 end
  1138.         $w.$win insert end $value
  1139.         }
  1140.     }
  1141.     }
  1142. }
  1143.  
  1144. #---------------------------------------------------------------------------
  1145. # CreateMonthMenu -- create a menu with all the months of the year
  1146. # Arguments:
  1147. #    w -- menu button -- becomes parent of menu
  1148. #    every -- if true, include an "every month" entry
  1149. #---------------------------------------------------------------------------
  1150. proc CreateMonthMenu {w {every 1}} {
  1151.     global MonthNames
  1152.     menu $w.menu -tearoff 0
  1153.  
  1154.     if {$every} {
  1155.     $w.menu add command -label "every month" -command "$w configure -text {every month}"
  1156.     }
  1157.  
  1158.     foreach month $MonthNames {
  1159.     $w.menu add command -label $month -command "$w configure -text $month"
  1160.     }
  1161. }
  1162.  
  1163. #---------------------------------------------------------------------------
  1164. # CreateWeekdayMenu -- create a menu with all the weekdays
  1165. # Arguments:
  1166. #    w -- menu button -- becomes parent of menu
  1167. #---------------------------------------------------------------------------
  1168. proc CreateWeekdayMenu {w} {
  1169.     global EnglishDayNames
  1170.     menu $w.menu -tearoff 0
  1171.  
  1172.     foreach d $EnglishDayNames {
  1173.     $w.menu add command -label $d -command "$w configure -text $d"
  1174.     }
  1175.     $w.menu add command -label "weekday" -command "$w configure -text weekday"
  1176. }
  1177.  
  1178. #---------------------------------------------------------------------------
  1179. # CreateDayMenu -- create a menu with entries 1-31 and possibly "every day"
  1180. # Arguments:
  1181. #    w -- menu button -- becomes parent of menu
  1182. #    min -- minimum day to start from.
  1183. #    max -- maximum day to go up to
  1184. #    every -- if true, include an "every day" entry
  1185. #---------------------------------------------------------------------------
  1186. proc CreateDayMenu {w {min 1} {max 31} {every 1}} {
  1187.     menu $w.menu -tearoff 0
  1188.     if {$every} {
  1189.     $w.menu add command -label "every day" -command "$w configure -text {every day}"
  1190.     }
  1191.     set d $min
  1192.     while { $d <= $max } {
  1193.     $w.menu add command -label $d -command "$w configure -text $d"
  1194.     incr d
  1195.     }
  1196. }
  1197.  
  1198. #---------------------------------------------------------------------------
  1199. # CreateYearMenu -- create a menu with entries from this year to this year+10
  1200. #                   and possibly "every year"
  1201. # Arguments:
  1202. #    w -- menu button -- becomes parent of menu
  1203. #    every -- if true, include an "every year" entry
  1204. #---------------------------------------------------------------------------
  1205. proc CreateYearMenu {w {every 1}} {
  1206.     menu $w.menu -tearoff 0
  1207.     if {$every} {
  1208.     $w.menu add command -label "every year" -command "$w configure -text {every year}"
  1209.     }
  1210.     global CurYear
  1211.     set d $CurYear
  1212.     while { $d < [expr $CurYear + 11] } {
  1213.     $w.menu add command -label $d -command "$w configure -text $d"
  1214.     incr d
  1215.     }
  1216. }
  1217.  
  1218. #---------------------------------------------------------------------------
  1219. # ModifyDay -- bring up dialog for adding reminder.
  1220. # Arguments:
  1221. #    d -- which day to modify
  1222. #    firstDay -- first weekday in month (0-6)
  1223. #---------------------------------------------------------------------------
  1224. proc ModifyDay {d firstDay} {
  1225.     global ModifyDialogResult AppendFile HighestTagSoFar ReminderTags
  1226.     catch {destroy .mod}
  1227.     toplevel .mod
  1228.     CreateModifyDialog .mod $d $firstDay "Cancel" "Add to reminder file" "Preview reminder"
  1229.     wm title .mod "TkRemind Add Reminder..."
  1230.     wm iconname .mod "Add Reminder"
  1231.     tkwait visibility .mod
  1232.     set oldFocus [focus]
  1233.     while {1} {
  1234.     grab .mod
  1235.     focus .mod.entry
  1236.     set ModifyDialogResult -1
  1237.     tkwait variable ModifyDialogResult
  1238.     if {$ModifyDialogResult == 1} {
  1239.         catch {focus $oldFocus}
  1240.         destroy .mod
  1241.         return 0
  1242.     }
  1243.     set problem [catch {set rem [CreateReminder .mod]} err]
  1244.     if {$problem} {
  1245.         tk_dialog .error Error "$err" error 0 Ok
  1246.     } else {
  1247.         if {$ModifyDialogResult == 3} {
  1248.         set rem [EditReminder $rem Cancel "Add reminder"]
  1249.         if {$ModifyDialogResult == 1} {
  1250.             continue
  1251.         }
  1252.         }
  1253.         set opts [RemindDialogToOptions .mod]
  1254.         catch {focus $oldFocus}
  1255.         destroy .mod
  1256.         Status "Writing reminder..."
  1257.         set f [open $AppendFile a]
  1258.         incr HighestTagSoFar
  1259.         set ReminderTags($HighestTagSoFar) 1
  1260.  
  1261.         WriteReminder $f TKTAG$HighestTagSoFar $rem $opts
  1262.         close $f
  1263.  
  1264.         FillCalWindow
  1265.         RestartBackgroundRemindDaemon
  1266.         return 0
  1267.     }
  1268.     }
  1269. }
  1270.  
  1271. #---------------------------------------------------------------------------
  1272. # CenterWindow -- center a window on the screen.  Stolen from tk_dialog code
  1273. # Arguments:
  1274. #    w -- window to center
  1275. #---------------------------------------------------------------------------
  1276. proc CenterWindow {w} {
  1277.     wm withdraw $w
  1278.     update idletasks
  1279.     set x [expr [winfo screenwidth $w]/2 - [winfo reqwidth $w]/2 \
  1280.         - [winfo vrootx [winfo parent $w]]]
  1281.     set y [expr [winfo screenheight $w]/2 - [winfo reqheight $w]/2 \
  1282.         - [winfo vrooty [winfo parent $w]]]
  1283.     wm geom $w +$x+$y
  1284.     wm deiconify $w
  1285. }
  1286.  
  1287. #---------------------------------------------------------------------------
  1288. # CreateReminder -- create the reminder
  1289. # Arguments:
  1290. #    w -- the window containing the add reminder dialog box.
  1291. # Returns:
  1292. #    The reminder as a string.
  1293. #---------------------------------------------------------------------------
  1294. proc CreateReminder {w} {
  1295.     global DidOmit
  1296.  
  1297.     set body [string trim [$w.entry get]]
  1298.  
  1299.     if {"$body" == ""} {
  1300.     error "Blank body in reminder"
  1301.     }
  1302.  
  1303.     set DidOmit 0
  1304.     set needOmit 0
  1305.     # Delegate the first part to CreateReminder1, CreateReminder2, or
  1306.     # CreateReminder3
  1307.     global OptionType SkipType repbut expbut advbut advcount
  1308.     global timebut timeadvbut timerepbut
  1309.  
  1310.     set rem [CreateReminder$OptionType $w]
  1311.  
  1312.     # Do the "until" part
  1313.     if {$expbut} {
  1314.     append rem " UNTIL [$w.expday cget -text] [$w.expmon cget -text] [$w.expyear cget -text]"
  1315.     }
  1316.  
  1317.     # Advance warning
  1318.     if {$advbut} {
  1319.     append rem " +"
  1320.     if {!$advcount} {
  1321.         append rem "+"
  1322.     } else {
  1323.         set needOmit 1
  1324.     }
  1325.     append rem [$w.advdays cget -text]
  1326.     }
  1327.  
  1328.     # Timed reminder
  1329.     if {$timebut} {
  1330.     set hour [$w.timehour cget -text]
  1331.     set min [$w.timemin cget -text]
  1332.     if {[$w.ampm cget -text] == "PM"} {
  1333.         if {$hour < 12} {
  1334.         incr hour 12
  1335.         }
  1336.     } else {
  1337.         if {$hour == 12} {
  1338.         set hour 0
  1339.         }
  1340.     }
  1341.     append rem " AT $hour:$min"
  1342.     if {$timeadvbut} {
  1343.         append rem " +[$w.timeadv cget -text]"
  1344.     }
  1345.     if {$timerepbut} {
  1346.         append rem " *[$w.timerep cget -text]"
  1347.     }
  1348.     }
  1349.  
  1350.     global SkipType
  1351.     if {$SkipType == 2} {
  1352.     append rem " SKIP"
  1353.     set needOmit 1
  1354.     } elseif {$SkipType == 3} {
  1355.     append rem " BEFORE"
  1356.     set needOmit 1
  1357.     } elseif {$SkipType == 4} {
  1358.     append rem " AFTER"
  1359.     set needOmit 1
  1360.     }
  1361.  
  1362.     if {$needOmit && !$DidOmit} {
  1363.     append rem " OMIT [GetWeekend $w 1]"
  1364.     }
  1365.  
  1366.  
  1367.     # Check it out!
  1368.     global Remind
  1369.     set f [open "|$Remind -arq -e -" r+]
  1370.     puts $f "BANNER %"
  1371.     puts $f "$rem MSG %"
  1372.     puts $f "MSG %_%_%_%_"
  1373.     puts $f "FLUSH"
  1374.     flush $f
  1375.     set err {}
  1376.     catch {set err [gets $f]}
  1377.     catch {close $f}
  1378.     if {"$err" != ""} {
  1379.     # Clean up the message a bit
  1380.     regsub -- {^-stdin-\([0-9]*\): } $err {} err
  1381.     error "Error from Remind: $err"
  1382.     }
  1383.     append rem " MSG $body"
  1384.     return $rem
  1385. }
  1386.  
  1387. #---------------------------------------------------------------------------
  1388. # CreateReminder1 -- Create the first part of a type-1 reminder
  1389. # Arguments:
  1390. #    w -- add reminder dialog window
  1391. # Returns: first part of reminder
  1392. #---------------------------------------------------------------------------
  1393. proc CreateReminder1 {w} {
  1394.  
  1395.     global repbut
  1396.  
  1397.     set rem "REM"
  1398.     set gotDay 0
  1399.     set gotMon 0
  1400.     set gotYear 0
  1401.     set d [$w.day1 cget -text]
  1402.     if {"$d" != "every day"} {
  1403.     append rem " $d"
  1404.     set gotDay 1
  1405.     }
  1406.     set m [$w.mon1 cget -text]
  1407.     if {"$m" != "every month"} {
  1408.     append rem " $m"
  1409.     set gotMon 1
  1410.     }
  1411.     set y [$w.year1 cget -text]
  1412.     if {"$y" != "every year"} {
  1413.     append rem " $y"
  1414.     set gotYear 1
  1415.     }
  1416.  
  1417.     # Check for repetition
  1418.     if {$repbut} {
  1419.     if {!$gotDay || !$gotMon || !$gotYear} {
  1420.         error "All components of a date must be specified if you wish to use the repeat feature."
  1421.     }
  1422.     append rem " *[$w.repdays cget -text]"
  1423.     }
  1424.  
  1425.     return $rem
  1426. }
  1427.  
  1428. #---------------------------------------------------------------------------
  1429. # CreateReminder2 -- Create the first part of a type-2 reminder
  1430. # Arguments:
  1431. #    w -- add reminder dialog window
  1432. # Returns: first part of reminder
  1433. #---------------------------------------------------------------------------
  1434. proc CreateReminder2 {w} {
  1435.     set wkday [$w.wkday2 cget -text]
  1436.     if {"$wkday" == "weekday"} {
  1437.     set wkday [GetWeekend $w 0]
  1438.     }
  1439.     set day [$w.day2 cget -text]
  1440.     set mon [$w.mon2 cget -text]
  1441.     set year [$w.year2 cget -text]
  1442.     set rem "REM $wkday $day"
  1443.     if {$mon != "every month"} {
  1444.     append rem " $mon"
  1445.     }
  1446.     if {$year != "every year"} {
  1447.     append rem " $year"
  1448.     }
  1449.     return $rem
  1450. }
  1451.  
  1452. #---------------------------------------------------------------------------
  1453. # CreateReminder3 -- Create the first part of a type-3 reminder
  1454. # Arguments:
  1455. #    w -- add reminder dialog window
  1456. # Returns: first part of reminder
  1457. #---------------------------------------------------------------------------
  1458. proc CreateReminder3 {w} {
  1459.     global MonthNames DidOmit
  1460.     set which [$w.ordinal cget -text]
  1461.     set day [$w.wkday3 cget -text]
  1462.     set mon [$w.mon3 cget -text]
  1463.     set year [$w.year3 cget -text]
  1464.     set rem "REM"
  1465.     if {$which != "Last"} {
  1466.     if {$which == "First"} {
  1467.         append rem " 1"
  1468.     } elseif {$which == "Second"} {
  1469.         append rem " 8"
  1470.     } elseif {$which == "Third"} {
  1471.         append rem " 15"
  1472.     } elseif {$which == "Fourth"} {
  1473.         append rem " 22"
  1474.     }
  1475.     if {$day != "weekday"} {
  1476.         append rem " $day"
  1477.     } else {
  1478.         append rem " [GetWeekend $w 0]"
  1479.     }
  1480.     if {$mon != "every month"} {
  1481.         append rem " $mon"
  1482.     }
  1483.     if {$year != "every year"} {
  1484.         append rem " $year"
  1485.     }
  1486.     } else {
  1487.     if {$day != "weekday"} {
  1488.         append rem " $day 1 --7"
  1489.     } else {
  1490.         append rem " 1 -1 OMIT [GetWeekend $w 1]"
  1491.         set DidOmit 1
  1492.     }
  1493.     if {$mon != "every month"} {
  1494.         set i [lsearch -exact $MonthNames $mon]
  1495.         if {$i == 11} {
  1496.         set i 0
  1497.         } else {
  1498.         incr i
  1499.         }
  1500.         append rem " [lindex $MonthNames $i]"
  1501.     }
  1502.     if {$year != "every year"} {
  1503.         if {$mon == "December"} {
  1504.         incr year
  1505.         }
  1506.         append rem " $year"
  1507.     }
  1508.     }
  1509.     return $rem
  1510. }
  1511.  
  1512. #---------------------------------------------------------------------------
  1513. # GetWeekend -- returns a list of weekdays or weekend days
  1514. # Arguments:
  1515. #    w -- add reminder dialog window
  1516. #    wkend -- if 1, we want weekend.  If 0, we want weekdays.
  1517. # Returns:
  1518. #    list of weekdays or weekend-days
  1519. #---------------------------------------------------------------------------
  1520. proc GetWeekend {w wkend} {
  1521.     global dSaturday dSunday dMonday dTuesday dWednesday dThursday dFriday
  1522.     global EnglishDayNames
  1523.     set ret {}
  1524.     foreach d $EnglishDayNames {
  1525.     set v [set d$d]
  1526.     if {$v == $wkend} {
  1527.         lappend ret $d
  1528.     }
  1529.     }
  1530.     return $ret
  1531. }
  1532.  
  1533. #---------------------------------------------------------------------------
  1534. # EditReminder -- allow user to edit what gets put in reminder file
  1535. # Arguments:
  1536. #    rem -- current reminder
  1537. #    args -- buttons to add to bottom
  1538. # Returns:
  1539. #    edited version of rem
  1540. #---------------------------------------------------------------------------
  1541. proc EditReminder {rem args} {
  1542.     catch {destroy .edit}
  1543.     global ModifyDialogResult
  1544.     toplevel .edit
  1545.     wm title .edit "TkRemind Preview reminder"
  1546.     wm iconname .edit "Preview reminder"
  1547.     text .edit.t -width 80 -height 5 -relief sunken
  1548.     .edit.t insert end $rem
  1549.     frame .edit.f
  1550.     set n 0
  1551.     foreach but $args {
  1552.     incr n
  1553.     button .edit.but$n -text $but -command "set ModifyDialogResult $n"
  1554.     pack .edit.but$n -in .edit.f -side left -fill x -expand 1
  1555.     }
  1556.     pack .edit.t -side top -fill both -expand 1
  1557.     pack .edit.f -side top -fill x -expand 1
  1558.     bind .edit <KeyPress-Escape> ".edit.but1 invoke"
  1559.     set ModifyDialogResult 0
  1560.     CenterWindow .edit
  1561.     tkwait visibility .edit
  1562.     set oldFocus [focus]
  1563.     focus .edit.t
  1564.     grab .edit
  1565.     tkwait variable ModifyDialogResult
  1566.     catch {focus $oldFocus}
  1567.     set rem [.edit.t get 1.0 end]
  1568.     catch {destroy .edit}
  1569.     return $rem
  1570. }
  1571.  
  1572. #---------------------------------------------------------------------------
  1573. # SetWinAttr -- sets an attribute for a window
  1574. # Arguments:
  1575. #    w -- window name
  1576. #    attr -- attribute name
  1577. #    val -- value to set it to
  1578. # Returns:
  1579. #    $val
  1580. #---------------------------------------------------------------------------
  1581. proc SetWinAttr {w attr val} {
  1582.     global attrPriv
  1583.     set attrPriv($w-$attr) $val
  1584. }
  1585.  
  1586. #---------------------------------------------------------------------------
  1587. # GetWinAttr -- gets an attribute for a window
  1588. # Arguments:
  1589. #    w -- window name
  1590. #    attr -- attribute name
  1591. # Returns:
  1592. #    Value of attribute
  1593. #---------------------------------------------------------------------------
  1594. proc GetWinAttr {w attr} {
  1595.     global attrPriv
  1596.     return $attrPriv($w-$attr)
  1597. }
  1598.  
  1599. #---------------------------------------------------------------------------
  1600. # WaitWinAttr -- wait for a window attribute to change
  1601. # Arguments:
  1602. #    w -- window name
  1603. #    attr -- attribute name
  1604. # Returns:
  1605. #    Value of attribute
  1606. #---------------------------------------------------------------------------
  1607. proc WaitWinAttr {w attr} {
  1608.     global attrPriv
  1609.     tkwait variable attrPriv($w-$attr)
  1610.     return $attrPriv($w-$attr)
  1611. }
  1612.  
  1613. #---------------------------------------------------------------------------
  1614. # BrowseForFile -- creates and operates a file browser dialog.
  1615. # Arguments:
  1616. #    w -- dialog window.
  1617. #    title -- dialog title
  1618. #    oktext -- text for "OK" button
  1619. #    showdots -- if non-zero, shows "dot" files as well.
  1620. # Returns:
  1621. #    complete path of filename chosen, or "" if Cancel pressed.
  1622. #---------------------------------------------------------------------------
  1623. proc BrowseForFile {w title {oktext "OK"} {showdots 0} {filter "*"}} {
  1624.     catch {destroy $w}
  1625.     toplevel $w
  1626.     wm title $w $title
  1627.  
  1628.     # Global array to hold window attributes
  1629.     global a${w}
  1630.  
  1631.     SetWinAttr $w status busy
  1632.     SetWinAttr $w showdots $showdots
  1633.  
  1634.     frame $w.fileframe
  1635.     frame $w.butframe
  1636.     label $w.cwd -text [pwd]
  1637.     entry $w.entry
  1638.     label $w.masklab -text "Match: "
  1639.     listbox $w.list -yscrollcommand "$w.scroll set"
  1640.     scrollbar $w.scroll -command "$w.list yview"
  1641.     button $w.ok -text $oktext -command "BrowseForFileOK $w"
  1642.     button $w.cancel -text "Cancel" -command "BrowseForFileCancel $w"
  1643.     entry $w.filter -width 7
  1644.     $w.filter insert end $filter
  1645.  
  1646.     pack $w.cwd $w.entry -side top -expand 0 -fill x
  1647.     pack $w.fileframe -side top -expand 1 -fill both
  1648.     pack $w.butframe -side top -expand 0 -fill x
  1649.     pack $w.list -in $w.fileframe -side left -expand 1 -fill both
  1650.     pack $w.scroll -in $w.fileframe -side left -expand 0 -fill y
  1651.     pack $w.ok -in $w.butframe -side left -expand 1 -fill x
  1652.     pack $w.cancel -in $w.butframe -side left -expand 1 -fill x
  1653.     pack $w.masklab -in $w.butframe -side left -expand 0
  1654.     pack $w.filter -in $w.butframe -side left -expand 1 -fill x
  1655.  
  1656.     # Fill in the box and wait for status to change
  1657.     BrowseForFileRead $w [pwd]
  1658.  
  1659.     bind $w <KeyPress-Escape> "$w.cancel flash; $w.cancel invoke"
  1660.     bind $w.list <Button-1> "$w.entry delete 0 end; $w.entry insert 0 \[selection get\]"
  1661.     bind $w.list <Double-Button-1> "$w.ok flash; $w.ok invoke"
  1662.     bind $w.list <Return> "$w.entry delete 0 end; $w.entry insert 0 \[selection get\]; $w.ok flash; $w.ok invoke"
  1663.     bind $w.entry <Return> "$w.ok flash; $w.ok invoke"
  1664.     bind $w.filter <Return> "BrowseForFileRead $w"
  1665.     bind $w.entry <KeyPress> "CompleteFile $w"
  1666.     bind $w.entry <KeyPress-space> "ExpandFile $w"
  1667.     bindtags $w.entry "Entry $w.entry $w all"
  1668.  
  1669.     bindtags $w.list "Listbox $w.list $w all"
  1670.     CenterWindow $w
  1671.     set oldFocus [focus]
  1672.     tkwait visibility $w
  1673.     focus $w.entry
  1674.     set oldGrab [grab current $w]
  1675.     grab set $w
  1676.     WaitWinAttr $w status
  1677.     catch {focus $oldFocus}
  1678.     catch {grab set $oldGrab}
  1679.     set ans [GetWinAttr $w status]
  1680.     destroy $w
  1681.     return $ans
  1682. }
  1683.  
  1684. proc CompleteFile {w} {
  1685.     set index [lsearch [$w.list get 0 end] [$w.entry get]* ]
  1686.     if {$index > -1} {
  1687.     $w.list see $index
  1688.     $w.list selection clear 0 end
  1689.     $w.list selection set $index
  1690.     }
  1691. }
  1692.  
  1693. proc ExpandFile {w} {
  1694.     set stuff [$w.list curselection]
  1695.     if {[string compare $stuff ""]} {
  1696.     $w.entry delete 0 end
  1697.     $w.entry insert end [$w.list get $stuff]
  1698.     }
  1699. }
  1700.  
  1701. proc BrowseForFileCancel {w} {
  1702.     SetWinAttr $w status {}
  1703. }
  1704.  
  1705. proc BrowseForFileOK {w} {
  1706.     set fname [$w.entry get]
  1707.     if {[string compare $fname ""]} {
  1708.     # If it starts with a slash, handle it specially.
  1709.     if {[string match "/*" $fname]} {
  1710.         if {[file isdirectory $fname]} {
  1711.         BrowseForFileRead $w $fname
  1712.         return
  1713.         } else {
  1714.         SetWinAttr $w status $fname
  1715.         return
  1716.         }
  1717.     }
  1718.     if {[string match */ $fname]} {
  1719.         set fname [string trimright $fname /]
  1720.     }
  1721.     if {[$w.cwd cget -text] == "/"} {
  1722.         set fname "/$fname"
  1723.     } else {
  1724.         set fname "[$w.cwd cget -text]/$fname"
  1725.     }
  1726.     # If it's a directory, change directories
  1727.     if {[file isdirectory $fname]} {
  1728.         BrowseForFileRead $w $fname
  1729.     } else {
  1730.         SetWinAttr $w status $fname
  1731.     }
  1732.     }
  1733. }
  1734.  
  1735. #---------------------------------------------------------------------------
  1736. # BrowseForFileRead -- read the current directory into the file browser
  1737. # Arguments:
  1738. #    w -- window name
  1739. #    dir -- directory
  1740. # Returns:
  1741. #    nothing
  1742. #---------------------------------------------------------------------------
  1743. proc BrowseForFileRead {w {dir ""}} {
  1744.     # Save working dir
  1745.     set cwd [pwd]
  1746.     if {$dir == ""} {
  1747.     set dir [$w.cwd cget -text]
  1748.     }
  1749.     if {[catch "cd $dir" err]} {
  1750.     tk_dialog .error Error "$err" error 0 Ok
  1751.     return
  1752.     }
  1753.     $w.cwd configure -text [pwd]
  1754.     if {[GetWinAttr $w showdots]} {
  1755.     set flist [glob -nocomplain .* *]
  1756.     } else {
  1757.     set flist [glob -nocomplain *]
  1758.     }
  1759.     set flist [lsort $flist]
  1760.     set filter [$w.filter get]
  1761.     if {$filter == ""} {
  1762.     set filter "*"
  1763.     }
  1764.     $w.list delete 0 end
  1765.     foreach item $flist {
  1766.     if {$item != "." && $item != ".."} {
  1767.         if {[file isdirectory $item]} {
  1768.         $w.list insert end "$item/"
  1769.         } else {
  1770.         if {[string match $filter $item]} {
  1771.             $w.list insert end $item
  1772.         }
  1773.         }
  1774.     }
  1775.     }
  1776.     if {[pwd] != "/"} {
  1777.     $w.list insert 0 "../"
  1778.     }
  1779.     cd $cwd
  1780.     $w.entry delete 0 end
  1781. }
  1782.  
  1783. #---------------------------------------------------------------------------
  1784. # StartBackgroundRemindDaemon
  1785. # Arguments:
  1786. #    none
  1787. # Returns:
  1788. #    nothing
  1789. # Description:
  1790. #    Starts a background Remind daemon to handle timed reminders
  1791. #---------------------------------------------------------------------------
  1792. proc StartBackgroundRemindDaemon {} {
  1793.     global Remind DaemonFile ReminderFile
  1794.     set problem [catch { set DaemonFile [open "|$Remind -z0 $ReminderFile" "r+"] } err]
  1795.     if {$problem} {
  1796.     tk_dialog .error Error "Can't start Remind daemon in background: $err" error 0 OK
  1797.     } else {
  1798.     fileevent $DaemonFile readable "DaemonReadable $DaemonFile"
  1799.     puts $DaemonFile "STATUS"
  1800.     flush $DaemonFile
  1801.     }
  1802. }
  1803.  
  1804. #---------------------------------------------------------------------------
  1805. # StopBackgroundRemindDaemon
  1806. # Arguments:
  1807. #    none
  1808. # Returns:
  1809. #    nothing
  1810. # Description:
  1811. #    Stops the background Remind daemon
  1812. #---------------------------------------------------------------------------
  1813. proc StopBackgroundRemindDaemon {} {
  1814.     global DaemonFile
  1815.     catch {
  1816.     puts $DaemonFile "EXIT"
  1817.     flush $DaemonFile
  1818.     close $DaemonFile
  1819.     }
  1820. }
  1821.  
  1822. #---------------------------------------------------------------------------
  1823. # RestartBackgroundRemindDaemon
  1824. # Arguments:
  1825. #    none
  1826. # Returns:
  1827. #    nothing
  1828. # Description:
  1829. #    Restarts the background Remind daemon
  1830. #---------------------------------------------------------------------------
  1831. proc RestartBackgroundRemindDaemon {} {
  1832.     global DaemonFile
  1833.     catch {
  1834.     puts $DaemonFile "REREAD"
  1835.     flush $DaemonFile
  1836.     }
  1837. }
  1838.  
  1839. #---------------------------------------------------------------------------
  1840. # DaemonReadable
  1841. # Arguments:
  1842. #    file -- file channel that is readable
  1843. # Returns:
  1844. #    nothing
  1845. # Description:
  1846. #    Reads data from the Remind daemon and handles it appropriately
  1847. #---------------------------------------------------------------------------
  1848. proc DaemonReadable { file } {
  1849.     global Ignore
  1850.     set line ""
  1851.     catch { set num [gets $file line] }
  1852.     if {$num < 0} {
  1853.     catch { close $file }
  1854.     return
  1855.     }
  1856.     switch -glob -- $line {
  1857.     "NOTE reminder*" {
  1858.         scan $line "NOTE reminder %s %s %s" time now tag
  1859.         IssueBackgroundReminder $file $time $now $tag
  1860.     }
  1861.     "NOTE newdate" {
  1862.         # Date has rolled over -- clear "ignore" list
  1863.         catch { unset Ignore}
  1864.         Initialize
  1865.         FillCalWindow
  1866.     }
  1867.     "NOTE reread" {
  1868.         puts $file "STATUS"
  1869.         flush $file
  1870.     }
  1871.     "NOTE queued*" {
  1872.         scan $line "NOTE queued %d" n
  1873.         if {$n == 1} {
  1874.         .b.nqueued configure -text "1 reminder queued"
  1875.         } else {
  1876.         .b.nqueued configure -text "$n reminders queued"
  1877.         }
  1878.     }
  1879.     default {
  1880.         puts "Unknown message from daemon: $line\n"
  1881.     }
  1882.     }
  1883. }
  1884.  
  1885. #---------------------------------------------------------------------------
  1886. # IssueBackgroundReminder
  1887. # Arguments:
  1888. #    file -- file channel that is readable
  1889. #    time -- time of reminder
  1890. #    now -- current time according to Remind daemon
  1891. #    tag -- tag for reminder, or "*" if no tag
  1892. # Returns:
  1893. #    nothing
  1894. # Description:
  1895. #    Reads a background reminder from daemon and pops up window.
  1896. #---------------------------------------------------------------------------
  1897. proc IssueBackgroundReminder { file time now tag } {
  1898.     global BgCounter Option Ignore
  1899.     if {$Option(Deiconify)} {
  1900.     wm deiconify .
  1901.     }
  1902.  
  1903.     set msg ""
  1904.     set line ""
  1905.     while (1) {
  1906.     gets $file line
  1907.     if {$line == "NOTE endreminder"} {
  1908.         break
  1909.     }
  1910.     if {$msg != ""} {
  1911.         append msg "\n";
  1912.     }
  1913.     append msg $line
  1914.     }
  1915.     # Do nothing if it's blank -- was probably a RUN-type reminder.
  1916.     if {$msg == ""} {
  1917.     return
  1918.     }
  1919.  
  1920.     # Do nothing if user told us to ignore this reminder
  1921.     if {[info exists Ignore($tag)]} {
  1922.     return
  1923.     }
  1924.  
  1925.     incr BgCounter
  1926.     set w .bg$BgCounter
  1927.     toplevel $w
  1928.     wm iconname $w "Reminder"
  1929.     wm title $w "Timed reminder ($time)"
  1930.     label $w.l -text "Reminder for $time issued at $now"
  1931.     message $w.msg -width 6i -text $msg
  1932.     frame $w.b
  1933.     button $w.ok -text "OK" -command "destroy $w"
  1934.     if {$tag != "*"} {
  1935.     button $w.nomore -text "Don't remind me again" -command \
  1936.         "destroy $w; set Ignore($tag) 1"
  1937.     }
  1938.     pack $w.l -side top
  1939.     pack $w.msg -side top -expand 1 -fill both
  1940.     pack $w.b -side top
  1941.     pack $w.ok -in $w.b -side left
  1942.     if {$tag != "*"} {
  1943.     pack $w.nomore -in $w.b -side left
  1944.     }
  1945.     
  1946.     CenterWindow $w
  1947.  
  1948.     # Automatically shut down window after a minute if option says so
  1949.     if {$Option(AutoClose)} {
  1950.     after 60000 "catch { destroy $w }"
  1951.     }
  1952.  
  1953.     update
  1954.     if {$Option(RingBell)} {
  1955.     bell
  1956.     }
  1957.     if {$Option(RunCmd) != ""} {
  1958.     if {$Option(FeedReminder)} {
  1959.         FeedReminderToCommand $Option(RunCmd) $msg
  1960.     } else {
  1961.         exec "/bin/sh" "-c" $Option(RunCmd) "&"
  1962.     }
  1963.     }
  1964.  
  1965.     # reread status
  1966.     if {$file != "stdin"} {
  1967.     puts $file "STATUS"
  1968.     flush $file
  1969.     }
  1970. }
  1971.  
  1972. #***********************************************************************
  1973. # %PROCEDURE: FeedReminderToCommand
  1974. # %ARGUMENTS:
  1975. #  cmd -- command to execute
  1976. #  msg -- what to feed it
  1977. # %RETURNS:
  1978. #  Nothing
  1979. # %DESCRIPTION:
  1980. #  Feeds "$msg" to a command.
  1981. #***********************************************************************
  1982. proc FeedReminderToCommand { cmd msg } {
  1983.     catch {
  1984.     set f [open "|$cmd" "w"]
  1985.     fconfigure $f -blocking 0
  1986.     fileevent $f writable [list CommandWritable $f $msg]
  1987.     }
  1988. }
  1989.  
  1990. #***********************************************************************
  1991. # %PROCEDURE: CommandWritable
  1992. # %ARGUMENTS:
  1993. #  f -- file which is writable
  1994. #  msg -- message to write
  1995. # %RETURNS:
  1996. #  Nothing
  1997. # %DESCRIPTION:
  1998. #  Writes $msg to $f; closes $f.
  1999. #***********************************************************************
  2000. proc CommandWritable { f msg } {
  2001.     puts $f $msg
  2002.     flush $f
  2003.     close $f
  2004. }
  2005.  
  2006.  
  2007. proc main {} {    
  2008.     global AppendFile HighestTagSoFar DayNames
  2009.     puts "\nTkRemind Copyright (c) 1996-1998 by David F. Skoll\n"
  2010.     LoadOptions
  2011.     CreateMoonImages
  2012.     Initialize
  2013.     ScanForTags $AppendFile
  2014.     CreateCalWindow $DayNames
  2015.     FillCalWindow
  2016.     StartBackgroundRemindDaemon
  2017.     DisplayTimeContinuously
  2018. }
  2019.  
  2020. #***********************************************************************
  2021. # %PROCEDURE: ScanForTags
  2022. # %ARGUMENTS:
  2023. #  fname -- name of file to scan
  2024. # %RETURNS:
  2025. #  Nothing
  2026. # %DESCRIPTION:
  2027. #  Scans the file for all tags of the form "TKTAGnnnn" and builds
  2028. #  the tag array.  Also adjusts HighestTagSoFar
  2029. #***********************************************************************
  2030. proc ScanForTags { fname } {
  2031.     global HighestTagSoFar ReminderTags
  2032.     if {[catch { set f [open $fname "r"]}]} {
  2033.     return
  2034.     }
  2035.     while {[gets $f line] >= 0} {
  2036.     switch -regexp -- $line {
  2037.         {^# TKTAG[0-9]+} {
  2038.         regexp {^# TKTAG([0-9]+)} $line dummy tagno
  2039.         if {$tagno > $HighestTagSoFar} {
  2040.             set HighestTagSoFar $tagno
  2041.         }
  2042.         set ReminderTags($tagno) 1
  2043.         }
  2044.     }
  2045.     }
  2046.     close $f
  2047. }
  2048.  
  2049. #***********************************************************************
  2050. # %PROCEDURE: ReadTaggedOptions
  2051. # %ARGUMENTS:
  2052. #  tag -- tag to match
  2053. # %RETURNS:
  2054. #  A list of options for the dialog box for the tagged reminder
  2055. # %DESCRIPTION:
  2056. #  Scans the file for specified tag and returns the "options" list for the
  2057. #  reminder.
  2058. #***********************************************************************
  2059. proc ReadTaggedOptions { tag } {
  2060.     global AppendFile
  2061.     if {[catch { set f [open $AppendFile "r"]}]} {
  2062.     return ""
  2063.     }
  2064.     while {[gets $f line] >= 0} {
  2065.     if {[string match "# $tag *" $line]} {
  2066.         gets $f line
  2067.         close $f
  2068.         return [string range $line 2 end]
  2069.     }
  2070.     }
  2071.     close $f
  2072.     return ""
  2073. }
  2074.  
  2075. #***********************************************************************
  2076. # %PROCEDURE: GetCurrentReminder
  2077. # %ARGUMENTS:
  2078. #  w -- text window
  2079. # %RETURNS:
  2080. #  The tag (TKTAGnnnn) for current editable reminder, or "" if no
  2081. #  current editable reminder.
  2082. #***********************************************************************
  2083. proc GetCurrentReminder { w } {
  2084.     set tags [$w tag names current]
  2085.     set index [lsearch -glob $tags "TKTAG*"]
  2086.     if {$index < 0} {
  2087.     return ""
  2088.     }
  2089.     set tag [lindex $tags $index]
  2090.     return $tag
  2091. }
  2092.  
  2093. #***********************************************************************
  2094. # %PROCEDURE: TaggedEnter
  2095. # %ARGUMENTS:
  2096. #  w -- text window
  2097. # %RETURNS:
  2098. #  Nothing
  2099. # %DESCRIPTION:
  2100. #  Highlights an "editable" reminder as mouse moves into it
  2101. #***********************************************************************
  2102. proc TaggedEnter { w } {
  2103.     set tag [GetCurrentReminder $w]
  2104.     if {$tag != ""} {
  2105.     $w tag configure $tag -foreground #FF0000
  2106.     }
  2107. }
  2108. #***********************************************************************
  2109. # %PROCEDURE: TaggedLeave
  2110. # %ARGUMENTS:
  2111. #  w -- text window
  2112. # %RETURNS:
  2113. #  Nothing
  2114. # %DESCRIPTION:
  2115. #  Removes highlight from an "editable" reminder as mouse leaves it
  2116. #***********************************************************************
  2117. proc TaggedLeave { w } {
  2118.     set tag [GetCurrentReminder $w]
  2119.     if {$tag != ""} {
  2120.     $w tag configure $tag -foreground #000000
  2121.     }
  2122. }
  2123.  
  2124. #***********************************************************************
  2125. # %PROCEDURE: EditTaggedReminder
  2126. # %ARGUMENTS:
  2127. #  w -- text window
  2128. # %RETURNS:
  2129. #  Nothing
  2130. # %DESCRIPTION:
  2131. #  Opens a dialog box to edit the current editable reminder
  2132. #***********************************************************************
  2133. proc EditTaggedReminder { w } {
  2134.     global ModifyDialogResult
  2135.     set tag [GetCurrentReminder $w]
  2136.     if {$tag == ""} {
  2137.     return
  2138.     }
  2139.  
  2140.     # Read in options
  2141.     set opts [ReadTaggedOptions $tag]
  2142.     if {$opts == ""} {
  2143.     return
  2144.     }
  2145.  
  2146.     toplevel .mod
  2147.     CreateModifyDialog .mod 1 0 "Cancel" "Replace reminder" "Delete reminder" "Preview reminder"
  2148.     wm title .mod "TkRemind Edit Reminder..."
  2149.     wm iconname .mod "Edit Reminder"
  2150.     OptionsToRemindDialog .mod $opts
  2151.  
  2152.     tkwait visibility .mod
  2153.     set oldFocus [focus]
  2154.     while {1} {
  2155.     grab .mod
  2156.     focus .mod.entry
  2157.     set ModifyDialogResult -1
  2158.     tkwait variable ModifyDialogResult
  2159.     if {$ModifyDialogResult == 1} {
  2160.         catch {focus $oldFocus}
  2161.         destroy .mod
  2162.         return 0
  2163.     }
  2164.     set problem [catch {set rem [CreateReminder .mod]} err]
  2165.     if {$problem} {
  2166.         tk_dialog .error Error "$err" error 0 Ok
  2167.         continue
  2168.     }
  2169.     if {$ModifyDialogResult == 4} {
  2170.         set rem [EditReminder $rem "Cancel" "Replace reminder"]
  2171.         if {$ModifyDialogResult == 1} {
  2172.         continue
  2173.         }
  2174.     }
  2175.     set opts [RemindDialogToOptions .mod]
  2176.     catch {focus $oldFocus}
  2177.     destroy .mod
  2178.     set problem [catch {
  2179.         if {$ModifyDialogResult == 2} {
  2180.         ReplaceTaggedReminder $tag $rem $opts
  2181.         } else {
  2182.         DeleteTaggedReminder $tag
  2183.         }
  2184.     } err]
  2185.     if {$problem} {
  2186.         tk_dialog .error Error "Error: $err" error 0 Ok
  2187.         return 1
  2188.     }
  2189.  
  2190.     FillCalWindow
  2191.     RestartBackgroundRemindDaemon
  2192.     return 0
  2193.     }
  2194. }
  2195.  
  2196. #***********************************************************************
  2197. # %PROCEDURE: UniqueFileName
  2198. # %ARGUMENTS:
  2199. #  stem -- base name of file
  2200. # %RETURNS:
  2201. #  A filename of the form "stem.xxx" which does not exist
  2202. #***********************************************************************
  2203. proc UniqueFileName { stem } {
  2204.     set n 1
  2205.     while {[file exists $stem.$n]} {
  2206.     incr n
  2207.     }
  2208.     return $stem.$n
  2209. }
  2210.  
  2211.  
  2212. #***********************************************************************
  2213. # %PROCEDURE: DeleteTaggedReminder
  2214. # %ARGUMENTS:
  2215. #  tag -- tag of reminder to delete
  2216. # %RETURNS:
  2217. #  Nothing
  2218. # %DESCRIPTION:
  2219. #  Deletes tagged reminder from reminder file
  2220. #***********************************************************************
  2221. proc DeleteTaggedReminder { tag } {
  2222.     global AppendFile
  2223.  
  2224.     set tmpfile [UniqueFileName $AppendFile]
  2225.     set out [open $tmpfile "w"]
  2226.     set in [open $AppendFile "r"]
  2227.  
  2228.     set foundStart 0
  2229.     set foundEnd 0
  2230.  
  2231.     while {[gets $in line] >= 0} {
  2232.     if {[string match "# $tag *" $line]} {
  2233.         set foundStart 1
  2234.         break
  2235.     }
  2236.     puts $out $line
  2237.     }
  2238.  
  2239.     if {! $foundStart} {
  2240.     close $in
  2241.     close $out
  2242.     file delete $tmpfile
  2243.     error "Did not find start of reminder with tag $tag"
  2244.     }
  2245.  
  2246.     while {[gets $in line] >= 0} {
  2247.     if { $line == "# TKEND"} {
  2248.         set foundEnd 1
  2249.         break
  2250.     }
  2251.     }
  2252.  
  2253.     if {! $foundEnd} {
  2254.     close $in
  2255.     close $out
  2256.     file delete $tmpfile
  2257.     error "Did not find end of reminder with tag $tag"
  2258.     }
  2259.  
  2260.     while {[gets $in line] >= 0} {
  2261.     puts $out $line
  2262.     }
  2263.     close $in
  2264.     close $out
  2265.     file rename -force -- $tmpfile $AppendFile
  2266. }
  2267.  
  2268. #***********************************************************************
  2269. # %PROCEDURE: ReplaceTaggedReminder
  2270. # %ARGUMENTS:
  2271. #  tag -- tag of reminder to replace
  2272. #  rem -- text to replace it with
  2273. #  opts -- edit options
  2274. # %RETURNS:
  2275. #  Nothing
  2276. # %DESCRIPTION:
  2277. #  Replaces a tagged reminder in the reminder file
  2278. #***********************************************************************
  2279. proc ReplaceTaggedReminder { tag rem opts } {
  2280.     global AppendFile
  2281.  
  2282.     set tmpfile [UniqueFileName $AppendFile]
  2283.     set out [open $tmpfile "w"]
  2284.     set in [open $AppendFile "r"]
  2285.  
  2286.     set foundStart 0
  2287.     set foundEnd 0
  2288.  
  2289.     while {[gets $in line] >= 0} {
  2290.     if {[string match "# $tag *" $line]} {
  2291.         set foundStart 1
  2292.         break
  2293.     }
  2294.     puts $out $line
  2295.     }
  2296.  
  2297.     if {! $foundStart} {
  2298.     close $in
  2299.     close $out
  2300.     file delete $tmpfile
  2301.     error "Did not find start of reminder with tag $tag"
  2302.     }
  2303.  
  2304.     # Consume the old reminder
  2305.     while {[gets $in line] >= 0} {
  2306.     if { $line == "# TKEND"} {
  2307.         set foundEnd 1
  2308.         break
  2309.     }
  2310.     }
  2311.  
  2312.     if {! $foundEnd} {
  2313.     close $in
  2314.     close $out
  2315.     file delete $tmpfile
  2316.     error "Did not find end of reminder with tag $tag"
  2317.     }
  2318.  
  2319.     # Write the new reminder
  2320.     WriteReminder $out $tag $rem $opts
  2321.  
  2322.     # Copy rest of file over
  2323.     while {[gets $in line] >= 0} {
  2324.     puts $out $line
  2325.     }
  2326.     close $in
  2327.     close $out
  2328.     file rename -force -- $tmpfile $AppendFile
  2329. }
  2330.  
  2331. #***********************************************************************
  2332. # %PROCEDURE: WriteReminder
  2333. # %ARGUMENTS:
  2334. #  out -- file to write to
  2335. #  tag -- reminder tag
  2336. #  rem -- reminder body
  2337. #  opts -- edit options
  2338. # %RETURNS:
  2339. #  Nothing
  2340. # %DESCRIPTION:
  2341. #  Writes a reminder to a file
  2342. #***********************************************************************
  2343. proc WriteReminder { out tag rem opts } {
  2344.     puts $out "# $tag Next reminder was created with TkRemind.  DO NOT EDIT"
  2345.     puts $out "# $opts"
  2346.     if {[string range $rem 0 3] == "REM "} {
  2347.     puts $out "REM TAG $tag [string range $rem 4 end]"
  2348.     } else {
  2349.     puts $out $rem
  2350.     }
  2351.     puts $out "# TKEND"
  2352. }
  2353.  
  2354. #***********************************************************************
  2355. # %PROCEDURE: DoShadeSpecial
  2356. # %ARGUMENTS:
  2357. #  n -- calendar box to shade
  2358. #  stuff -- Remind command line
  2359. # %RETURNS:
  2360. #  Nothing
  2361. # %DESCRIPTION:
  2362. #  Handles the "SHADE" special -- shades a box.
  2363. #***********************************************************************
  2364. proc DoShadeSpecial { n stuff } {
  2365.     set num [scan $stuff "%d %d %d" r g b]
  2366.     if {$num == 1} {
  2367.     set g $r
  2368.     set b $r
  2369.     } elseif {$num != 3} {
  2370.     return
  2371.     }
  2372.     if {$r < 0 || $r > 255 || $g < 0 || $g > 255 || $b < 0 || $b > 255} {
  2373.     return
  2374.     }
  2375.     set bg [format "#%02x%02x%02x" $r $g $b]
  2376.     .cal.t$n configure -background $bg
  2377. }
  2378.  
  2379. #***********************************************************************
  2380. # %PROCEDURE: DoMoonSpecial
  2381. # %ARGUMENTS:
  2382. #  n -- calendar box for moon
  2383. #  stuff -- Remind command line
  2384. # %RETURNS:
  2385. #  Nothing
  2386. # %DESCRIPTION:
  2387. #  Handles the "MOON" special -- draws a moon symbol
  2388. #***********************************************************************
  2389. proc DoMoonSpecial { n stuff } {
  2390.     set msg ""
  2391.     set num [scan $stuff "%d %d %d %s" phase junk1 junk2 msg]
  2392.     if {$num < 1} {
  2393.     return
  2394.     }
  2395.     if {$phase < 0 || $phase > 3} {
  2396.     return
  2397.     }
  2398.     switch -exact -- $phase {
  2399.     0 { set image new }
  2400.     1 { set image first }
  2401.     2 { set image full }
  2402.     3 { set image last }
  2403.     }
  2404.     .cal.t$n configure -state normal
  2405.     .cal.t$n image create end -image $image
  2406.  
  2407.     if {$msg != ""} {
  2408.     .cal.t$n insert end " $msg"
  2409.     }
  2410.     .cal.t$n insert end "\n"
  2411.     .cal.t$n configure -state disabled
  2412. }
  2413. #***********************************************************************
  2414. # %PROCEDURE: DisplayTime
  2415. # %ARGUMENTS:
  2416. #  None
  2417. # %RETURNS:
  2418. #  Nothing
  2419. # %DESCRIPTION:
  2420. #  Displays current date and time in status window
  2421. #***********************************************************************
  2422. proc DisplayTime {} {
  2423.     set msg [clock format [clock seconds] -format "%e %b %Y %I:%M%p"]
  2424.     Status $msg
  2425. }
  2426.  
  2427. #***********************************************************************
  2428. # %PROCEDURE: CreateMoonImages
  2429. # %ARGUMENTS:
  2430. #  None
  2431. # %RETURNS:
  2432. #  Nothing
  2433. # %DESCRIPTION:
  2434. #  Creates the moon images "new", "first", "full" and "last"
  2435. #***********************************************************************
  2436. proc CreateMoonImages {} {
  2437.     image create bitmap full -foreground black \
  2438.         -data "#define newmoon_width 16\n#define newmoon_height 16\nstatic unsigned char newmoon_bits[] = {\n0x00, 0x00, 0xc0, 0x01, 0x30, 0x06, 0x0c, 0x18, 0x04, 0x10, 0x02, 0x20,\n0x02, 0x20, 0x01, 0x40, 0x01, 0x40, 0x01, 0x40, 0x02, 0x20, 0x02, 0x20,\n0x04, 0x10, 0x0c, 0x18, 0x30, 0x06, 0xc0, 0x01};"
  2439.     image create bitmap first -foreground black \
  2440.         -data "#define firstquarter_width 16\n#define firstquarter_height 16\nstatic unsigned char firstquarter_bits[] = {\n0x00, 0x00, 0xc0, 0x01, 0xf0, 0x06, 0xfc, 0x18, 0xfc, 0x10, 0xfe, 0x20,\n0xfe, 0x20, 0xff, 0x40, 0xff, 0x40, 0xff, 0x40, 0xfe, 0x20, 0xfe, 0x20,\n0xfc, 0x10, 0xfc, 0x18, 0xf0, 0x06, 0xc0, 0x01};"
  2441.     image create bitmap new -foreground black \
  2442.         -data "#define fullmoon_width 16\n#define fullmoon_height 16\nstatic unsigned char fullmoon_bits[] = {\n0x00, 0x00, 0xc0, 0x01, 0xf0, 0x07, 0xfc, 0x1f, 0xfc, 0x1f, 0xfe, 0x3f,\n0xfe, 0x3f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xfe, 0x3f, 0xfe, 0x3f,\n0xfc, 0x1f, 0xfc, 0x1f, 0xf0, 0x07, 0xc0, 0x01};"
  2443.     image create bitmap last -foreground black \
  2444.         -data "#define lastquarter_width 16\n#define lastquarter_height 16\nstatic unsigned char lastquarter_bits[] = {\n0x00, 0x00, 0xc0, 0x01, 0xb0, 0x07, 0x8c, 0x1f, 0x84, 0x1f, 0x82, 0x3f,\n0x82, 0x3f, 0x81, 0x7f, 0x81, 0x7f, 0x81, 0x7f, 0x82, 0x3f, 0x82, 0x3f,\n0x84, 0x1f, 0x8c, 0x1f, 0xb0, 0x07, 0xc0, 0x01};"
  2445. }
  2446.  
  2447. #***********************************************************************
  2448. # %PROCEDURE: DisplayTimeContinuously
  2449. # %ARGUMENTS:
  2450. #  None
  2451. # %RETURNS:
  2452. #  Nothing
  2453. # %DESCRIPTION:
  2454. #  Continuously displays current date and time in status window,
  2455. #  updating once a minute
  2456. #***********************************************************************
  2457. proc DisplayTimeContinuously {} {
  2458.     DisplayTime
  2459.     set secs [clock format [clock seconds] -format "%S"]
  2460.     # Doh -- don't interpret as an octal number if leading zero
  2461.     scan $secs "%d" decSecs
  2462.     set decSecs [expr 60 - $decSecs]
  2463.     after [expr $decSecs * 1000] DisplayTimeContinuously
  2464. }
  2465. main
  2466.  
  2467. # For debugging only...
  2468. #fileevent stdin readable "DaemonReadable stdin"
  2469. #Initialize
  2470. #CreateCalWindow $DayNames
  2471. #ConfigureCalWindow March 1998 0 31
  2472.