## wv_timeline.tcl - a web version of the Timeline widget.  Hard-wired
##  are the names of the three themes, the start and end times of the
##  "data' of the three themes, and the size of the boxes in the
##  timeline...
#
##  created by Rob Edsall  July 24, 1999

set themes {rainfall fires landslides}

set StartTime(rainfall) {93 4 1 12 0}
set EndTime(rainfall)   {93 4 29 12 0}
set StartTime(fires) {93 4 1 12 0}
set EndTime(fires)   {93 5 1 0 0}
set StartTime(landslides) {93 1 1 0 0}
set EndTime(landslides) {93 12 31 0 0}

set boxLength(0) 96.
set boxLength(1) 120.
set boxLength(2) 96.
set boxLength(3) 120.
set boxLength(4) 15.

set font -linotype-palatino-medium-r-normal-*-14-90-*-*-*-*-*-*
set ifont -linotype-palatino-medium-i-normal-*-14-90-*-*-*-*-*-*
set bigfnt -linotype-palatino-medium-r-normal-*-18-90-*-*-*-*-*-*

# clor is the color of each timeline.

set clor(0) DarkSeaGreen4
set clor(1) Tan2
set clor(2) Brown3

set span {year month day hour minute}

# no_units is the number of whatevers in whatever... no_units(0) is the
# number of months in a year, no_units(1) is the number of days
# in a month (in general), etc.  This is used for graphical purposes.

set no_units(-1) 1.0
set no_units(0) 12.0
set no_units(1) 30.0
set no_units(2) 24.0
set no_units(3) 60.0
set no_units(4) 60.0

set wd 480

## create the bitmaps for the buttons... in the non-web
## version, these would be in separate X11 bitmap files.

image create bitmap allb -data "
#define allBack.bmp_width 16
#define allBack.bmp_height 16
static unsigned char allBack.bmp_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x1b, 0xc0, 0x1b, 0xf8, 0x1b, 0xfe, 0x1b, 0xf8, 0x1b, 0xe0, 0x1b,
   0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

"

image create bitmap allf -data "
#define allFront.bmp_width 16
#define allFront.bmp_height 16
static unsigned char allFront.bmp_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0xd8, 0x00, 0xd8, 0x07, 0xd8, 0x1f, 0xd8, 0x7f, 0xd8, 0x1f, 0xd8, 0x03,
   0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
"

image create bitmap back -data "
#define back.bmp_width 16
#define back.bmp_height 16
static unsigned char back.bmp_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x0c, 0x80, 0x0f, 0xe0, 0x0f, 0xf8, 0x0f, 0xe0, 0x0f, 0x80, 0x0f,
   0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
"

image create bitmap frnt -data "
#define front.bmp_width 16
#define front.bmp_height 16
static unsigned char front.bmp_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x30, 0x00, 0xf0, 0x01, 0xf0, 0x07, 0xf0, 0x1f, 0xf0, 0x07, 0xf0, 0x01,
   0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
"

image create bitmap magn -data "
#define magIn.bmp_width 16
#define magIn.bmp_height 16
static unsigned char magIn.bmp_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03,
   0x60, 0x0c, 0x20, 0x09, 0x10, 0x11, 0xd0, 0x17, 0x10, 0x11, 0x20, 0x09,
   0x70, 0x0c, 0xb8, 0x03, 0x10, 0x00, 0x00, 0x00};
"

image create bitmap mago -data "
#define magout.bmp_width 16
#define magout.bmp_height 16
static unsigned char magout.bmp_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x60, 0x0c, 0x20, 0x08,
   0x10, 0x10, 0xd0, 0x17, 0x10, 0x10, 0x20, 0x08, 0x60, 0x0c, 0x80, 0x03,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
"

image create bitmap lock -data "
#define lock.bmp_width 16
#define lock.bmp_height 16
static unsigned char lock.bmp_bits[] = {
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x60, 0x06,
   0x20, 0x04, 0x20, 0x04, 0xf0, 0x0f, 0xf0, 0x0f, 0x70, 0x0e, 0x70, 0x0e,
   0xf0, 0x0f, 0x70, 0x0e, 0xf0, 0x0f, 0x00, 0x00};
"
 

