
# This code is shared by all the ICEM CFD GUI's.
#
# Copyright (c) 1993 - 1995 Pacific Marketing and Consulting, Inc,
#       and ICEM Systems, GmbH.  All rights reserved.
# Author:  Wayne A. Christopher, wayne@icemcfd.com

# Each element of specs is a list of points.

proc curve_viewer {w title geo xlabel ylabels specs done_cmd rescale_cmd
    	xmess xint ylog syms xaxis_labels} {
    global curve_length curve_xlabel curve_ylabel curve_smooth
    global curve_num curve_symbols
    global curve_lines curve_lim curve_title curve_modify curve_saved_specs
    global curve_xlog curve_ylog curve_xgrid curve_ygrid
    global curve_pixels curve_symtype curve_minmaxval
    global curve_rescale_cmd curve_xint curve_yint curve_background
    global curve_fullviewer curve_xaxis_labels curve_saved_ylabels
    global curve_selected curve_deleted is_win use_blt_graph curve_graph

    if {[info commands blt::graph] == ""} {
        if $is_win {
           if [catch { load blt24.dll } err] {
              set use_blt_graph 0
          } else {
              set use_blt_graph 1
          }
        } else {
          set use_blt_graph 0
        }
    } else {
      set use_blt_graph 1
    }

    set curve_xlabel($w) $xlabel
    set curve_rescale_cmd($w) $rescale_cmd
    set curve_xint($w) $xint
    set curve_yint($w) 0

    set curve_pixels($w,linew) 2
    set curve_pixels($w,circw) 1
    set curve_pixels($w,symx) 4
    set curve_pixels($w,circr) 4

    set curve_smooth($w) 0
    set curve_title($w) $title

    set curve_xlog($w) 0
    set curve_ylog($w) $ylog
    set curve_xgrid($w) 1
    set curve_ygrid($w) 1
    set curve_symbols($w) $syms
    set curve_symtype($w) o
    set curve_lines($w) 1
    set curve_modify($w) 0
    set curve_fullviewer($w) [string length $title]
    set curve_xaxis_labels($w) $xaxis_labels

    if {[winfo exists $w.c] || [winfo exists $w.main.graph]} {
	# Just add the curves to what's already there
	set ns [llength $specs]
	for {set i 0} {$i < $ns} {incr i} {
	    incr curve_num($w)
	    catch {unset curve_deleted($w,$curve_num($w))}
	}
	eval lappend curve_saved_specs($w) $specs
	eval lappend curve_saved_ylabels($w) $ylabels
	curve_setstuff $w $curve_saved_specs($w) $curve_saved_ylabels($w)
	curve_perform $w
	return
    }

    set curve_num($w) [llength $specs]
    set curve_saved_specs($w) $specs
    set curve_saved_ylabels($w) $ylabels

    for {set i 0} {$i < $curve_num($w)} {incr i} {
	catch {unset curve_deleted($w,$i)}
    }

    curve_setstuff $w $specs $ylabels

    if ![info exists curve_background($w)] { set curve_background($w) black }

    if $use_blt_graph {

        if {$curve_background($w) == "black"} {
	        set white white
        } else {
            set white black
        }
        set curve_graph(zoom) 0
        foreach v {minx maxx miny maxy} { set curve_minmaxval($w,$v) "" }
        foreach v {minx_on maxx_on miny_on maxy_on} { set curve_minmaxval($w,$v) 0 }

        if $curve_fullviewer($w) {
	    set buttons ""

	    set graph $w.main.graph
	    set legend $w.main.legend

	    set gwidth 600
	    set gheight 500

	    #lappend buttons [list Print "blt_curve_hardcopy $w"]
	    lappend buttons [list "Full range" "blt_curve_full $graph $w"]
	    lappend buttons [list Load "curve_load $w"]
	    lappend buttons [list Save "curve_save $w"]
	    lappend buttons [list Delete "curve_delete_plot $w"]
	    lappend buttons [list Done "$done_cmd"]
	    if {[form_init $w "$title" "" "$buttons" "" 1 1 1] == ""} {
		    error "Unable to create $title window.\n"
	    }
	    set com "curve_perform $w"
	    form_checkbutton $w.bottom.xlog "X log" curve_xlog($w) {1 0} "" "$com"
	    form_checkbutton $w.bottom.ylog "Y log" curve_ylog($w) {1 1} "" "$com"
	    form_checkbutton $w.bottom.symbols "Symbols" curve_symbols($w) {1 2} "" "$com"
	    form_checkbutton $w.bottom.lines "Lines" curve_lines($w) {1 3} "" "$com"
	    form_checkbutton $w.bottom.xgrid "X grid" curve_xgrid($w) {1 4} "" "$com"
	    form_checkbutton $w.bottom.ygrid "Y grid" curve_ygrid($w) {1 5} "" "$com"
	} else {
	    set graph $w.graph
	    set legend ""
	    set gwidth [$w cget -width]
	    set gheight [$w cget -height]
	}

	if ![winfo exists $graph] {
	    blt::graph $graph -plotbackground $curve_background($w) -plotrelief flat \
		-plotborderwidth 0 -topmargin 1 -rightmargin 1 \
		-width $gwidth -height $gheight
	    pack $graph -side left -fill both -expand 1
	}

        $graph legend configure -hide no -background "" -position plotarea \
                                -activebackground $curve_background($w) \
                                -anchor ne -relief flat \
                                -foreground $white -borderwidth 0

        $graph axis configure x -title "$curve_xlabel($w)" -justify left
        if $curve_xlog($w) {
          $graph axis configure x -log 1
        } else {
          $graph axis configure x -log 0
        }
        $graph axis configure y -title ""
        if $curve_ylog($w) {
          $graph axis configure y -log 1
        } else {
          $graph axis configure y -log 0
        }
        if $curve_xgrid($w) {
          $graph grid configure -mapx x
        } else {
          $graph grid configure -mapx ""
        }
        if $curve_ygrid($w) {
          $graph grid configure -mapy y
        } else {
          $graph grid configure -mapy ""
        }

        bind $graph <Configure> "curve_perform $w %w %h"
        if {$done_cmd != ""} {
            wm protocol $w WM_DELETE_WINDOW "$done_cmd"
        }
        if $curve_fullviewer($w) {
	    form_finish $geo
	}

    } else {

        # If title is "" then we assume the window is already created and sized
        if !$curve_fullviewer($w) {
	    canvas $w.c -background $curve_background($w)
        } else {
	    top_window $w 1 $title $done_cmd
	    $w configure -background $curve_background($w)
	    canvas $w.c -width 600 -height 600 -background $curve_background($w)
        }
        frame $w.buts -background $curve_background($w)

        button $w.buts.delete -text Delete -command "curve_delete_plot $w"
        button $w.buts.done -text Done -command $done_cmd
        button $w.buts.ps -text "Print" -command "curve_hardcopy $w"
        button $w.buts.full -text "Full range" -command "curve_full $w"
        button $w.buts.load -text "Load" -command "curve_load $w"
        button $w.buts.save -text "Save" -command "curve_save $w"
        checkbutton $w.buts.xlog -text "X log" -variable curve_xlog($w) -relief raised \
	    -command "curve_perform $w"
        checkbutton $w.buts.ylog -text "Y log" -variable curve_ylog($w) -relief raised \
	    -command "curve_perform $w"
        checkbutton $w.buts.symbols -text "Symbols" -variable curve_symbols($w) -relief raised \
	    -command "curve_perform $w"
        checkbutton $w.buts.lines -text "Lines" -variable curve_lines($w) -relief raised \
	    -command "curve_perform $w"
        checkbutton $w.buts.xgrid -text "X grid" -variable curve_xgrid($w) -relief raised \
	    -command "curve_perform $w"
        checkbutton $w.buts.ygrid -text "Y grid" -variable curve_ygrid($w) -relief raised \
	    -command "curve_perform $w"

        if $curve_fullviewer($w) {
	    set brc {
	        xlog 0 0 ylog 0 1 symbols 0 2 lines 0 3 xgrid 0 4 ygrid  0 5
	        ps   1 0 full 1 1 load    1 2 save  1 3 done  1 4 delete 1 5
	    }
	    foreach {b r c} $brc {
	        grid $w.buts.$b -row $r -column $c -padx 3 -pady 3 -sticky news
	    }
        }
        if {$xmess != ""} {
	    label $w.message -text $xmess
	    grid $w $w.message -row 0 -column 0 -sticky ew
        }

        grid $w.c -row 1 -column 0 -sticky news
        if $curve_fullviewer($w) {
	    grid $w.buts -row 2 -column 0 -sticky news
         }
         bind $w.c <Configure> "curve_perform $w %w %h"
         grid columnconfigure $w 1 -weight 1000


        if {$title != ""} {
	    if {$geo == ""} { set geo +100+100 }
	    top_geometry $w $geo
	    top_make_on_screen $w
        }
    }
}

proc curve_delete_plot {w} {
    global curve_selected bigfont curve_startx curve_starty curve_selected
    global curve_deleted curve_lid curve_tid use_blt_graph

    if [info exists curve_selected] return
    set curve_selected ""

    set mess "Select the plots with the left button; middle and right = done"
    if {[info exists use_blt_graph] && $use_blt_graph} {
       set graph $w.main.graph
	if ![winfo exists $graph] { set graph $w.graph }
       $graph marker create text -coords {-Inf -Inf} -outline red -name message \
        -text "$mess" -anchor sw -xoffset 5 -yoffset -5 -fill ""
    } else {
        set graph $w.c
        set t [$graph create text [expr {$curve_startx($w) + 10}] \
	       [expr {$curve_starty($w) - 10}] -text $mess \
	       -fill red -anchor sw -font $bigfont]
    }
    while 1 {
	vwait curve_selected
	if ![info exists curve_selected] {
	    if {[info exists use_blt_graph] && $use_blt_graph} {
	        catch { $graph marker delete message }
	    } else {
	        $graph delete $t
	    }
	    return ;# just in case there was an error
	}
	if {$curve_selected == ""} break

	set curve_deleted($w,$curve_selected) 1
	if {[info exists use_blt_graph] && $use_blt_graph} {
	    catch { $graph element delete $curve_lid($w,$curve_selected) }
	    catch { $graph element delete $curve_tid($w,$curve_selected) }
	} else {
	    $w.c delete curve_lid($w,$curve_selected)
	    $w.c delete curve_tid($w,$curve_selected)
	}
	unset curve_lid($w,$curve_selected)
	unset curve_tid($w,$curve_selected)
	curve_perform $w
    }
    if {[info exists use_blt_graph] && $use_blt_graph} {
        catch { $graph marker delete message }
    } else {
        $graph delete $t
    }
    unset curve_selected
}

