#!/bin/sh
#The next line executes wish - wherever it is \
exec wish "$0" "$@"

# This program applies the greycstoration program to one or more
# files from a selected directory, with output to a different directory.
# The many greycstoration parameters are set using UI widgets.
#
# For greycstoration see: http://www.greyc.ensicaen.fr/~dtschump/greycstoration/
#
# This TCL script uses only standard TCL/Tk 8.4 facilities and has
# been tested in MacOS X 10.4 and in Ubuntu Linux 6.
#
# This script has been proposed by --> Dave Cortesi <--
#
# Usage:
# (1)  Select the source directory by clicking Source.
#      Navigate to a directory containing input images.
#      Names of all files in that directory are listed
#      in the scrolling listbox.
#
# (2)  Select the destination directory by clicking Dest.
#      Navigate to a different directory.
#
# NOTE TO MAC OS X USERS: PATH NAMES MAY NOT INCLUDE SPACES
# OR OTHER SHELL SPECIAL CHARACTERS (this could be fixed)
#
# (3)  Choose the function to apply: denoise, resize, or inpaint.
#
# (3a) If you choose resize, set the geometry parameters.
# WHICH ARE NOT CURRENTLY IMPLEMENTED!
#
# (3b) If you choose inpaint, click Choose and navigate to
#      select the masking image.
#
# (4)  Set the other greycstoration parameters using the various widgets.
#      Click the button Default to reset these to default values.
#
# (5)  Use click, shift-click, and control-click in the list of
#      source files to select one or more source images.
#
# (6)  Click Interactive or Batch to apply greycstoration to each
#      of the selected images in turn. If you click Interactive,
#      you will view each image before it is saved, and can cause
#      greycstoration to make extra iterations. If you click Batch
#      there is no interaction.
#

# --------- Misc globals and constants
# list of files shown in .lb_files
set list_files [list ]
# command set by radio buttons
set cmd_string "-restore"
# path to mask image set by get_mask
set mask_path ""
# image resolution set by radio buttons
set res_bits "8"
# fast mode set by checkbutton
set fast_mode 0
# interp-type set by radio buttons
set pinterp 0

set font_settings { courier 14 }
if [string equal $tcl_platform(platform) "windows"] {
	set font_settings { courier 10 }
}

# ---------- Make the widgets
# ensure the file list gets the focus if you click in it
tk_focusFollowsMouse

# ---------- Directories and file list
# A button to select a directory and a title to display the result
# (could be a text field and let the user type in the path as
# an alternative, but for now don't want pain of
# parsing a user string & checking errors.)

labelframe .fr_files -text "Source/Dest Selection" -borderwidth 3 -relief sunken

button .bu_source -text "Source" -width 8 \
	-command {get_source_dir} \
	-default normal -state normal \
	-font $font_settings \

label .ti_source -text "" \
	-width 40 \
	-borderwidth 3 -relief sunken \
	-font $font_settings

listbox .lb_files \
	-width 50 -height 20 -font $font_settings \
	-activestyle dotbox \
	-listvariable list_files \
	-selectmode extended \
	-yscroll {.sb_files set}

scrollbar .sb_files -orient vertical -command {.lb_files yview}

button .bu_dest -text "Dest" -width 8 \
	-command {get_dest_dir} \
	-default normal -state normal \
	-font $font_settings \

label .ti_dest -text "" \
	-width 40 \
	-borderwidth 3 -relief sunken \
	-font $font_settings

grid .ti_source		-in .fr_files -row 0 -column 0 -sticky nw -ipadx 2 -ipady 4
grid .bu_source		-in .fr_files -row 0 -column 1 -sticky nw -ipadx 2 -ipady 4
grid .lb_files		-in .fr_files -row 1 -column 0 -columnspan 2 -sticky ew
grid .ti_dest		-in .fr_files -row 2 -column 0 -sticky sw -ipadx 2 -ipady 4
grid .bu_dest		-in .fr_files -row 2 -column 1 -sticky sw -ipadx 2 -ipady 4

grid .fr_files		-in .		-row 0 -column 0 -rowspan 2 -sticky nw

# -------- Activation buttons below file frame

frame .fr_go
button .bu_batch -text "Batch" -command {doit 0} \
	-default normal -state normal \
	-font $font_settings

button .bu_inter -text "Interact" -command {doit 1} \
	-default normal -state normal \
	-font $font_settings

button .bu_default -text "default" -command {defaults} \
	-default normal -state normal \
	-font $font_settings


grid .bu_batch		-in .fr_go	-row 0 -column 0 -sticky w -padx 10
grid .bu_inter		-in .fr_go	-row 0 -column 1 -sticky w -padx 10
grid .bu_default	-in .fr_go  -row 0 -column 3 -sticky e -padx 20