##  figureDays determines the number of days in the duration for each
##   theme.  It's supplied a startdate and an enddate (in SY SM SD, and
##   EY, EM, and ED) and returns the number of days, inclusive, as
##   $days.

proc figureDays {SY EY SM EM SD ED} {

 set n [expr $EY-$SY]
 set days [expr 365*$n]

  if {$SM == 1} {
     set days \
   [expr $days+((31 - $SD) + 335)]
 
  } elseif {$SM == 2} {
     set days \
   [expr $days+((28 - $SD) + 307)]
  } elseif {$SM == 3} {
     set days \
   [expr $days+((31 - $SD) + 276)]
  } elseif {$SM == 4} {
     set days \
   [expr $days+((30 - $SD) + 246)]
  } elseif {$SM == 5} {
     set days \
   [expr $days+((31 - $SD) + 215)]
  } elseif {$SM == 6} {
     set days \
     [expr $days+((30 - $SD) + 185)]
  } elseif {$SM == 7} {
     set days \
   [expr $days+((31 - $SD) + 154)]
  } elseif {$SM == 8} {
     set days \
   [expr $days+((31 - $SD) + 123)]
  } elseif {$SM == 9} {
     set days \
   [expr $days+((30 - $SD) + 93)]
  } elseif {$SM == 10} {
     set days \
   [expr $days+((31 - $SD) + 62)]
  } elseif {$SM == 11} {
     set days \
   [expr $days+((30 - $SD) + 32)]
  } else {
     set days \
   [expr $days+(31 - $SD)]
  }
 
  if {[expr fmod($SY,4) == 0] && \
   $SM < 3 && $EM > 2} {
   set days [expr $days + 1]
  }
 
  if {$EM == 1} {
     set days \
   [expr $days - (334 + (31 - $ED))]
  } elseif {$EM == 2} {
     set days \
   [expr $days - (306 + (28 - $ED))]
  } elseif {$EM == 3} {
     set days \
   [expr $days - (275 + (31 - $ED))]
      } elseif {$EM == 4} {
     set days \
   [expr $days - (245 + (30 - $ED))]
  } elseif {$EM == 5} {
     set days \
   [expr $days - (214 + (31 - $ED))]
  } elseif {$EM == 6} {
     set days \
   [expr $days - (184 + (30 - $ED))]
  } elseif {$EM == 7} {
     set days \
   [expr $days - (153 + (31 - $ED))]
  } elseif {$EM == 8} {
     set days \
   [expr $days - (122 + (31 - $ED))]
  } elseif {$EM == 9} {
     set days \
   [expr $days - (92 + (30 - $ED))]
  } elseif {$EM == 10} {
     set days \
   [expr $days - (61 + (31 - $ED))]
  } elseif {$EM == 11} {
     set days \
   [expr $days - (31 + (30 - $ED))]
  } else {
     set days \
   [expr $days - (31 - $ED)]
  }
 

  if {[expr fmod($EY,4) == 0] && \
   $EM > 2 && \
   $SY != $EY} {

   set days [expr $days + 1]
  }
 

 if {[expr $EY - $SY] > 1} {

     foreach year \
       {[expr $SY+1] [expr $EY-1]} {
  set $days [expr $days+365]
  if {[expr fmod($year,4)] == 0} {
     set $days [expr $days+1]
  }
     }
 }

return $days
}

## mag -- "zooms" to the next scale, out or in.
##

proc mag {theme arg} {
 global unit

 if {
  $unit($theme) < 4 && \
  $arg == 1 || \
  $arg == -1 && \
  $unit($theme) > -1
 } {
  set unit($theme) [expr $unit($theme) + $arg]

  MakeTimeline $theme $unit($theme)
 }
}