proc curve_load {w {load_func ""}} {
    global curve_num curve_length curve_data curve_ylabel curve_fullviewer
    global curve_deleted

    set curve_fullviewer($w) 1

    set file [file_selection -message "Select a file to load the data from." \
		  -default [directory]/curve_data -title "Load curve"]
    if {$file == ""} return

    set fp [open $file r]
    catch {unset curve_deleted}
    set curve_num($w) [gets $fp]
    if {[llength $curve_num($w)] > 1} {
	set curve_data($w,0,0) $curve_num($w)
	set curve_num($w) 1
	set curve_ylabel($w,0) curve
	set j 1
	while {![eof $fp]} {
	    set cc [gets $fp]
	    if {[llength $cc] == 2} {
		set curve_data($w,0,$j) $cc
		incr j
	    }
	}
	set curve_length($w,0) $j
    } else {
	for {set i 0} {$i < $curve_num($w)} {incr i} {
	    set curve_ylabel($w,$i) [gets $fp]
	    set curve_length($w,$i) [gets $fp]
	    if {$load_func != ""} {
		eval $load_func $i \"$curve_ylabel($w,$i)\"
	    }
	    for {set j 0} {$j < $curve_length($w,$i)} {incr j} {
		set curve_data($w,$i,$j) [gets $fp]
	    }
	}
    }
    close $fp
    mess "Curve data read from $file\n"
    curve_minmax $w
    curve_perform $w
}

proc curve_save {w {save_func ""}} {
    global curve_num curve_length curve_data curve_ylabel

    set file [file_selection -message "Select a file to save the data to." \
		-title "Save curve" \
		-is_save_dialog 1 -default [directory]/curve_data \
		-new_ok 2 ]

    if {$file == ""} return

    set fp [open $file w]
    if {$curve_num($w) != 1} {
	puts $fp $curve_num($w)
	for {set i 0} {$i < $curve_num($w)} {incr i} {
	    puts $fp $curve_ylabel($w,$i)
	    puts $fp $curve_length($w,$i)
	    for {set j 0} {$j < $curve_length($w,$i)} {incr j} {
		puts $fp $curve_data($w,$i,$j)
	    }
	}
    } elseif {$save_func != ""} {
	puts $fp 1
	puts $fp [eval $save_func]
	puts $fp $curve_length($w,0)
	for {set j 0} {$j < $curve_length($w,0)} {incr j} {
	    puts $fp $curve_data($w,0,$j)
	}
    } else {
	for {set j 0} {$j < $curve_length($w,0)} {incr j} {
	    puts $fp $curve_data($w,0,$j)
	}
    }
    close $fp
    mess "Curve data written to $file\n"
}

proc curve_editor {w title geo xlabel ylabels specs {load_stuff ""} {save_stuff ""}} {
    global curve_length curve_xlabel curve_ylabel curve_smooth curve_num curve_symbols
    global curve_lines curve_lim curve_title curve_modify curve_saved_specs
    global curve_xlog curve_ylog curve_xgrid curve_ygrid curve_done curve_pixels
    global curve_symtype curve_rescale_cmd curve_data curve_xint curve_yint
    global curve_background curve_fullviewer curve_minmax curve_minmaxval
    global curve_xaxis_labels is_win use_blt_graph curve_graph

    if 0 {
	if {[info commands blt::graph] == ""} {
	    if $is_win {
		if [catch { load blt24.dll } err] {
		    set use_blt_graph 0
		} else {
		    set use_blt_graph 1
		}
	    } else {
		set use_blt_graph 0
	    }
	} else {
	    set use_blt_graph 1
	}
    }
    # We depend on the canvas bindings here
    set use_blt_graph 0

    set curve_fullviewer($w) 1

    set curve_xlabel($w) $xlabel
    set curve_xaxis_labels($w) ""
    set curve_rescale_cmd($w) ""
    set curve_xint($w) 0
    set curve_yint($w) 0

    set curve_pixels($w,linew) 2
    set curve_pixels($w,circw) 2
    set curve_pixels($w,circr) 4

    set curve_smooth($w) 0
    set curve_num($w) [llength $specs]
    set curve_title($w) $title
    set curve_saved_specs($w) $specs

    set curve_xlog($w) 0
    set curve_ylog($w) 0
    set curve_xgrid($w) 1
    set curve_ygrid($w) 1
    set curve_symbols($w) 1
    set curve_symtype($w) o
    set curve_lines($w) 1
    set curve_modify($w) 1

    curve_setstuff $w $specs $ylabels

    if ![info exists curve_background($w)] { set curve_background($w) black }

    if $use_blt_graph {

        if {$curve_background($w) == "black"} {
	    set white white
        } else {
            set white black
        }
        set curve_graph(zoom) 0
        foreach v {minx maxx miny maxy} { set curve_minmaxval($w,$v) "" }
        foreach v {minx_on maxx_on miny_on maxy_on} { set curve_minmaxval($w,$v) 0 }

        set graph $w.main.graph
        set buttons ""

        #lappend buttons [list Print "blt_curve_hardcopy $w"]
        lappend buttons [list "Full range" "blt_curve_full $graph $w"]
        lappend buttons [list "Set range" "curve_setr $w"]
        lappend buttons [list Load "curve_load $w $load_stuff"]
        lappend buttons [list Save "curve_save $w $save_stuff"]
        lappend buttons [list Cancel "set curve_done($w) 0"]
        lappend buttons [list Done "set curve_done($w) 1"]
        if {[form_init $w "$title" graph "$buttons" "" 1 1 1] == ""} {
            error "Unable to create $title window.\n"
        }

        blt::graph $graph -plotbackground $curve_background($w) -plotrelief flat \
                      -plotborderwidth 0 -topmargin 1 -rightmargin 1 -width 600 \
                      -height 600
        pack $graph -side left -fill both -expand 1

        $graph legend configure -hide no -background "" -position plotarea \
                                -activebackground $curve_background($w) \
                                -anchor ne -relief flat \
                                -foreground $white -borderwidth 0

        $graph axis configure x -title "$curve_xlabel($w)" -justify left
        if $curve_xlog($w) {
          $graph axis configure x -log 1
        } else {
          $graph axis configure x -log 0
        }
        $graph axis configure y -title ""
        if $curve_ylog($w) {
          $graph axis configure y -log 1
        } else {
          $graph axis configure y -log 0
        }
        if $curve_xgrid($w) {
          $graph grid configure -mapx x
        } else {
          $graph grid configure -mapx ""
        }
        if $curve_ygrid($w) {
          $graph grid configure -mapy y
        } else {
          $graph grid configure -mapy ""
        }

        bind $graph <Configure> "curve_perform $w %w %h"
        form_finish $geo
        tkwait variable curve_done($w)
        top_destroy $w 1

    } else {

        top_window $w 1 $title
        $w configure -background $curve_background($w)
        canvas $w.c -width 600 -height 600 -background $curve_background($w)
        frame $w.x -background $curve_background($w)
        frame $w.y -background $curve_background($w)

        frame $w.buts -background $curve_background($w)

        button $w.buts.done -text Done -command "set curve_done($w) 1"
        button $w.buts.cancel -text Cancel -command "set curve_done($w) 0"
        button $w.buts.ps -text "Print" -command "curve_hardcopy $w"
        button $w.buts.reset -text Reset
        button $w.buts.full -text "Full range" -command "curve_full $w"
        button $w.buts.setr -text "Set range" -command "curve_setr $w"
        button $w.buts.load -text "Load" -command [list curve_load $w $load_stuff]
        button $w.buts.save -text "Save" -command [list curve_save $w $save_stuff]

        foreach {b r c} {
	    full 0 0 setr  0 1 ps     0 2 load   0 3 save 0 4
	    done 0 5 reset 0 6 cancel 0 7
        } {
	    grid $w.buts.$b -row $r -column $c -padx 3 -pady 3 -sticky news
        }


        grid $w.c -row 1 -column 0 -sticky news
        grid $w.buts -row 2 -column 0 -sticky news

        bind $w.c <Configure> "curve_perform $w %w %h"

        top_geometry $w $geo
        top_make_on_screen $w
        tkwait variable curve_done($w)

        top_destroy $w 1
    }

    if $curve_done($w) {
	set specs {}
	for {set p 0} {$p < $curve_num($w)} {incr p} {
	    set spec {}
	    for {set i 0} {$i < $curve_length($w,$p)} {incr i} {
		lappend spec $curve_data($w,$p,$i)
	    }
	    lappend specs $spec
	}
	return $specs
    } else {
	return $curve_saved_specs($w)
    }
}

# -----------------------------------------------------------------