grid .fr_go			-in . -row 2 -column 0

# ---------- command selection buttons

labelframe .fr_cmd -text "Operation" -borderwidth 3 -relief sunken

# ---- frame around restore button

frame .fr_restore

radiobutton .rb_denoise -text "denoise" -font $font_settings \
		-variable cmd_string -value "-restore"

grid .rb_denoise		-in .fr_restore -row 0 -column 0 -sticky nw

grid .fr_restore		-in .fr_cmd -row 0  -sticky nw -ipady 4

# ----- frame around resize button and geometry spinner

frame .fr_resize

radiobutton .rb_resize -text "resize" -font $font_settings \
		-variable cmd_string -value "-resize"

label .ti_gh -text "gh%" -font $font_settings
spinbox .sp_gh -from 100 -to 1600 -width 5 -font $font_settings
label .ti_gv -text "gv%" -font $font_settings
spinbox .sp_gv -from 100 -to 1600 -width 5 -font $font_settings


grid .rb_resize			-in .fr_resize -row 0 -column 0 -columnspan 4 -sticky nw -columnspan 5
grid .ti_gh				-in .fr_resize -row 1 -column 0
grid .sp_gh				-in .fr_resize -row 1 -column 1
grid .ti_gv				-in .fr_resize -row 1 -column 2
grid .sp_gv				-in .fr_resize -row 1 -column 3

grid .fr_resize			-in .fr_cmd -row 1 -column 0 -sticky nw -ipady 4

# ----- frame around inpaint button and mask-file selection

frame .fr_inpaint

radiobutton .rb_inpaint -text "inpaint" -font $font_settings \
		-variable cmd_string -value "-inpaint"

label .ti_mask -text "(mask image)" \
	-width 40 \
	-borderwidth 3 -relief sunken -font $font_settings

button .bu_mask -text "Choose" -command {get_mask} \
	-default normal -state normal \
	-font $font_settings \

grid .rb_inpaint		-in .fr_inpaint -row 0 -column 0 -sticky w -columnspan 2
grid .ti_mask 			-in .fr_inpaint -row 1 -column 0 -sticky w
grid .bu_mask			-in .fr_inpaint -row 1 -column 1 -sticky e

grid .fr_inpaint		-in .fr_cmd -row 2

grid .fr_cmd			-in . -row 0 -column 1 -sticky ne -ipadx 4

# ----------- global parameter widgets

labelframe .fr_parms -text "Parameters" -borderwidth 3 -relief sunken

# ----- bits/pixel selection

frame .fr_bits

label .ti_bits -text "bits/pixel" -font $font_settings

radiobutton .rb_8 -text "8" -font $font_settings -variable res_bits -value "8"
radiobutton .rb_16 -text "16" -font $font_settings -variable res_bits -value "16"
radiobutton .rb_32 -text "32" -font $font_settings -variable res_bits -value "32"

grid .ti_bits		-in .fr_bits -row 0 -column 0 -sticky w
grid .rb_8			-in .fr_bits -row 0 -column 1
grid .rb_16			-in .fr_bits -row 0 -column 2
grid .rb_32			-in .fr_bits -row 0 -column 3
grid .fr_bits		-in .fr_parms -row 0 -column 0 -columnspan 4 -sticky nw

# ------ Assorted parameters as spinboxes, scales, checkboxes...
# coded and displayed in order as displayed by greycstation -h
# naming convention is .ti_XXX (title) .sp_XXX (spinbox) .sc_XXX (scale) .cb_XXX (checkbutton)
# where XXX is the parameter preceded by p. Thus -dt is .ti_pdt/.sp_pdt

label .ti_pdt  -text "-dt" -font $font_settings
spinbox .sp_pdt -from 0 -to 100 -width 3 -font $font_settings
grid .ti_pdt 		-in .fr_parms -row 1 -column 0 -sticky e
grid .sp_pdt		-in .fr_parms -row 1 -column 1 -sticky w -padx 8

label .ti_piter -text "-iter" -font $font_settings
spinbox .sp_piter -from 1 -to 16 -width 3 -font $font_settings
grid .ti_piter		-in .fr_parms -row 1 -column 2 -sticky e
grid .sp_piter		-in .fr_parms -row 1 -column 3 -sticky w -padx 8

label .ti_pp -text "-p" -font $font_settings
scale .sc_pp -from 0 -to 5.0 -digits 3 -resolution 0.01 -tickinterval 0.5 \
	-length 350 -orient horizontal -font {courier 8} -showvalue true
grid .ti_pp 		-in .fr_parms -row 3 -column 0 -sticky e
grid .sc_pp			-in .fr_parms -row 3 -column 1 -columnspan 3 -sticky w