##
## makeTimeline creates the linear timelines for each theme.
##
##
proc MakeTimeline {i u} {

   global boxLength number start end font clor wd
   global wdSr no_units bL_first bL_last bL_inside
   global ff themes resolution frac wdBoxes bigfnt

   set region {0 0 20}
   set wd 480

 # bL_first is the length of the first rectangle.
 # bL_inside is the total
 # length of all of the boxes between the
 # first and last.  bL_last is the
 # length of the last rectangle.

 # wdSr is the width of the underlying
 #  scrollable region for the theme.

   set region [linsert $region 2 $wdSr($i,$u)]

 #  .$i.c is the frame that all of
 #   the stuff is packaged into.
 #  .$i.c.mark has the little line
 #   that marks the display date.
 #  .$i.c.canvas is the window
 #   through which you look to see
 #   the big rectangle with the timeline on it.

   catch {destroy .$i.c}
   frame .$i.c -borderwidth 1 -relief sunken
   canvas .$i.c.mark1 -height 10 -width $wd -borderwidth 0
   canvas .$i.c.mark2 -height 30 -width $wd -borderwidth 0

   scrollbar .$i.c.xscroll -orient horizontal \
  -command ".$i.c.canvas xview"

   canvas .$i.c.canvas  -height 30 -width $wd \
 -borderwidth 1 -relief sunken \
      -xscrollcommand "canScr $i $u" -scrollregion $region

 # start with the canvas at the far left of the srcollregion.
 #  (frac(rainfall) = 0)

   .$i.c.canvas xview moveto \
 [expr $frac($i)*($wdBoxes($i,$u)/$wdSr($i,$u))]
 

# ************ MAKING THE TIMELINE******************************
 
# _____the first rectangle in the timeline is usually incomplete____
 
 # xs, xe, xt are the x-locations of the
 #  box (and text) coordinates.  It uses bL_first
 #  to determine the boxLength of the first rect.
   set xs [expr $wd/2]
   set xe [expr $xs + $bL_first($i,$u) - 1]
   set xt [expr $xs + ($xe-$xs)/2]

 # the box is 8 units tall and $xe-$xs units wide.
   .$i.c.canvas create rectangle \
 $xs 20 $xe 28 -fill $clor($i) -outline gray
 
 # the text is created using the GetLabel procedure
   .$i.c.canvas create text \
 $xt 10  -text [GetLabel $i $u 0] -font $font
# __________________________________________________________________

# ______ the complete rectangles between the first and last rects___

   set h 0
 
 # if there are no inside boxes (only the first and last),
 #  then bL_inside is zero... if not, then create the
 #  inside boxes.
   if {$bL_inside($i,$u) != 0} {

 # xs1 is the x-coord of the left of the second
 # (first interior) box.
     set xs1 [expr $xe + 1]
 
 # repeat for all interior boxes.
     for {set j 0} {$j < [expr $number($i,$u) - 2]} {incr j 1} {
 set xs [expr $xs1 + $j*$boxLength($u)]
  set xe [expr $xs + $boxLength($u)-1]
  set xt [expr $xs + ($boxLength($u)/2)]
  .$i.c.canvas create rectangle \
  $xs 20 $xe 28 -fill $clor($i) -outline gray

  .$i.c.canvas create text \
  $xt 10 -text [GetLabel $i $u [expr $j+1]] -font $font
 
 incr h

      }
   }
# _________________________________________________________________

# ________ the last rectangle, usually incomplete. ________________

   if {$bL_last($i,$u) != 0} {
     set xs [expr $xe + 1]
     set xe [expr $xs + $bL_last($i,$u)]
     set xt [expr $xs + ($xe-$xs)/2]
     .$i.c.canvas create rectangle \
  $xs 20 $xe 28 -fill $clor($i) -outline gray
     .$i.c.canvas create text \
  $xt 10  -text [GetLabel $i $u [expr $h+1]] -font $font
   }
#___________________________________________________________________
#********************************************************************
 

 # on what scale?
   if {$u == 0} {
    set u_text "years"
   } elseif {$u == 1} {
    set u_text "months"
   } elseif {$u == 2} {
    set u_text "days"
   } elseif {$u == 3} {
    set u_text "hours"
   } else {
    set u_text "minutes"
   }

   .$i.c.mark2 create text \
 [expr $wd-50] 10 -text $u_text -font $bigfnt
   .$i.c.mark2 create text \
 [expr ($wd/2)] 7 -text "display date" -font $font
   .$i.c.mark1 create line \
 [expr ($wd/2)] 0 [expr ($wd/2)] 10 -width 0.5 -fill black
   .$i.c.mark2 create line \
 [expr ($wd/2)] 20 [expr ($wd/2)] 30 -width 0.5 -fill black

 # pack the elements of the timeline in the frame...
   pack .$i.c.xscroll -side bottom -fill x
   pack .$i.c.mark1 -side bottom
   pack .$i.c.canvas -side bottom -fill x
   pack .$i.c.mark2 -side bottom
   pack .$i.c

}