proc curve_monitor {w title text_title geo xlabel ylabels buttons ylog {width 600} {height 600} {xint 1} {subform 0}} {
    global curve_length curve_xlabel curve_ylabel curve_smooth curve_num
    global curve_symbols curve_lines curve_lim curve_title curve_modify
    global curve_saved_specs curve_xlog curve_ylog curve_xgrid curve_ygrid
    global curve_pixels curve_symtype curve_rescale_cmd curve_xint
    global curve_yint curve_background tdv_default curve_fullviewer
    global curve_xaxis_labels curve_minmaxval is_win use_blt_graph curve_graph

    if {!$subform && [winfo exists $w]} { top_destroy $w }

    if {[info commands blt::graph] == ""} {
        if $is_win {
           if [catch { load blt24.dll } err] {
              set use_blt_graph 0
          } else {
              set use_blt_graph 1
          }
        } else {
          set use_blt_graph 0
        }
    } else {
	set use_blt_graph 1
    }

    set curve_fullviewer($w) 1

    set curve_xlabel($w) $xlabel
    set curve_xaxis_labels($w) ""
    set curve_rescale_cmd($w) ""

    set curve_pixels($w,linew) 2
    set curve_pixels($w,circw) 1
    set curve_pixels($w,symx) 2
    set curve_pixels($w,circr) 2

    set curve_smooth($w) 0
    set curve_num($w) [llength $ylabels]
    if !$curve_num($w) { error "zero-length ylabel list" }
    set curve_title($w) $title
    set curve_saved_specs($w) ""
    set curve_xint($w) $xint
    set curve_yint($w) 0

    set curve_xlog($w) 0
    set curve_ylog($w) $ylog
    set curve_xgrid($w) 1
    set curve_ygrid($w) 1
    set curve_symbols($w) 1
    set curve_symtype($w) o
    set curve_lines($w) 1
    set curve_modify($w) 0
    foreach v {minx maxx miny maxy} { set curve_minmaxval($w,$v) "" }
    foreach v {minx_on maxx_on miny_on maxy_on} { set curve_minmaxval($w,$v) 0 }

    curve_setstuff $w {} $ylabels

    if ![info exists curve_background($w)] { set curve_background($w) black }
    if {$curve_background($w) == "black"} {
	set white white
    } else {
        set white black
    }
    if {![info exists curve_ncolors]} {curve_define_colors}

    if $use_blt_graph {

        set curve_graph(zoom) 0

	if $subform {
	    set bot $w.bottom
	    set graph $w.main.graph

	    form_frame $w.main flat 0 {0 0 -sticky nsew}
	    form_frame $bot flat 0 {1 0}
	    grid rowconfigure $w 0 -weight 1000

	    #form_button $bot.print Print "blt_curve_hardcopy $w" {0 0}
	    #form_button $bot.setrange "Set range" "curve_limits $w" {0 1}
	    #form_button $bot.full "Full range" "blt_curve_full $graph $w" {0 2} ""

	    set com "curve_perform $w"
	    form_checkbutton $bot.xlog "X log" curve_xlog($w) {1 0} "" "$com"
	    form_checkbutton $bot.ylog "Y log" curve_ylog($w) {1 1} "" "$com"
	    form_checkbutton $bot.symbols "Symbols" curve_symbols($w) {1 2} "" "$com"
	    form_checkbutton $bot.lines "Lines" curve_lines($w) {1 3} "" "$com"
	    form_checkbutton $bot.xgrid "X grid" curve_xgrid($w) {1 4} "" "$com"
	    form_checkbutton $bot.ygrid "Y grid" curve_ygrid($w) {1 5} "" "$com"

	    set subform 1

	} else {

	    set graph $w.main.graph

	    #lappend buttons [list Print "blt_curve_hardcopy $w"]
	    lappend buttons [list "Set range" "curve_limits $w"]
	    lappend buttons [list "Full range" "blt_curve_full $graph $w"]

	    if {[form_init $w "$title" "" "$buttons" "" 1 1 1] == ""} {
		error "Unable to create $title window.\n"
	    }
	    set com "curve_perform $w"
	    form_checkbutton $w.bottom.xlog "X log" curve_xlog($w) {1 0} "" "$com"
	    form_checkbutton $w.bottom.ylog "Y log" curve_ylog($w) {1 1} "" "$com"
	    form_checkbutton $w.bottom.symbols "Symbols" curve_symbols($w) {1 2} "" "$com"
	    form_checkbutton $w.bottom.lines "Lines" curve_lines($w) {1 3} "" "$com"
	    form_checkbutton $w.bottom.xgrid "X grid" curve_xgrid($w) {1 4} "" "$com"
	    form_checkbutton $w.bottom.ygrid "Y grid" curve_ygrid($w) {1 5} "" "$com"
	    set graph $w.main.graph

	    set subform 0
        }

        blt::graph $graph -plotbackground $curve_background($w) -plotrelief flat \
                      -plotborderwidth 0 -topmargin 1 -rightmargin 1 -width $width \
                      -height $height
        pack $graph -side left -fill both -expand 1

        $graph legend configure -hide no -background "" -position plotarea \
                                -activebackground $curve_background($w) \
                                -anchor ne -relief flat \
                                -foreground $white -borderwidth 0

        $graph axis configure x -title "$curve_xlabel($w)" -justify left
        if $curve_xlog($w) {
          $graph axis configure x -log 1
        } else {
          $graph axis configure x -log 0
        }
        $graph axis configure y -title ""
        if $curve_ylog($w) {
          $graph axis configure y -log 1
        } else {
          $graph axis configure y -log 0
        }
        if $curve_xgrid($w) {
          $graph grid configure -mapx x
        } else {
          $graph grid configure -mapx ""
        }
        if $curve_ygrid($w) {
          $graph grid configure -mapy y
        } else {
          $graph grid configure -mapy ""
        }

        bind $graph <Configure> "curve_perform $w %w %h"

	if !$subform {
	    form_finish $geo
	}

    } else {

	if !$subform {
	    top_window $w 1 $title
	}
        $w configure -background $curve_background($w)
        canvas $w.c -width $width -height $height -background $curve_background($w)
        frame $w.buts
        lappend buttons [list Print "curve_hardcopy $w"]
        lappend buttons [list "Set range" "curve_limits $w"]
        lappend buttons [list "Full range" "curve_full $w"]
        set b 0
        foreach but $buttons {
	    button $w.buts.b$b -text [lindex $but 0] -command [lindex $but 1]
	    grid $w.buts.b$b -row 1 -column $b -sticky news
	    incr b
        }
        checkbutton $w.buts.xlog -text "X log" -variable curve_xlog($w) \
	        -command "curve_perform $w"
        checkbutton $w.buts.ylog -text "Y log" -variable curve_ylog($w) \
	        -command "curve_perform $w"
        checkbutton $w.buts.symbols -text "Symbols" -variable curve_symbols($w) \
	        -command "curve_perform $w"
        checkbutton $w.buts.lines -text "Lines" -variable curve_lines($w) \
	        -command "curve_perform $w"
        checkbutton $w.buts.xgrid -text "X grid" -variable curve_xgrid($w) \
	        -command "curve_perform $w"
        checkbutton $w.buts.ygrid -text "Y grid" -variable curve_ygrid($w) \
	        -command "curve_perform $w"

        set c 0
        foreach b {xlog ylog symbols lines xgrid ygrid} {
	    grid $w.buts.$b -row 2 -column $c
            incr c
        }

        set ncol [llength $buttons]
        if {$ncol < 6} {set ncol 6}
        set maxwidth 0
        for {set i 0} {$i < $ncol} {incr i} {
	    set wid [grid columnconfigure $w.buts $i -minsize]
	    if {$wid > $maxwidth} { set maxwidth $wid }
        }
        for {set i 0} {$i < $ncol} {incr i} {
	    grid columnconfigure $w.buts $i -minsize $maxwidth -weight 1
        }

if {0} {
        label $w.ttitle -background $curve_background($w) \
            -foreground $white -text $text_title
        scrollbar $w.yscroll -relief sunken \
            -command "$w.text yview" -orient v
        text $w.text -yscroll "$w.yscroll set" -height 8 \
            -exportselection 1 -wrap word -padx 4 -pady 4 \
            -relief sunken -borderwidth 2 -background $white
}

        grid $w.c -row 0 -column 0 -sticky news -columnspan 2
        grid $w.buts -row 2 -column 0 -sticky news -columnspan 2

        grid rowconfigure $w 0 -weight 1
        grid rowconfigure $w 2 -weight 0
        grid rowconfigure $w 3 -weight 0
        grid columnconfigure $w 0 -weight 1
        grid columnconfigure $w 1 -weight 0

        bind $w.c <Configure> "curve_perform $w %w %h"

        top_geometry $w $geo
        top_make_on_screen $w
        top_minsize $w 100 100
        top_title $w $title
    }
}

proc curve_limits {w} {
    form_kill .curve_set_limits
    set d [form_init .curve_set_limits "Set range"]
    if {$d != ""} {
	form_checkbutton $d.minxl "Min X" curve_minmaxval($w,minx_on) {0 0}
	form_checkbutton $d.maxxl "Max X" curve_minmaxval($w,maxx_on) {0 2}
	form_checkbutton $d.minyl "Min Y" curve_minmaxval($w,miny_on) {1 0}
	form_checkbutton $d.maxyl "Max Y" curve_minmaxval($w,maxy_on) {1 2}
	form_entry $d.minx curve_minmaxval($w,minx) float_blank {0 1}
	form_entry $d.maxx curve_minmaxval($w,maxx) float_blank {0 3}
	form_entry $d.miny curve_minmaxval($w,miny) float_blank {1 1}
	form_entry $d.maxy curve_minmaxval($w,maxy) float_blank {1 3}
	form_finish bot
    }
    form_wait .curve_set_limits
    curve_perform $w
}

proc curve_monitor_addline {w line {color ""}} {
    global mess_tagnum; incr mess_tagnum

    set now [$w.text index end]
    $w.text insert end "$line\n"
    if {$color != ""} {
	$w.text tag add t$mess_tagnum $now "end - 1c"
	if {$color != ""} {
	    $w.text tag configure t$mess_tagnum -foreground $color
	}
    }
    $w.text yview -pickplace end
    update idle
}

proc curve_monitor_addpoint {w xval yvals} {
    global curve_saved_specs

    if ![winfo exists $w] return

    set nspecs {}
    set len [llength $yvals]
    for {set i 0} {$i < $len} {incr i} {
	set nspec [lindex $curve_saved_specs($w) $i]
	if {[lindex $yvals $i] != ""} {
	    lappend nspec [list $xval [lindex $yvals $i]]
	}
	lappend nspecs $nspec
    }
    set curve_saved_specs($w) $nspecs
}

proc curve_monitor_reset {w title} {
    global curve_saved_specs curve_title

    if ![winfo exists $w] return

    curve_setstuff $w {} {}
    set curve_title($w) $title
    set curve_saved_specs($w) {}
    curve_perform $w
}

proc curve_monitor_update {w} {
    global curve_saved_specs
    if ![winfo exists $w] return

    curve_setstuff $w $curve_saved_specs($w) {}
    curve_perform $w
}

proc curve_monitor_done {w} {
    catch {top_destroy $w}
}

# -----------------------------------------------------------------

proc curve_setstuff {w specs ylabels} {
    global curve_lim curve_dlim curve_num curve_length curve_ylabel
    global curve_data

    catch {unset curve_data}

    for {set i 0} {$i < $curve_num($w)} {incr i} {
	set spec [lindex $specs $i]
	set len [llength $spec]
	if {$ylabels != ""} {
	    set curve_ylabel($w,$i) [lindex $ylabels $i]
	}
	set curve_length($w,$i) $len

	set j 0

	foreach pt $spec {
	    set curve_data($w,$i,$j) $pt
	    set x [lindex $pt 0]; set y [lindex $pt 1]
	    if {![scan $x %f xxx] || ![scan $y %f yyy]} {
		error "Expected two floats, got \{$pt\}"
	    }
	    incr j
	}
    }
    curve_minmax $w
}