label .ti_pa -text "-a" -font $font_settings
scale .sc_pa -from 0 -to 1.0 -digits 3 -resolution 0.01 -tickinterval 0.1 \
	-length 350 -orient horizontal -font {courier 8} -showvalue true
grid .ti_pa			-in .fr_parms -row 4 -column 0 -sticky e
grid .sc_pa			-in .fr_parms -row 4 -column 1 -columnspan 3 -sticky w

label .ti_palpha -text "-alpha" -font $font_settings
scale .sc_palpha -from 0 -to 16.0 -digits 3 -resolution 0.1 -tickinterval 2 \
	-length 350 -orient horizontal -font {courier 8} -showvalue true
grid .ti_palpha		-in .fr_parms -row 5 -column 0 -sticky e
grid .sc_palpha		-in .fr_parms -row 5 -column 1 -columnspan 3 -sticky w

label .ti_psigma -text "-sigma" -font $font_settings
scale .sc_psigma -from 0 -to 8.0 -digits 3 -resolution 0.1 -tickinterval 1 \
	-length 350 -orient horizontal -font {courier 8} -showvalue true
grid .ti_psigma		-in .fr_parms -row 6 -column 0 -sticky e
grid .sc_psigma		-in .fr_parms -row 6 -column 1 -columnspan 3 -sticky w

label .ti_pfast -text "-fast" -font $font_settings
checkbutton .cb_pfast -variable fast_mode
grid .ti_pfast 		-in .fr_parms -row 7 -column 0 -sticky e
grid .cb_pfast		-in .fr_parms -row 7 -column 1 -sticky w

label .ti_pprec -text "-prec" -font $font_settings
spinbox .sb_pprec -from 1 -to 9 -width 3 -font $font_settings
grid .ti_pprec 		-in .fr_parms -row 7 -column 2 -sticky e
grid .sb_pprec		-in .fr_parms -row 7 -column 3 -sticky w -padx 8

label .ti_pdl -text "-dl" -font $font_settings
scale .sc_pdl -from 0 -to 1.0 -digits 3 -resolution 0.01 -tickinterval 0.1 \
	-length 350 -orient horizontal -font {courier 8} -showvalue true
grid .ti_pdl		-in .fr_parms -row 8 -column 0 -sticky e
grid .sc_pdl		-in .fr_parms -row 8 -column 1 -columnspan 3 -sticky w

label .ti_pda -text "-da" -font $font_settings
scale .sc_pda -from 0 -to 90 -digits 2 -resolution 1.0 -tickinterval 5 \
	-length 350 -orient horizontal -font {courier 8} -showvalue true
grid .ti_pda		-in .fr_parms -row 8 -column 0 -sticky e
grid .sc_pda		-in .fr_parms -row 8 -column 1 -columnspan 3 -sticky w

label .ti_pinterp -text "-interp" -font $font_settings
radiobutton .rb_interp0 -text "n-n" -font $font_settings -variable pinterp -value "0"
radiobutton .rb_interp1 -text "lin" -font $font_settings -variable pinterp -value "1"
radiobutton .rb_interp2 -text "R-K" -font $font_settings -variable pinterp -value "2"
grid .ti_pinterp 	-in .fr_parms -row 9 -column 0 -sticky e
grid .rb_interp0 	-in .fr_parms -row 9 -column 1
grid .rb_interp1	-in .fr_parms -row 9 -column 2
grid .rb_interp2	-in .fr_parms -row 9 -column 3

label .ti_psdt -text "-sdt" -font $font_settings
spinbox .sp_psdt -from 1 -to 100 -width 5 -font $font_settings
grid .ti_psdt		-in .fr_parms -row 10 -column 0 -sticky e
grid .sp_psdt		-in .fr_parms -row 10 -column 1 -sticky w -padx 8

label .ti_psp -text "-sp" -font $font_settings
spinbox .sp_psp -from 0 -to 16 -width 3 -font $font_settings
grid .ti_psp		-in .fr_parms -row 10 -column 2 -sticky e
grid .sp_psp		-in .fr_parms -row 10 -column 3 -sticky w -padx 8

label .ti_ptile -text "-tile" -font $font_settings
spinbox .sp_ptile -values {0 256 512 1024 2048} -width 6 -font $font_settings
grid .ti_ptile 		-in .fr_parms -row 11 -column 0 -sticky e
grid .sp_ptile		-in .fr_parms -row 11 -column 1 -sticky w -padx 8

label .ti_pbtile -text "-btile" -font $font_settings
spinbox .sp_pbtile -from 0 -to 16 -width 3 -font $font_settings
grid .ti_pbtile		-in .fr_parms -row 11 -column 2 -sticky e
grid .sp_pbtile		-in .fr_parms -row 11 -column 3 -sticky w -padx 8