## puts the proper label over each rectangle...
##  depends on scale of timeline

proc GetLabel {j u i} {
   global start

 set daylist {31 28 31 30 31 30 31 31 30 31 30 31}

 if {$u == 0} {
  return [expr $start($j,$u)+$i]
 } elseif {$u == 1} {
   set lab [expr int(fmod([expr $start($j,$u)+$i],12))]
   if {$lab == 0} {
   set lab 12
   set labels "Dec"
  } elseif {$lab == 1} {
   set labels "Jan"
  } elseif {$lab == 2} {
   set labels "Feb"
  } elseif {$lab == 3} {
   set labels "Mar"
  } elseif {$lab == 4} {
   set labels "Apr"
  } elseif {$lab == 5} {
   set labels "May"
  } elseif {$lab == 6} {
   set labels "Jun"
  } elseif {$lab == 7} {
   set labels "Jul"
  } elseif {$lab == 8} {
   set labels "Aug"
  } elseif {$lab == 9} {
   set labels "Sep"
  } elseif {$lab == 10} {
   set labels "Oct"
  } elseif {$lab == 11} {
   set labels "Nov"
  } elseif {$lab == 12} {
   set labels "Dec"
  }
  return $labels
 } elseif {$u == 3} {
  set label [expr int(fmod([expr $start($j,$u)+$i],24))]
  return $label
 } elseif {$u == 4} {
  set label [expr int(fmod([expr $start($j,$u)+$i],60))]
  return $label
 } elseif {$u == 2} {

  set month $start($j,1)
  set subtr 0
  set cumda [lindex $daylist [expr $start($j,1)-1]]

  for {set d 0} {$d <= $i} {incr d 1} {

   set day [expr $d + $start($j,2)]
  if {$day <= $cumda} {
   set label [expr $day - $subtr]
  } else {
   set subtr $cumda
   set label [expr $day - $subtr]
   incr cumda [lindex $daylist $month]
   incr month 1
   if {$month == 13} {
   set month 1
   }
  }
   }
 return $label
 }
}

 

#  canScr - canvas scroll procedure - ff is the *fraction* of the
# scrollbar of the left side of the slider.  i.e. if the slider is
# to the far left, ff is 0.0, but if it's to the far right, it's
# close to 1.0 (but not exactly 1.0... it's technically equal to
# 1.0 - (width of canvas/width of scrollregion)

proc canScr {j u args} {

      global ff lf bound boxLength offset diffStart
 global frac unit wd wdSr themes wdBoxes

 # see above for the description of ff.
 set ff($j,$u) [lindex $args 0]
 set lf [lindex $args 1]

 # ************
 # check for bindings... if one timeline is bound to another,
 #  this loop will move that timeline using the other's scrollbar.
 set i 0
 foreach k $themes {
   if {$i != $j && $bound($j,$i) == 1} {
    set a \
  [expr ($offset($j,$i)- \
  $diffStart($j,$i,[expr $unit($j)+1])) \
  * (1-($wd/$wdSr($i,$unit($i))))]
    set b [expr ($wdSr($i,$unit($i))-$wd)]
    set c [expr $ff($j,$u)*$wdSr($j,$unit($j))/$wdSr($i,$unit($i))]

  # ff($i,$u) is the fraction of the canvas to the left
  # of the bound timeline (corresponding to $i)
    set ff($i,$u) [expr ($a/$b) + $c]
    .$i.c.xscroll set $ff($i,$u) $lf
    .$i.c.canvas xview moveto $ff($i,$u)
         set frac($i) [expr $ff($i,$u)/($wdBoxes($i,$u)/$wdSr($i,$u))]
 
  # figure out the date corresponding to the
  #  position of the canvas.
    MkDisDate $i $frac($i) $u
     }
 incr i 1
 }
 # ************
 
 .$j.c.xscroll set $ff($j,$u) $lf
 set frac($j) [expr $ff($j,$u)/($wdBoxes($j,$u)/$wdSr($j,$u))]
 
 # figure out the date corresponding to the
 #  position of the canvas.
 MkDisDate $j $frac($j) $u
}
 