proc curve_minmax {w} {
    global curve_lim curve_dlim curve_num curve_length curve_ylabel
    global curve_data

    foreach i {minx maxx miny maxy minposx minposy} { set $i "" }
    for {set i 0} {$i < $curve_num($w)} {incr i} {
	for {set j 0} {$j < $curve_length($w,$i)} {incr j} {
	    set x [lindex $curve_data($w,$i,$j) 0]
	    set y [lindex $curve_data($w,$i,$j) 1]
	    if {($minx == "") || ($x < $minx)} { set minx $x }
	    if {($maxx == "") || ($x > $maxx)} { set maxx $x }
	    if {($miny == "") || ($y < $miny)} { set miny $y }
	    if {($maxy == "") || ($y > $maxy)} { set maxy $y }
	    if {(($minposx == "") || ($x < $minposx)) && ($x > 0)} {
		set minposx $x
	    }
	    if {(($minposy == "") || ($y < $minposy)) && ($y > 0)} {
		set minposy $y
	    }
	}
    }

    if {$minx == ""} {
	# There were no points.
	set minx 0; set miny 0
	set maxx 1; set maxy 1
	set minposx 0.1; set maxposy 0.1
    }
    if {$miny == $maxy} {
	set miny [expr {$miny - 0.01}]
	set maxy [expr {$maxy + 0.01}]
    }
    if {$minx == $maxx} {
	set minx [expr {$minx - 0.01}]
	set maxx [expr {$maxx + 0.01}]
    }

    foreach i {minx maxx miny maxy minposx minposy} {
	set curve_lim($w,$i) [set $i]
	set curve_dlim($w,$i) [set $i]
    }
}

proc curve_updownbuts {w x y} {
    global tdv_library

    button $x.up -bitmap @$tdv_library/hup.xbm -command "curve_mod $w xd 0.3"
    button $x.dn -bitmap @$tdv_library/hdn.xbm -command "curve_mod $w xu 0.3"
    button $x.inc -bitmap @$tdv_library/hexpand.xbm -command "curve_mod $w xe 0.3"
    button $x.dec -bitmap @$tdv_library/hshrink.xbm -command "curve_mod $w xs 0.3"

    button $y.up -bitmap @$tdv_library/vup.xbm -command "curve_mod $w yd 0.3"
    button $y.dn -bitmap @$tdv_library/vdn.xbm -command "curve_mod $w yu 0.3"
    button $y.inc -bitmap @$tdv_library/vexpand.xbm -command "curve_mod $w ye 0.3"
    button $y.dec -bitmap @$tdv_library/vshrink.xbm -command "curve_mod $w ys 0.3"

    pack $x.dn $x.inc $x.dec $x.up -side left -padx 2 -pady 2 -expand 1
    pack $y.up $y.inc $y.dec $y.dn -side top -padx 2 -pady 2 -expand 1
}

proc curve_full {w} {
    global curve_minmaxval
    foreach i {minx maxx miny maxy} {
	if [info exists curve_minmaxval($w,${i}_on)] {
	    set curve_minmaxval($w,${i}_on) 0
	}
    }
    curve_minmax $w
    curve_perform $w
}

proc curve_setr {w} {
    global curve_dlim curve_lim

    form_kill .curve_set_range
    set d [form_init .curve_set_range "Set range"]
    if {$d != ""} {
	form_label $d.minxl "Min X" {0 0}
	form_label $d.maxxl "Max X" {0 2}
	form_label $d.minyl "Min Y" {1 0}
	form_label $d.maxyl "Max Y" {1 2}
	form_entry $d.minx curve_dlim($w,minx) float {0 1}
	form_entry $d.maxx curve_dlim($w,maxx) float {0 3}
	form_entry $d.miny curve_dlim($w,miny) float {1 1}
	form_entry $d.maxy curve_dlim($w,maxy) float {1 3}
	form_finish bot
    }
    if ![form_wait .curve_set_range] return
    foreach i {minx maxx miny maxy} { set curve_lim($w,$i) $curve_dlim($w,$i) }
    curve_perform $w
}

proc curve_mod {w what pct} {
    global curve_lim

    set dx [expr {($curve_lim($w,maxx) - $curve_lim($w,minx)) * $pct}]
    set dy [expr {($curve_lim($w,maxy) - $curve_lim($w,miny)) * $pct}]

    case $what in {
	xe {
	    set curve_lim($w,maxx) [expr {$curve_lim($w,maxx) + $dx}]
	    set curve_lim($w,minx) [expr {$curve_lim($w,minx) - $dx}]
	}
	xs {
	    set curve_lim($w,maxx) [expr {$curve_lim($w,maxx) - $dx}]
	    set curve_lim($w,minx) [expr {$curve_lim($w,minx) + $dx}]
	}
	xu {
	    set curve_lim($w,maxx) [expr {$curve_lim($w,maxx) + $dx}]
	    set curve_lim($w,minx) [expr {$curve_lim($w,minx) + $dx}]
	}
	xd {
	    set curve_lim($w,maxx) [expr {$curve_lim($w,maxx) - $dx}]
	    set curve_lim($w,minx) [expr {$curve_lim($w,minx) - $dx}]
	}
	ye {
	    set curve_lim($w,maxy) [expr {$curve_lim($w,maxy) + $dy}]
	    set curve_lim($w,miny) [expr {$curve_lim($w,miny) - $dy}]
	}
	ys {
	    set curve_lim($w,maxy) [expr {$curve_lim($w,maxy) - $dy}]
	    set curve_lim($w,miny) [expr {$curve_lim($w,miny) + $dy}]
	}
	yu {
	    set curve_lim($w,maxy) [expr {$curve_lim($w,maxy) + $dy}]
	    set curve_lim($w,miny) [expr {$curve_lim($w,miny) + $dy}]
	}
	yd {
	    set curve_lim($w,maxy) [expr {$curve_lim($w,maxy) - $dy}]
	    set curve_lim($w,miny) [expr {$curve_lim($w,miny) - $dy}]
	}
    }
    if {$curve_lim($w,minx) > 0} { set curve_lim($w,minposx) $curve_lim($w,minx) }
    if {$curve_lim($w,miny) > 0} { set curve_lim($w,minposy) $curve_lim($w,miny) }
    curve_perform $w
}

proc curve_perform {w {width 0} {height 0}} {
    global curve_num curve_dlim curve_lim curve_rescale_cmd curve_selected
    global curve_deleted use_blt_graph

    if {[info exists use_blt_graph] && $use_blt_graph} {
	if [winfo exists $w.main.graph] {
	    set graph $w.main.graph
	} else {
	    set graph $w.graph
	}
    } else {
        set graph $w.c
    }
    if !$width { set width [winfo width $graph] }
    if !$height { set height [winfo height $graph] }

    if {[info exists use_blt_graph] && $use_blt_graph} {
        blt_curve_setup $w
    } else {
        foreach it [$graph find all] { $graph delete $it }
        curve_setup $w $width $height
    }
    for {set i 0} {$i < $curve_num($w)} {incr i} {
	if ![info exists curve_deleted($w,$i)] {
	    if {[info exists use_blt_graph] && $use_blt_graph} {
	        blt_curve_add $w $i $width $height
	    } else {
	        curve_add $w $i $width $height
	    }
	}
    }
    if {$curve_rescale_cmd($w) != ""} {
	eval $curve_rescale_cmd($w) $curve_lim($w,minx) $curve_lim($w,miny) \
	    $curve_lim($w,maxx) $curve_lim($w,maxy)
    }
    catch { unset curve_selected }
}