grid .fr_parms			-in . -row 1 -column 1 -rowspan 2 -sticky sw

# last part of setup, set defaults

# defaults sets default values in the various spinboxes and scales.
# this is called during setup and from a button. It does not change
# the selections of source/dest dirs or mask image.

proc defaults { } {
global cmd_string
global res_bits
global fast_mode
global pinterp

	set cmd_string "-restore"
	set res_bits "8"
	.sp_gh set 100
	.sp_gv set 100
	.sp_pdt set 20
	.sp_piter set 1
	.sc_pp set 0.8
	.sc_pa set 0.9
	.sc_palpha set 0.8
	.sc_psigma set 0.8
	set fast_mode 1
	.sb_pprec set 2
	.sc_pdl set 0.8
	.sc_pda set 30
	set pinterp "0"
	.sp_psdt set 10
	.sp_psp set 3
	.sp_ptile set 0
	.sp_pbtile set 4
}

defaults

# ----------- Procedures called from UI elements

# doit 0/1 invokes the greycstoration command using the parameters
# set by the widgets plus -visu with its argument 0/1.

proc doit {arg} {
global greycstoration
global list_files
global cmd_string
global mask_path
global res_bits
global fast_mode
global pinterp

	set selnums [.lb_files curselection]
	if { $selnums eq "" } { return }
	set sdir [.ti_source cget -text]
	set odir [.ti_dest cget -text]
	set parms "-bits $res_bits "
	set parms "$parms -dt [.sp_pdt get]"
	set parms "$parms -iter [.sp_piter get]"
	set parms "$parms -p [.sc_pp get]"
	set parms "$parms -a [.sc_pa get]"
	set parms "$parms -alpha [.sc_palpha get]"
	set parms "$parms -sigma [.sc_psigma get]"
	set parms "$parms -fast $fast_mode"
	set parms "$parms -prec [.sb_pprec get]"
	set parms "$parms -dl [.sc_pdl get]"
	set parms "$parms -da [.sc_pda get]"
	set parms "$parms -interp $pinterp"
	set parms "$parms -sdt [.sp_psdt get]"
	set parms "$parms -sp [.sp_psp get]"
	if { [.sp_ptile get] } {
		set parms "$parms -tile [.sp_ptile get] -btile [.sp_pbtile get]"
	}
	foreach number $selnums {
		set file [.lb_files get $number]
		set ipath [.ti_source cget -text]
		set opath [.ti_dest cget -text]
		set mask "$mask_path[.ti_mask cget -text]"
		set cmd "greycstoration -visu $arg $cmd_string $ipath/$file -o $opath/$file"
		if { $cmd_string eq "-inpaint" } {
			set cmd "$cmd -reference $mask"
		}
		if { $cmd_string eq "-resize" } {
			set cmd "$cmd -g [.sp_gh get]"
		}
		set cmd "$cmd $parms"
		puts "$cmd"
		eval "exec $cmd >& ~/greycstoration_blah_blah.txt"
	}
}

# get_dest_dir prompts user for destination directory and stores as
# text of label .ti_dest.

proc get_dest_dir { } {
	set dir [ tk_chooseDirectory \
		-title "Directory to receive output image(s)" \
		-mustexist true ]
	if { $dir eq "" } { set dir "(?)" }
	.ti_dest configure -text $dir
}

# get_source_dir prompts user for source directory, stores it as
# text of label .ti_source, and populates .lb_files with list of
# files in that directory.

proc get_source_dir { } {
global list_files
	set dir [ tk_chooseDirectory \
		-title "Directory of source image(s)" \
		-mustexist true ]
	if { $dir eq "" } {
	# user must have hit cancel button
		set dir "(?)"
		set list_files [list ]
		return
	}
	.ti_source configure -text $dir
	set list_files [glob -directory $dir -tails -types f * ]
}

# get_mask prompts the user to select a file for the inpaint mask
# and stores the filename in the .ti_mask text. Starting dir is the
# source dir if one has been chosen. Full path is saved in mask_path

proc get_mask { } {
global mask_path

	set sdir [.ti_source cget -text]
	if { $sdir ne "" } {
		set path [ tk_getOpenFile -initialdir $sdir \
			-multiple false -title "Select inpaint Mask image" ]
	} else {
		set path [ tk_getOpenFile \
			-multiple false -title "Select inpaint Mask image" ]
	}
	set slash [string last "/" $path ]
	if [ expr $slash == -1 ] {
		set mask_path ""
	} else {
		set mask_path [string range $path 0 $slash]
		set path [string range $path [expr $slash + 1] end ]
	}
	.ti_mask configure -text $path
}