## MkDisDate:  change the date in the text of each
##  timeline accroding to the position of the canvas.
##
proc MkDisDate {j x u} {
 global wdSr start number font no_units
 global bL_first boxLength dd resolution

 set wd 480.

        # transformations from canvas space to temporal space

      set nf($j) \
  [expr $no_units($u)*($bL_first($j,$u)/$boxLength($u))]

 if {$u < 4} {
   set spot \
   [expr ($no_units($u)+1)-$nf($j)+ \
   $x*($number($j,[expr $u+1]))]
 } else {
   set spot [expr $x*60*$number($j,$u)]
 }
 
 set num_unit [expr int(($spot-1)/$no_units($u))]

 set dd($j,$u) [expr int(fmod([expr $num_unit + $start($j,$u)], \
  $no_units([expr $u-1])))]
 
 if {[expr $u - 1] >= 0} {
   set dd($j,[expr $u-1]) [expr $start($j,[expr $u-1]) + \
  int(($num_unit + $start($j,$u))/$no_units([expr $u-1]))]
 }
 
 if {[expr $u + 1] <= $resolution($j)} {
   set dd($j,[expr $u + 1]) \
   [expr int(fmod(($spot-1), $no_units($u)))]
 }
 
 for {set a 0} {$a <= 4} {incr a 1} {
        if {$dd($j,$a) < 10} {
  if {$dd($j,$a) == 0 && $a == 1} {
   set l_text($a) [expr int($no_units([expr $a-1]))]
  } elseif {$dd($j,$a) == 0 && $a == 2} {
   set l_text($a) [expr int($no_units([expr $a-1]))]
  } else {
         set l_text($a) "0$dd($j,$a)"
  }
        } else {
         set l_text($a) "$dd($j,$a)"
        }
      }
 set la_text \
   "$l_text(1) / $l_text(2) / $l_text(0)   $l_text(3):$l_text(4)"

 
      .$j.dis.l configure -text $la_text
    #  pack $w.name.dis.l -side left
}

##  buttonBar - creates the buttons for each theme.
##
proc buttonBar {i} {
 global themes
 frame .$i.buttonBar
 button .$i.buttonBar.allBack -image allb  \
   -command "fast $i 0"
 button .$i.buttonBar.back -image back \
   -command "moveIt $i -1"
 button .$i.buttonBar.front -image frnt \
   -command "moveIt $i 1"
 
 button .$i.buttonBar.allFront -image allf \
   -command "fast $i 1"
 button .$i.buttonBar.magIn -image magn \
   -command "mag $i 1"
 button .$i.buttonBar.magOut -image mago \
   -command "mag $i -1"

 pack .$i.buttonBar -side top
 pack .$i.buttonBar.allBack  \
  .$i.buttonBar.back \
   .$i.buttonBar.front \
  .$i.buttonBar.allFront \
  -side left
 pack .$i.buttonBar.magIn \
  .$i.buttonBar.magOut -side left
}

## fast -- moves the canvas and the displaydate to the
##  end or beginning of the timeline.
##
proc fast {theme arg} {
 global wdSr ff lf unit wdBoxes
 
 if {$arg == 1} {
 
  ## move to the far right.
  set $ff($theme,$unit($theme)) \
  [expr 1-(480./$wdSr($theme,$unit($theme)))]
  set $lf 1
    set frac($theme) \
  [expr $ff($theme,$unit($theme)) / \
  ($wdBoxes($theme,$unit($theme)) / \
   $wdSr($theme,$unit($theme)))]
  .$theme.c.canvas xview moveto \
  [expr 1-(480./$wdSr($theme,$unit($theme)))]
   #displayDate $w $theme 1
 
 } else {
 
  ## move to the far left.
  set $ff($theme,$unit($theme)) 0
  set $lf [expr 400./$wdSr($theme,$unit($theme))]
  set frac($theme) \
   [expr  $ff($theme,$unit($theme))/ \
  ($wdBoxes($theme,$unit($theme)) / \
   $wdSr($theme,$unit($theme)))]
       .$theme.c.canvas xview moveto 0
  #displayDate $w $theme 0
 }
}