proc curve_setup {w width height} {
    global curve_data curve_length curve_xlabel curve_ylabel curve_smooth
    global curve_num curve_xlog curve_ylog curve_xgrid curve_ygrid curve_lim
    global curve_symbol curve_lines curve_title curve_modify
    global curve_startx curve_xoff curve_xfactor curve_xint
    global curve_starty curve_yoff curve_yfactor curve_yint
    global curve_background normalfont curve_fullviewer
    global curve_botlabel_tag curve_toplabel_tag curve_minmaxval
    global curve_xaxis_labels curve_no_scale_at_end

    set nosc [info exists curve_no_scale_at_end]

    set three_xl [expr {$width <= 400}]
    set three_yl [expr {$height <= 300}]

    set can $w.c

    if {$curve_background($w) == "black"} {
	set white white
    } else {
	set white black
    }

    # These might be non-numbers so be paranoid
    set miny 0.1; set maxy 1; set minx 0.1; set maxx 1
    foreach i {minx maxx miny maxy minposx minposy} {
	if {[scan $curve_lim($w,$i) %f $i] < 1} { set $i 0 }
    }
    if [info exists curve_minmaxval($w,minx)] {
	if {($curve_minmaxval($w,minx) != "") &&
	    $curve_minmaxval($w,minx_on) &&
	    ($curve_minmaxval($w,minx) > $minx)} {
	    set minx $curve_minmaxval($w,minx)
	}
	if {($curve_minmaxval($w,miny) != "") &&
	    $curve_minmaxval($w,miny_on) &&
	    ($curve_minmaxval($w,miny) > $miny)} {
	    set miny $curve_minmaxval($w,miny)
	}
	if {($curve_minmaxval($w,maxx) != "") &&
	    $curve_minmaxval($w,maxx_on) &&
	    ($curve_minmaxval($w,maxx) < $maxx)} {
	    set maxx $curve_minmaxval($w,maxx)
	}
	if {($curve_minmaxval($w,maxy) != "") &&
	    $curve_minmaxval($w,maxy_on) &&
	    ($curve_minmaxval($w,maxy) < $maxy)} {
	    set maxy $curve_minmaxval($w,maxy)
	}
    }

    set xmargin 50
    if {$curve_xlabel($w) == ""} {
	set ymargin 50
    } else {
	set ymargin 70
    }
    set xupmargin 20
    set yupmargin 35

    #set width [winfo width $can]
    #set height [winfo height $can]

    if $curve_xlog($w) {
	if {$minx <= 0} {set minx $minposx}
	if {$minx == ""} { set minx 0.1; set maxx 1 }
	set xstuff [curve_compute_log_ticks $minx $maxx 8 $nosc]
    } else {
	set num 8
	if {$curve_xaxis_labels($w) != ""} { set num $maxx }
	#puts "curve_compute_linear_ticks $minx $maxx $num $curve_xint($w) $nosc"
	set xstuff [curve_compute_linear_ticks $minx $maxx $num $curve_xint($w) $nosc]
    }
    set minx [lindex $xstuff 0]; set maxx [lindex $xstuff 1]
    set xmagnitude [lindex $xstuff 2]; set xlabels [lindex $xstuff 3]
    set xx [lindex $xstuff 4]

    if {$curve_xaxis_labels($w) != ""} { set xlabels $curve_xaxis_labels($w) }

    #puts "xstuff $xstuff"

    if $curve_ylog($w) {
	if {$miny <= 0} {set miny $minposy}
	set ystuff [curve_compute_log_ticks $miny $maxy 6 $nosc]
    } else {
	set ystuff [curve_compute_linear_ticks $miny $maxy 6 0 $nosc]
    }
    #puts "ystuff $ystuff"
    set miny [lindex $ystuff 0]; set maxy [lindex $ystuff 1]
    set ymagnitude [lindex $ystuff 2]; set ylabels [lindex $ystuff 3]
    set yy [lindex $ystuff 4]

    set curve_startx($w) $xmargin
    set curve_starty($w) [expr {$height - $ymargin}]
    if $curve_xlog($w) {
	set curve_xoff($w) [expr {-log10($minx)}]
	set xr [expr {log10($maxx) - log10($minx)}]
	if {$xr == 0} { set xr 1 }
	set curve_xfactor($w) [expr {($width - $xmargin - $xupmargin) / \
		($xr + 0.0)}]
    } else {
	set curve_xoff($w) [expr {-$minx}]
	set xr [expr {$maxx - $minx}]
	if {$xr == 0} { set xr 1 }
	set curve_xfactor($w) [expr {($width - $xmargin - $xupmargin) / \
		($xr + 0.0)}]
    }
    if $curve_ylog($w) {
	set curve_yoff($w) [expr {-log10($miny)}]
	set yr [expr {log10($maxy) - log10($miny)}]
	if {$yr == 0} { set yr 1 }
	set curve_yfactor($w) [expr {($height - $ymargin - $yupmargin) / \
		($yr + 0.0)}]
    } else {
	set curve_yoff($w) [expr {-$miny}]
	set yr [format %g [expr {$maxy - $miny}]]
	if {$yr == 0} { set yr 1 }
	set curve_yfactor($w) [expr {($height - $ymargin - $yupmargin) / \
		($yr + 0.0)}]
    }

    # -----------------------

    set ticks [curve_compute_points_list $xx {} \
	       $curve_startx($w) $curve_xoff($w) \
		   $curve_xfactor($w) $curve_xlog($w) \
	       $curve_starty($w) $curve_yoff($w) \
		   $curve_yfactor($w) $curve_ylog($w)]

    set xitems ""
    set i 0
    set nticks [llength $ticks]
    foreach xp $ticks {
	if $curve_xgrid($w) {
	    set l [$can create line $xp [expr {$curve_starty($w) + 4}] $xp $yupmargin \
		   -fill DimGray]
	    $can addtag grid withtag $l
	}
	set vv [lindex $xlabels $i]
	if {$three_xl && ($i > 0) && ($i < $nticks - 1) &&
	    ($i != $nticks / 2)} {
	    set vv ""
	}

	if {$vv != ""} {
	    set l [$can create line $xp [expr {$curve_starty($w) + 4}] \
		       $xp $curve_starty($w) -fill white -width 3]
	    $can addtag grid withtag $l

	    set t [$can create text $xp [expr {$curve_starty($w) + 5}] \
		   -text $vv -fill $white -anchor n -font $normalfont]
	    $can addtag labels withtag $t
	    lappend xitems $t
	}
	incr i
    }
    if $nosc {
	$can itemconfigure [lindex $xitems 0] -anchor nw
	$can itemconfigure [lindex $xitems end] -anchor ne
    }

    if {!$curve_xint($w) && ($xmagnitude != "") && !$nosc} {
	set t [$can create text [expr {$width - 3}] [expr {$height - 3}] \
	       -text 1e$xmagnitude -anchor se -fill $white -font $normalfont]
	$can addtag labels withtag $t
    }

    # -----------------------

    set yvs ""
    foreach y $ylabels {
	if {!$nosc && ($ymagnitude != "")} {
	    lappend yvs [expr $y * pow(10.0,$ymagnitude)]
	} elseif {$y != ""} {
	    lappend yvs $y
	} else {
	    lappend yvs 1
	}
    }

    set ticks [curve_compute_points_list {} $yvs \
		   $curve_startx($w) $curve_xoff($w) \
		   $curve_xfactor($w) $curve_xlog($w) \
		   $curve_starty($w) $curve_yoff($w) \
		   $curve_yfactor($w) $curve_ylog($w)]

    set i 0
    set nticks [llength $ticks]
    foreach yp $ticks {
	if $curve_ygrid($w) {
	    set l [$can create line [expr {$curve_startx($w) - 4}] $yp \
		   [expr {$width - $xupmargin}] $yp -fill DimGray]
	    $can addtag grid withtag $l
	}
	set vv [lindex $ylabels $i]
	if {$three_yl && ($i > 0) && ($i < $nticks - 1) &&
	    ($i != $nticks / 2)} {
	    set vv ""
	}
	if {$vv != ""} {
	    if $curve_yint($w) {
		if {$ymagnitude != ""} {
		    set vv [expr {int($vv * pow(10.0,$ymagnitude))}]
		} else {
		    set vv [expr {int($vv)}]
		}
	    }
	    if $nosc {
		set x 4
		set a w
	    } else {
		set x [expr {$curve_startx($w) - 5}]
		set a e
	    }
	    set l [$can create line [expr {$curve_startx($w) - 4}] $yp \
		   $curve_startx($w) $yp -fill white -width 3]
	    $can addtag grid withtag $l

	    set t [$can create text $x $yp \
		   -text $vv -fill $white -anchor $a -font $normalfont]
	    $can addtag labels withtag $t
	}
	incr i
    }
    if {($ymagnitude != "") && !$nosc} {
	set t [$can create text 3 3 -text 1e$ymagnitude -anchor nw \
		-fill $white -font $normalfont]
	$can addtag labels withtag $t
    }

    # -----------------------

    set l [$can create line $curve_startx($w) $curve_starty($w) [expr {$width - $xupmargin}] \
	   $curve_starty($w) -fill $white]
    $can addtag lines withtag $l
    set l [$can create line $curve_startx($w) $curve_starty($w) $curve_startx($w) $yupmargin \
	   -fill $white]
    $can addtag lines withtag $l
    set t [$can create text [expr {$width - 5}] 5 -text $curve_title($w) \
	   -fill $white -anchor ne -font $normalfont]
    set curve_toplabel_tag($w) $t
    set bb [$can bbox $t]; set yy [lindex $bb 3]
    $can addtag labels withtag $t
    set l [$can create line [lindex $bb 0] $yy [lindex $bb 2] $yy -fill $white]
    $can addtag labels withtag $l

    if $curve_fullviewer($w) {
	if $curve_modify($w) {
	    set text "Left button = zoom, Middle = move/create point, Right = delete"
	} else {
	    set text "Left button = zoom"
	}
        set t [$can create text 5 [expr {$height - 2}] -text $text \
		   -fill $white -anchor sw -font $normalfont]
	set curve_botlabel_tag($w) $t
	$can addtag labels withtag $t
    }

    if {$curve_xlabel($w) != ""} {
	set t [$can create text 50 [expr {$height - 22}] -text $curve_xlabel($w) \
		   -fill $white -anchor sw -font $normalfont]
	set curve_botlabel_tag($w) $t
	$can addtag labels withtag $t
    }

    set r [$can create rectangle 0 0 [expr {$curve_startx($w) - 4}] $height \
	   -fill $curve_background($w) -outline $curve_background($w)]
    $can addtag mask withtag $r
    set r [$can create rectangle 0 0 $width [expr $yupmargin - 2] \
	   -fill $curve_background($w) -outline $curve_background($w)]
    $can addtag mask withtag $r
    set r [$can create rectangle 0 [expr {$curve_starty($w) + 4}] $width $height \
	   -fill $curve_background($w) -outline $curve_background($w)]
    $can addtag mask withtag $r
    set r [$can create rectangle [expr {$width - $xupmargin + 2}] 0 $width $height \
	   -fill $curve_background($w) -outline $curve_background($w)]
    $can addtag mask withtag $r

    $can lower mask labels
    $can lower lines mask
    $can lower grid lines

    # This is necessary because binding things to the canvas does the wrong thing.
    set back [$can create rectangle 0 0 $width $height -fill $curve_background($w) \
	      -outline $curve_background($w)]
    $can lower $back

    if $curve_fullviewer($w) {
	bind $can <ButtonPress-1> "curve_zoom_begin $w %x %y"
	bind $can <Button1-Motion> "curve_zoom_drag $w %x %y"
	bind $can <ButtonRelease-1> "curve_zoom_end $w %x %y"

	bind $can <ButtonPress-2> "set curve_selected \{\}"
	bind $can <ButtonPress-3> "set curve_selected \{\}"
    }

    if $curve_modify($w) {
	curve_edit_bindings $w $back canvas 0
    }
}

proc curve_define_colors {} {
    global curve_colors curve_patterns curve_stipple_to_pspat curve_ncolors

    set curve_colors {
	red green blue yellow lavender cyan magenta orange pink violet
    }
    set curve_patterns {
	{0xff 0xff} {0xff 0x00} {0xc0 0xff} {0x33 0x33} {0xf0 0xf0}
	{0xff 0xff} {0xff 0x00} {0xc0 0xff} {0x33 0x33} {0xf0 0xf0}
    }

    # This is really annoying.
    set curve_stipple_to_pspat(ffff) ""
    set curve_stipple_to_pspat(ff00) "8 8"
    set curve_stipple_to_pspat(c0ff) "4 2 8 2"
    set curve_stipple_to_pspat(03ff) "4 2 8 2"
    set curve_stipple_to_pspat(3333) "2 2"
    set curve_stipple_to_pspat(cccc) "2 2"
    set curve_stipple_to_pspat(0f0f) "4 4"
    set curve_stipple_to_pspat(f0f0) "4 4"

    set curve_ncolors [llength $curve_colors]
}