## moveIt -- moves the timeline over one box
## (one unit at whatever resolution is displayed)
##
proc moveIt {theme arg} {
 global unit boxLength wdSr ff wdBoxes

 set rightmost [expr 1-(480/$wdSr($theme,$unit($theme)))]

 set spot [expr $ff($theme,$unit($theme)) + \
   $arg * $rightmost * $boxLength($unit($theme)) / \
   ($wdSr($theme,$unit($theme))-480.)]
 
 if {$spot < 0.0} {set spot 0.0}
 if {$spot > $rightmost} {set spot $rightmost}

 .$theme.c.canvas xview moveto $spot
 set ff($theme,$unit($theme)) $spot
 set frac($theme) \
   [expr  $ff($theme,$unit($theme))* \
  ($wdBoxes($theme,$unit($theme)) / \
   $wdSr($theme,$unit($theme)))]
 #changeDate $w $theme [expr $unit($theme)+1] $spot
 
}
 

proc binding {i} {
 global ch bound
 foreach t {0 1 2} {
  foreach s {0 1 2} {
   if {$t != $s} {
    if {$ch($t) == 1 && $ch($s) == 1} {
  set bound($t,$s) 1
    } else {
  set bound($t,$s) 0
    }
 
   }
  }
 }
}

### main program:
##

set j 0

# three themes (rainfall, landslides, fires)... each gets
# its own loop to initialize the geometry variables...
#
foreach t $themes {
   set default_detail($j) 0
  # resolution -- integer (in this case, 4) that specifies
 #  the finest resoultion of the data
   set resolution($j) [expr [llength $span]-1]
 
   set i 0

 # for each scale: get the start and end times for each theme.
   foreach item $span {
 set start($j,$i)   [lindex $StartTime($t) $i]
 set end($j,$i)     [lindex $EndTime($t) $i]

 if {$end($j,$i) - $start($j,$i) != 0 && \
  $default_detail($j) == 0} {
  if {$i != 4} {
   set default_detail($j) $i
  } else {
   set default_detail($j) 3
  }
 }
 incr i
   }

 # get the number of boxes for each scale... 0 - years
 # 1 - months, 2 - days, 3 - hours, 4 - minutes.

   set number($j,0) [expr $end($j,0)-$start($j,0)+1]

   set number($j,1) [expr 12*($number($j,0)) - (12-$end($j,1)) \
      - ($start($j,1)-1)]
   set number($j,2) \
  [figureDays $start($j,0) $end($j,0) $start($j,1) $end($j,1)\
  $start($j,2) $end($j,2)]

   set number($j,3) [expr 24*($number($j,2)) - (24-$end($j,3)) \
     - ($start($j,3)-1)]
   set number($j,4) [expr 60*($number($j,3)) - (60-$end($j,4)) \
     - ($start($j,4)-1)]
   set unit($j) $default_detail($j)

 # set length of first and last boxes according to
 # the fraction of the first and last (year, month,
 # day, etc.) in the data.
   for {set u 0} {$u <= $resolution($j)} {incr u 1} {
     if {$number($j,$u) != 1} {
  # how big should the first box be?
       if {$u != $resolution($j)} {
  set bL_first($j,$u)  [expr $boxLength($u)*($no_units($u) - \
     $start($j,[expr $u+1]))/$no_units($u)]
       } else {
  set bL_first($j,$u) $boxLength($u)
       }
   # are there interior boxes?
  if {$number($j,$u) != 2} {
  set bL_inside($j,$u) \
   [expr $boxLength($u)*[expr $number($j,$u) - 2]]
       } else {
  set bL_inside($j,$u) 0
       }
  # how big should the last box be?
       if {$u != $resolution($j)} {
         set bL_last($j,$u)  \
  [expr $boxLength($u)* \
  (($end($j,[expr $u+1])+1)/$no_units($u))]
       } else {
  set bL_last($j,$u) $boxLength($u)
       }
  # wdSr - the width of the canvas... the sum of the
  #  widths of all the boxes plus "padding" on either
  #  side of the timeline
       set wdSr($j,$u) [expr $wd + $bL_first($j,$u) + \
  $bL_inside($j,$u) + $bL_last($j,$u)]

     } else {

  # if there's only one box at that scale (e.g. there'd
  #  be only one box for the year scale if the duration
  #  of the data were from June 1999 to December 1999
       if {$u == $resolution($j)} {
  set bL_first($j,$u) $boxLength($u)
       } else {
        if {$number($j,[expr $u+1]) != 1} {
            set bL_first($j,$u) \
      [expr ($number($j,[expr $u+1])\
   /$no_units($u))*$boxLength($u)]
         } else {
     set bL_first($j,$u) \
      [expr (1/$no_units($u))*$boxLength($u)]
         }
        set bL_last($j,$u)   0
        set bL_inside($j,$u) 0
        set wdSr($j,$u) [expr $wd + $bL_first($j,$u)]
       }
     }
 # wdBoxes is the sum of the widths of the boxes
   set wdBoxes($j,$u) [expr $wdSr($j,$u) - $wd]
 # start at the far left.
   set ff($j,$u) 0.0
   }
   set frac($j) 0
   incr j
}