proc curve_add {w num width height} {
    global curve_colors curve_ncolors curve_symbols curve_lines curve_linecolor
    global curve_length curve_ylabel curve_modify curve_cid curve_lid
    global curve_pixels normalfont curve_tid curve_title curve_deleted

    if ![info exists curve_ncolors] { curve_define_colors }

    set can $w.c

    set color [lindex $curve_colors [expr {$num % $curve_ncolors}]]
    set curve_linecolor($w,$num) $color

    if $curve_lines($w) {
	set l [eval $can create line 0 0 0 0 -fill $color \
		-width $curve_pixels($w,linew)]
	$can lower $l mask
	if $curve_modify($w) {
	    curve_edit_bindings $w $l line $num
	}
	set curve_lid($w,$num) $l
	$can bind $l <ButtonPress-1> "curve_pick_item $num"
    }
    if $curve_symbols($w) {
	for {set i 0} {$i < $curve_length($w,$num)} {incr i} {
	    curve_add_circle $w $num $i
	}
    }
    set t [$can create text [expr {$width - 5}] 5 -text $curve_ylabel($w,$num) \
	   -fill $color -anchor ne -font $normalfont]
    set curve_tid($w,$num) $t
    $can raise $t labels
    $can bind $t <ButtonPress-1> "curve_pick_item $num"

    set num_not_deleted 0
    for {set i 0} {$i < $num} {incr i} {
	if ![info exists curve_deleted($w,$i)] {
	    incr num_not_deleted
	}
    }
    set bb [$can bbox $t]
    set ttt [expr [string length $curve_title($w)] ? 1 : 0]
    set ny [expr {([lindex $bb 3] - [lindex $bb 1] + 1) * ($num_not_deleted + $ttt) + 10}]
    $can coords $t [expr {$width - 5}] $ny

    catch {unset curve_deleted($w,$num)}
    curve_update $w $num
}

proc curve_add_circle {w num pt} {
    global curve_linecolor curve_modify curve_cid curve_pixels curve_symtype
    global curve_background

    if {$curve_background($w) == "black"} {
	set white white
    } else {
	set white black
    }

    case $curve_symtype($w) in {
	o {
	    set sym [$w.c create oval 0 0 0 0 -outline $curve_linecolor($w,$num) \
		   -fill $white -width $curve_pixels($w,circw)]
	}
	x {
	    set s1 [$w.c create line 0 0 0 0 -fill $curve_linecolor($w,$num)]
	    set s2 [$w.c create line 0 0 0 0 -fill $curve_linecolor($w,$num)]

	    set sym "$s1 $s2"
	}
    }
    foreach s $sym { $w.c lower $s mask }
    if $curve_modify($w) {
	foreach s $sym {
	    curve_edit_bindings $w $s circle $num
	}
    }
    set curve_cid($w,$num,$pt) $sym
}

proc curve_update {w num} {
    global curve_startx curve_starty curve_xoff curve_yoff curve_xfactor
    global curve_yfactor
    global curve_xlog curve_ylog curve_symbols curve_lines curve_symtype
    global curve_length curve_coords curve_cid curve_lid curve_pixels

    if ![info exists curve_lid($w,$num)] return

    set pts [curve_compute_points_var $w curve_data $num $curve_length($w,$num) \
	         $curve_startx($w) $curve_xoff($w) $curve_xfactor($w) $curve_xlog($w) \
		 $curve_starty($w) $curve_yoff($w) $curve_yfactor($w) $curve_ylog($w)]
    set curve_coords($w,$num) $pts

    if $curve_symbols($w) {
	for {set i 0} {$i < $curve_length($w,$num)} {incr i} {
	    case $curve_symtype($w) in {
		o {
		    set size $curve_pixels($w,circr)
		    set x [lindex $pts [expr {$i * 2}]]
		    set y [lindex $pts [expr {$i * 2 + 1}]]
		    if {($x == "") || ($y == "")} continue
		    set x1 [expr {$x - $size}]; set x2 [expr {$x + $size}]
		    set y1 [expr {$y - $size}]; set y2 [expr {$y + $size}]
		    $w.c coords $curve_cid($w,$num,$i) $x1 $y1 $x2 $y2
		}
		x {
		    set size $curve_pixels($w,symx)
		    set x [lindex $pts [expr {$i * 2}]]
		    set y [lindex $pts [expr {$i * 2 + 1}]]
		    if {($x == "") || ($y == "")} continue
		    set x1 [expr {$x - $size}]; set x2 [expr {$x + $size}]
		    set y1 [expr {$y - $size}]; set y2 [expr {$y + $size}]
		    $w.c coords [lindex $curve_cid($w,$num,$i) 0] $x1 $y1 $x2 $y2
		    $w.c coords [lindex $curve_cid($w,$num,$i) 1] $x1 $y2 $x2 $y1
		}
	    }
	}
    }
    if $curve_lines($w) {
	set npts {}; foreach p $pts { if {$p != ""} { lappend npts $p } }
	if {[llength $npts] >= 4} {
	    eval $w.c coords $curve_lid($w,$num) $npts
	}
    }
}

# ------------------------------------------------------------

proc curve_event {w which op but num x y} {
    global curve_data curve_coords curve_selected_num curve_selected_ind
    global curve_length curve_cid curve_zoom_box

    if [info exists curve_zoom_box($w)] {
	$w.c delete $curve_zoom_box($w)
	unset curve_zoom_box($w)
    }

    case "$which $but $op" in {
	{{circle 2 press}} {
	    set pt [curve_closest $w $num $x $y]
	    set curve_selected_num($w) $num
	    set curve_selected_ind($w) $pt
	}
	{{line 2 press} {canvas 2 press}} {
	    set pt [curve_after $w $num $x]
	    set curve_selected_num($w) $num
	    set curve_selected_ind($w) $pt
	    # Put a new point here.

	    for {set i $curve_length($w,$num)} {$i > $pt} {incr i -1} {
		set curve_cid($w,$num,$i) $curve_cid($w,$num,[expr {$i - 1}])
		set curve_data($w,$num,$i) $curve_data($w,$num,[expr {$i - 1}])
	    }

	    curve_add_circle $w $num $pt
	    incr curve_length($w,$num)

	    curve_move $w $num $pt $x $y
	}
	{{circle 2 move} {line 2 move} {canvas 2 move}} {
	    curve_move $w $curve_selected_num($w) $curve_selected_ind($w) $x $y
	}
	{{circle 2 release} {line 2 release} {canvas 2 release}} {
	    catch {unset curve_selected_num($w)}
	    catch {unset curve_selected_ind($w)}
	}
	{{circle 3 press}} {
	    set pt [curve_closest $w $num $x $y]

	    if {$curve_length($w,$num) < 3} { bell; return }

	    foreach sym $curve_cid($w,$num,$pt) { $w.c delete $sym }
	    for {set i $pt} {$i < $curve_length($w,$num) - 1} {incr i} {
		set curve_cid($w,$num,$i) $curve_cid($w,$num,[expr {$i + 1}])
		set curve_data($w,$num,$i) $curve_data($w,$num,[expr {$i + 1}])
	    }
	    unset curve_cid($w,$num,$i)
	    unset curve_data($w,$num,$i)
	    incr curve_length($w,$num) -1
	}
    }
    curve_update $w $num
}

proc curve_move {w num pt x y} {
    global curve_data curve_xlog curve_ylog curve_length
    global curve_startx curve_starty curve_xoff curve_yoff curve_xfactor curve_yfactor

    set xc [expr {($x - $curve_startx($w)) / ($curve_xfactor($w) + 0.0) - $curve_xoff($w)}]
    if $curve_xlog($w) { set xc [expr {pow(10.0, $xc)}] }
    set yc [expr {- ($y - $curve_starty($w)) / ($curve_yfactor($w) + 0.0) - $curve_yoff($w)}]
    if $curve_ylog($w) { set yc [expr {pow(10.0, $yc)}] }
    set curve_data($w,$num,$pt) "$xc $yc"

    # Now make sure the function is still monotonic.
    for {set i [expr {$pt + 1}]} {$i < $curve_length($w,$num)} {incr i} {
	set x [lindex $curve_data($w,$num,$i) 0]
	set y [lindex $curve_data($w,$num,$i) 1]
	set ox [lindex $curve_data($w,$num,[expr {$i - 1}]) 0]
	if {$x < $ox} {
	    set curve_data($w,$num,$i) "$ox $y"
	} else {
	    break
	}
    }
    for {set i [expr {$pt - 1}]} {$i > 0} {incr i -1} {
	set x [lindex $curve_data($w,$num,$i) 0]
	set y [lindex $curve_data($w,$num,$i) 1]
	set ox [lindex $curve_data($w,$num,[expr {$i + 1}]) 0]
	if {$x > $ox} {
	    set curve_data($w,$num,$i) "$ox $y"
	} else {
	    break
	}
    }
}

proc curve_closest {w num x y} {
    global curve_coords

    set clp ""
    set px ""
    set n 0
    foreach v $curve_coords($w,$num) {
	if {$px == ""} {
	    set px $v
	} else {
	    if {$v != ""} {
		set dx [expr {$px - $x}]; set dy [expr {$v - $y}]
		set d [expr {sqrt($dx * $dx + $dy * $dy)}]
		if {($clp == "") || ($d < $cld)} {
		    set clp $n; set cld $d
		}
	    }
	    set px ""
	    incr n
	}
    }
    return $clp
}

proc curve_after {w num x} {
    global curve_coords

    set isx 1
    set ind 0
    foreach v $curve_coords($w,$num) {
	if $isx {
	    if {($v != "") && ($v > $x)} { return $ind }
	    incr ind
	    set isx 0
	} else {
	    set isx 1
	}
    }
    return $ind
}

# ------------------------------------------------------------

# This returns a list with the following.  A new min, a new max, the
# order of magnitude of the tick labels (like -3), a list of the labels
# to use, and a list of the values associated with them.

proc curve_compute_linear_ticks {min max num int nosc} {
    #mess " Ticks : max= $max, min= $min, num= $num, int= $int\n" red
    if {$max < $min} {set m $min; set min $max; set max $m}
    #mess " Ticks : max= $max, min= $min, num= $num, int= $int\n" green
    if {$min != 0} {
	set exp1 [expr {int(log10(abs($min)))}]
    } else {
	set exp1 -1000
    }
    if {$max != 0} {
	set exp2 [expr {int(log10(abs($max)))}]
    } else {
	set exp2 -1000
    }
    set exp [expr {($exp1 > $exp2) ? $exp1 : $exp2}]
    if {$max == $min} {
	if {$exp == -1000} {set exp 0}
	set max [format %g [expr {$max + pow(10,$exp-1)}]]
	set min [format %g [expr {$min + pow(10,$exp-1)}]]
    }
    set tfact [format %g [expr pow(10.0,$exp)]]
    set incr 1
    set mant1 [expr {int($min / $tfact)}]
    set mant2 [expr {int($max / $tfact)}]
    if {$mant1 * $tfact > $min} {set mant1 [expr {$mant1 - $incr}]}
    if {$mant2 * $tfact < $max} {set mant2 [expr {$mant2 + $incr}]}
    set diff [expr {$mant2 - $mant1}]
    if {$diff < $num} {
	set incr 0.1
	set mant1 [expr {int(10 * $min / $tfact) / 10.0}]
	set mant2 [expr {int(10 * $max / $tfact) / 10.0}]
	if {$mant1 * $tfact > $min} {set mant1 [expr {$mant1 - $incr}]}
	if {$mant2 * $tfact < $max} {set mant2 [expr {$mant2 + $incr}]}
    }
    # puts "exp $exp mant1 $mant1 mant2 $mant2"

    while {($mant2 - $mant1) / $incr >= 2 * $num} {set incr [expr {2 * $incr}]}
    set labels {}
    set points {}
    #puts "mant1 $mant1 mant2 $mant2 incr $incr tfact $tfact"
    set last_ll ""
    for {set m $mant1} {$m <= $mant2} {set m [expr {$m + $incr}]} {
	#puts "m $m tfact $tfact"
	set vv [expr {$m * $tfact}]
	if $int {
	    # Small roundoff is possible here
	    set ll [format %d [expr {int($vv * 1.0000001)}]]
	} elseif $nosc {
	    set ll [format %g $vv]
	} else {
	    set ll [format %.3g $m]
	}
	if {$last_ll != $ll} {
	    lappend labels $ll
	    if $int {
		lappend points [format %g [expr {int($vv * 1.0000001)}]]
	    } else {
		lappend points [format %g $vv]
	    }
	    set last_ll $ll
	}
    }
    return [list [format %g [expr {$mant1 * $tfact}]] \
	    [format %g [expr {$mant2 * $tfact}]] $exp $labels $points]
    }

proc curve_compute_log_ticks {min max num nosc} {
    global tcl_version
    #puts "<<< $min $max $num"
    if {$max < $min} {set m $min; set min $max; set max $m}
    if {$max <= 0} {set min 1; set max 10}
    if {$min <= 0} {
	set maxexp [expr {int(log10($max))}]
	set min [expr {pow(10.0,$maxexp - 2)}]
    }
    if [expr $tcl_version < 8.4] {
        set exp1 [expr {int(floor(log10($min)))}]
        set exp2 [expr {int(floor(log10($max))) + 1}]
    } else {
        set exp1 [floor [expr log10($min)]]
        set exp2 [expr [floor [expr log10($max)]] + 1]
    }
    set maxmant [format %g [expr {pow(10,$exp2)}]]
    #puts "... exp1 $exp1 exp2 $exp2 maxmant $maxmant"

    if {$maxmant * 1.01 < $max} { incr exp2 }

    set ediff [expr {$exp2 - $exp1}]
    for {set eincr 1} {$ediff / $eincr > 10} {incr eincr} {}
    set numords [expr {$ediff / $eincr}]

    set labels {}
    set points {}
    for {set ord $exp1} {$ord < $exp2} {incr ord $eincr} {
	lappend labels "1e$ord"
	lappend points [expr {pow(10.0,$ord)}]
	if {$numords < 6} {
	    for {set i 2} {$i < 10} {incr i} {
		lappend labels ""
		lappend points [expr {$i * pow(10.0,$ord)}]
	    }
	}
    }
    lappend labels "1e$ord"
    lappend points [format %g [expr {pow(10.0,$ord)}]]

    set min [format %g [expr {pow(10,$exp1)}]]
    set max [format %g [expr {pow(10,$ord)}]]
    #puts ">>> $min $max $labels $points"
    #puts "np [llength $points]"
    return [list $min $max "" $labels $points]
}

# -----------------------------------------------------------

proc curve_pick_item {num} {
    global curve_selected

    if [info exists curve_selected] { set curve_selected $num }
}

proc curve_zoom_begin {w x y} {
    global curve_zoom_x curve_zoom_y curve_zoom_box curve_selected

    if [info exists curve_selected] return ;# the curve things have bindings

    set curve_zoom_x($w) $x
    set curve_zoom_y($w) $y
    set curve_zoom_box($w) [$w.c create rectangle $x $y $x $y -outline pink]
}

proc curve_zoom_drag {w x y} {
    global curve_zoom_x curve_zoom_y curve_zoom_box curve_selected

    if [info exists curve_selected] return ;# the curve things have bindings

    if [info exists curve_zoom_box($w)] {
	$w.c coords $curve_zoom_box($w) $curve_zoom_x($w) $curve_zoom_y($w) $x $y
    }
}

proc curve_zoom_end {w x y} {
    global curve_zoom_x curve_zoom_y curve_zoom_box curve_lim
    global curve_startx curve_starty curve_xoff curve_yoff curve_xfactor
    global curve_yfactor curve_xlog curve_ylog curve_selected

    if [info exists curve_selected] return ;# the curve things have bindings

    if [info exists curve_zoom_box($w)] {
	$w.c delete $curve_zoom_box($w)
	unset curve_zoom_box($w)
	set xx $curve_zoom_x($w)
	set yy $curve_zoom_y($w)
	if {($x == $xx) || ($y == $yy)} return

	set x1 [expr {($xx - $curve_startx($w)) / $curve_xfactor($w) - $curve_xoff($w)}]
	set y1 [expr {- ($yy - $curve_starty($w)) / $curve_yfactor($w) - $curve_yoff($w)}]
	set x2 [expr {($x - $curve_startx($w)) / $curve_xfactor($w) - $curve_xoff($w)}]
	set y2 [expr {- ($y - $curve_starty($w)) / $curve_yfactor($w) - $curve_yoff($w)}]

	if {$x1 > $x2} { set x $x1; set x1 $x2; set x2 $x }
	if {$y1 > $y2} { set y $y1; set y1 $y2; set y2 $y }

	if $curve_xlog($w) {
	    set x1 [expr {pow(10.0,$x1)}]
	    set x2 [expr {pow(10.0,$x2)}]
	}
	if $curve_ylog($w) {
	    set y1 [expr {pow(10.0,$y1)}]
	    set y2 [expr {pow(10.0,$y2)}]
	}

	set curve_lim($w,minx) $x1; set curve_lim($w,maxx) $x2
	set curve_lim($w,miny) $y1; set curve_lim($w,maxy) $y2
	curve_perform $w
    }
}

proc curve_edit_bindings {w it what num} {
    $w.c bind $it <ButtonPress-2> "curve_event $w $what press 2 $num %x %y"
    $w.c bind $it <ButtonRelease-2> "curve_event $w $what release 2 $num %x %y"
    $w.c bind $it <Button2-Motion> "curve_event $w $what move 2 $num %x %y"

    $w.c bind $it <ButtonPress-3> "curve_event $w $what press 3 $num %x %y"
    $w.c bind $it <ButtonRelease-3> "curve_event $w $what release 3 $num %x %y"
    $w.c bind $it <Button3-Motion> "curve_event $w $what move 3 $num %x %y"

    foreach {n1 n2} {1 3 3 1} {
	$w.c bind $it <Button$n1-ButtonPress-$n2> \
	    "curve_event $w $what press 2 $num %x %y"
	$w.c bind $it <Button$n1-ButtonRelease-$n2> \
	    "curve_event $w $what release 2 $num %x %y"
	$w.c bind $it <Button$n1-Button$n2-Motion> \
	    "curve_event $w $what move 2 $num %x %y"
    }
}

proc curve_hardcopy {w} {
    file_hardcopy .curve_tdv .curve_tdv.view "curve_start_hardcopy $w" \
	curve_end_hardcopy
}

proc curve_start_hardcopy {w} {
    global graphics_type

    catch {top_destroy .curve_tdv}
    top_window .curve_tdv
    set cc .curve_tdv.view
    tdv_init $cc [$w.c cget -width] [$w.c cget -height] $graphics_type black 0
    pack $cc -side top -fill both -expand 1
    set tdv_origin_var($cc) 0; tdv_toggle_origin $cc
    set tdv_axes_var($cc) 0; tdv_toggle_axes $cc
    set pc [tdv_plotcanvas_im -canvas $w.c -transform 0]
    $cc add_image $pc
    top_geometry .curve_tdv +[winfo x $w]+[winfo y $w]
    update
    return $cc
}

proc curve_end_hardcopy {} {
    catch {top_destroy .curve_tdv}
}

# -----------------------------------------------------------------------------
# blt::graph functions
#

proc blt_curve_hardcopy {w} {
#    set graph $w.main.graph
#    file_hardcopy "" "$w" "" "blt_curve_start_hardcopy $w" \
#                  "" "" $graph
# can't get this to work - Bruce
#    file_hardcopy "$w" "" "blt_curve_start_hardcopy $w" ""
    mess "Blt graph printing not implemented\n" red
    return
}

proc blt_curve_start_hardcopy {w} {
    set graph $w.main.graph
    return $graph
}

proc blt_curve_full {g w} {
    global curve_minmaxval

    $g axis configure x -min {} -max {}
    $g axis configure y -min {} -max {}
    foreach item {min max} {
      set curve_minmaxval($w,${item}x_on) 0
      set curve_minmaxval($w,${item}y_on) 0
    }
    curve_perform $w
}

proc blt_curve_full {g w} {
    global curve_minmaxval

    $g axis configure x -min {} -max {}
    $g axis configure y -min {} -max {}
    foreach item {min max} {
      set curve_minmaxval($w,${item}x_on) 0
      set curve_minmaxval($w,${item}y_on) 0
    }
    curve_perform $w
}

proc blt_curve_zoom_start {g x y} {
    global curve_graph

    if {[$g legend get @$x,$y] != ""} return

    if !$curve_graph(zoom) {
        $g marker create text -coords {-Inf -Inf} -outline red -name message \
            -text "Select 2nd corner with left button" \
            -anchor sw -fill "" -xoffset 5 -yoffset -5
        set curve_graph(zoom) 1
        set curve_graph(x) $x
        set curve_graph(y) $y
        set curve_graph(xp) [$g axis invtransform x $x]
        set curve_graph(yp) [$g axis invtransform y $y]
        if {[$g cget -plotbackground] == "black"} {
	    set white white
        } else {
            set white black
        }
        $g marker create line -name box -fill "" -outline $white -linewidth 2
    }
}