## how many years, months, days, etc different
##  are the start times between
##  the themes? Also, initialize bindings and offsets.

set i 0
foreach s $themes {
  set j 0
  foreach t $themes {
   set diffStart($j,$i,0) [expr $start($j,0)-$start($i,0)]
   set diffStart($s,$i,1) [expr 12*$diffStart($j,$i,0) \
     - (12-$start($i,1)) \
      - ($start($j,1)-1)]
   set diffStart($j,$i,2) [figureDays $start($j,0) \
     $start($i,0) $start($j,1) \
     $start($i,1) $start($j,2) $start($i,2)]
   set diffStart($j,$i,3) [expr 24*$diffStart($j,$i,2)\
     -$start($j,3)+ $start($i,3)]
   set diffStart($j,$i,4) [expr 60*$diffStart($j,$i,3)-\
     $start($j,4)+ $start($i,4)]
   set bound($i,$j) 0
   set offset($i,$j) 0
  incr j 1
 }
incr i 1
}

# display date defaults to start time.

set j 0
foreach t $themes {
 for {set i 0} {$i <= 4} {incr i 1} {
  set dd($j,$i) $start($j,$i)
 }
incr j 1
}

## get the canvases for each theme to appear in the Tcl window (.)
##

set i 0
foreach t $themes {

 frame .$i -width 500 -height 200 -relief sunken -borderwidth 2
 frame .$i.dis
 
 for {set u 0} {$u <= 4} {incr u 1} {
  if {$dd($i,$u) < 10} {
   set l_text($u) "0$dd($i,$u)"
  } else {
   set l_text($u) "$dd($i,$u)"
  }
  }
 label .$i.dis.t -text $t -font $bigfnt
 set la_text "$l_text(1) / $l_text(2) / $l_text(0) \
   $l_text(3):$l_text(4)"
 label .$i.dis.l -text $la_text -font $font

 pack .$i
 pack .$i.dis -side right
 pack .$i.dis.t .$i.dis.l -side top

 buttonBar $i
 MakeTimeline $i $unit($i)
 incr i
}

## the binding checkbuttons...
##

set ch(0) 0
set ch(1) 0
set ch(2) 0

checkbutton .0.dis.chck0 -image lock \
 -selectimage lock -indicatoron 0 \
 -variable ch(0)  -command "binding 0"
pack .0.dis.chck0 -side top -pady 10

checkbutton .1.dis.chck1 -image lock \
 -selectimage lock -indicatoron 0 \
 -variable ch(1)  -command "binding 1"
pack .1.dis.chck1 -side top -pady 10

checkbutton .2.dis.chck2 -image lock \
 -selectimage lock -indicatoron 0 \
 -variable ch(2)  -command "binding 2"
pack .2.dis.chck2 -side top -pady 10

frame .l -width 600 -height 300 -relief raised -bd 1
label .l.l -wraplength 500 -font $bigfnt -text "The linear timelines.\
  Assuming that the user has imported three\
'themes' of varying temporal duration, the user has the option of\
changing the display date (what is represented in the display-animation)\
of individual themes or binding two or more themes together to\
be animated at the same time.  Use the lock icons to bind two themes\
together.  The forward/backward VCR controls \
move the theme one unit forward or backward; the fast-forward/fast-backward \
controls move the timeline to the start or end of the theme's duration.\
  The magnifying tools 'zoom' to a finer or coarser temporal scale.  In so\
doing, the user can control the database time between frames of the\
animation: a forward motion with 'hours' visible advances one hour,\
while the same action with the 'days' visible advances one day."

pack .l -side top -fill both -expand yes -padx 20 -pady 10
pack .l.l