proc blt_curve_zoom_end {g x y} {
    global curve_graph

    if {[$g legend get @$x,$y] != ""} return

    if {$curve_graph(zoom)} {
        $g marker delete message
        catch {$g marker delete box}
        set curve_graph(zoom) 0
    }
    if [info exists curve_graph(zoom,print,start)] {
        set xmin $curve_graph(x)
        set xmax $x
        set ymin $curve_graph(y)
        set ymax $y
        set curve_graph(zoom,print,end) [list $xmin $ymin $xmax $ymax]
        unset curve_graph(zoom,print,start)
        return
    }
    if {$x != $curve_graph(x)} {
        set xp [$g axis invtransform x $x]
        if {$xp < $curve_graph(xp)} {
            $g axis configure x -min $xp -max $curve_graph(xp)
        } else {
            $g axis configure x -min $curve_graph(xp) -max $xp
        }
    }
    if {$y != $curve_graph(y)} {
        set yp [$g axis invtransform y $y]
        if {$yp < $curve_graph(yp)} {
            $g axis configure y -min $yp -max $curve_graph(yp)
        } else {
            $g axis configure y -min $curve_graph(yp) -max $yp
        }
    }
}

proc blt_curve_zoom_motion {g x y} {
    global curve_graph

    if {$curve_graph(zoom) == 1} {
        set xp [$g axis invtransform x $x]; set yp [$g axis invtransform y $y]
        $g marker configure box -coords [list $curve_graph(xp) $curve_graph(yp) \
            $xp $curve_graph(yp) $xp $yp $curve_graph(xp) $yp $curve_graph(xp) \
            $curve_graph(yp)]
    }
}

proc blt_curve_add {w num width height} {
    global curve_colors curve_ncolors curve_symbols curve_lines curve_linecolor
    global curve_length curve_ylabel curve_modify curve_cid curve_lid
    global curve_pixels normalfont curve_tid curve_title curve_deleted curve_hidden

    if ![info exists curve_ncolors] { curve_define_colors }

    set graph $w.main.graph
    if ![winfo exists $graph] { set graph $w.graph }
    set color [lindex $curve_colors [expr {$num % $curve_ncolors}]]
    set curve_linecolor($w,$num) $color
    $graph element bind $num <ButtonPress-1> "curve_pick_item $num"
    set curve_lid($w,$num) $num
    $graph legend bind $num <ButtonPress-1> "blt_toggle_item $w $num"
    set curve_tid($w,$num) $num

    set num_not_deleted 0
    for {set i 0} {$i < $num} {incr i} {
	if ![info exists curve_deleted($w,$i)] {
	    incr num_not_deleted
	}
    }
    catch { unset curve_deleted($w,$num) }
    catch { unset curve_hidden($w,$num) }
    blt_curve_update $w $num
}

proc blt_toggle_item {w num} {
    global curve_hidden

    if [info exists curve_hidden($w,$num)] {
	unset curve_hidden($w,$num)
    } else {
	set curve_hidden($w,$num) 1
    }
    $w.main.graph axis configure x -min {} -max {}
    $w.main.graph axis configure y -min {} -max {}
    blt_curve_update $w $num
}

proc blt_curve_setup {w} {
    global curve_data curve_length curve_xlabel curve_ylabel curve_smooth
    global curve_num curve_xlog curve_ylog curve_xgrid curve_ygrid curve_lim
    global curve_symbol curve_lines curve_title curve_modify
    global curve_startx curve_xoff curve_xfactor curve_xint
    global curve_starty curve_yoff curve_yfactor curve_yint
    global curve_background normalfont curve_fullviewer
    global curve_botlabel_tag curve_toplabel_tag curve_minmaxval
    global curve_xaxis_labels curve_no_scale_at_end curve_selected

    if [winfo exists $w.main.graph] {
	set graph $w.main.graph
    } else {
	set graph $w.graph
    }

    if {$curve_background($w) == "black"} {
	set white white
    } else {
	set white black
    }

    if {$curve_xgrid($w) || $curve_ygrid($w)} {
        $graph grid configure -hide 0
    } else {
        $graph grid configure -hide 1
    }
    if $curve_xgrid($w) {
        $graph grid configure -mapx x
    } else {
        $graph grid configure -mapx ""
    }
    if $curve_ygrid($w) {
        $graph grid configure -mapy y
    } else {
        $graph grid configure -mapy ""
    }

    set nosc [info exists curve_no_scale_at_end]

    set miny 0.1; set maxy 1; set minx 0.1; set maxx 1
    foreach i {minx maxx miny maxy minposx minposy} {
	if {[scan $curve_lim($w,$i) %f $i] < 1} { set $i 0 }
    }
    if [info exists curve_minmaxval($w,minx)] {
	if {($curve_minmaxval($w,minx) != "") &&
	    $curve_minmaxval($w,minx_on) &&
	    ($curve_minmaxval($w,minx) > $minx)} {
	    set minx $curve_minmaxval($w,minx)
	}
	if {($curve_minmaxval($w,miny) != "") &&
	    $curve_minmaxval($w,miny_on) &&
	    ($curve_minmaxval($w,miny) > $miny)} {
	    set miny $curve_minmaxval($w,miny)
	}
	if {($curve_minmaxval($w,maxx) != "") &&
	    $curve_minmaxval($w,maxx_on) &&
	    ($curve_minmaxval($w,maxx) < $maxx)} {
	    set maxx $curve_minmaxval($w,maxx)
	}
	if {($curve_minmaxval($w,maxy) != "") &&
	    $curve_minmaxval($w,maxy_on) &&
	    ($curve_minmaxval($w,maxy) < $maxy)} {
	    set maxy $curve_minmaxval($w,maxy)
	}
    }

    if $curve_xlog($w) {
	if {$minx <= 0} {set minx $minposx}
	if {$minx == ""} { set minx 0.1; set maxx 1 }
	set xstuff [curve_compute_log_ticks $minx $maxx 8 $nosc]
    } else {
	set num 8
	if {$curve_xaxis_labels($w) != ""} { set num $maxx }
	set xstuff [curve_compute_linear_ticks $minx $maxx $num $curve_xint($w) $nosc]
    }
    set minx [lindex $xstuff 0]; set maxx [lindex $xstuff 1]
    set xmagnitude [lindex $xstuff 2]; set xlabels [lindex $xstuff 3]
    set xx [lindex $xstuff 4]

    if $curve_xlog($w) {
	$graph axis configure x -log 1 -min $minx -max $maxx
    } else {
	$graph axis configure x -log 0 -min $minx -max $maxx
    }
    if [info exists curve_minmaxval($w,minx)] {
        set curve_minmaxval($w,minx) $minx
        set curve_minmaxval($w,maxx) $maxx
    }

    if $curve_ylog($w) {
	if {$miny <= 0} {set miny $minposy}
	set ystuff [curve_compute_log_ticks $miny $maxy 6 $nosc]
    } else {
	set ystuff [curve_compute_linear_ticks $miny $maxy 6 0 $nosc]
    }
    set miny [lindex $ystuff 0]; set maxy [lindex $ystuff 1]
    set ymagnitude [lindex $ystuff 2]; set ylabels [lindex $ystuff 3]
    set yy [lindex $ystuff 4]

    if $curve_ylog($w) {
	$graph axis configure y -log 1 -min $miny -max $maxy
    } else {
	$graph axis configure y -log 0 -min $miny -max $maxy
    }
    if [info exists curve_minmaxval($w,miny)] {
        set curve_minmaxval($w,miny) $miny
        set curve_minmaxval($w,maxy) $maxy
    }

    if $curve_fullviewer($w) {
	if $curve_modify($w) {
	    set text "Left button = zoom, Middle = move/create point, Right = delete"
	} else {
	    set text "Left button = zoom"
	}
	 $graph marker create text -coords {-Inf -Inf} -outline red -name message \
            -text "$text" -anchor sw -xoffset 5 -yoffset -5 -fill ""
    }
    if $curve_fullviewer($w) {
        bind $graph <ButtonPress-1> {blt_curve_zoom_start %W %x %y}
        bind $graph <ButtonRelease-1> {blt_curve_zoom_end %W %x %y}
        bind $graph <Motion> {blt_curve_zoom_motion %W %x %y}
	bind $graph <ButtonPress-2> "set curve_selected \{\}"
        bind $graph <ButtonPress-3> "set curve_selected \{\}"
    }
}

proc blt_curve_update {w num} {
    global curve_xlog curve_ylog curve_symbols curve_symtype
    global curve_cid curve_lid curve_pixels curve_lines
    global curve_linecolor curve_data curve_ylabel curve_minmaxval
    global curve_hidden

    if ![info exists curve_lid($w,$num)] return

    set graph $w.main.graph
    if ![winfo exists $graph] { set graph $w.graph }
    set color $curve_linecolor($w,$num)
    set label $curve_ylabel($w,$num)
    set lid $curve_lid($w,$num)

    set npts(x) {}; set npts(y) {}
    foreach item [lsort -dictionary [array names curve_data $w,$num,*]] {
        set pt $curve_data($item)
        set x [lindex $pt 0]; set y [lindex $pt 1]
        if {$x == "" || $y == ""} {
            continue
	} elseif {![scan $x %f xxx]} {
	    error "Expected x value to be float, got \{$pt\}"
	} elseif {![scan $y %f yyy]} {
	    error "Expected y value to be float, got \{$pt\}"
	} elseif {[expr $x < $curve_minmaxval($w,minx)] || \
	          [expr $x > $curve_minmaxval($w,maxx)] || \
	          [expr $y < $curve_minmaxval($w,miny)] || \
	          [expr $y > $curve_minmaxval($w,maxy)]} {
	    continue
	} else {
	    lappend npts(x) $x
	    lappend npts(y) $y
	}
    }

#    if {[llength $npts(x)] < 4 || [llength $npts(y)] < 4} {
#      return
#    }

    if $curve_lines($w) {
        set linewidth 0.01i
    } else {
        set linewidth 0.0i
    }
    if $curve_symbols($w) {
        case $curve_symtype($w) in {
	    o { set symbol circle }
	    x { set symbol cross }
        }
        set pixels 0.03i
    } else {
        set symbol circle
        set pixels 0.0i
    }
    if {!$curve_lines($w) && !$curve_symbols($w)} {
      set hide 1
    } else {
      set hide 0
    }
    if [info exists curve_hidden($w,$num)] {
	set npts(x) ""
	set npts(y) ""
	set color gray
    }
    if ![$graph element exists $lid] {
	$graph element create $lid
    }
    $graph element configure $lid -xdata $npts(x) -ydata $npts(y) -hide $hide \
	-color $color -pixels $pixels -linewidth $linewidth -symbol $symbol \
	-label $label
}

