# Listbox chapter
proc ListSelect { parent choices } {
	# Create two lists side by side
	frame $parent
	ScrolledListbox2 $parent.choices -width 20 -height 5 -setgrid 1
	ScrolledListbox2 $parent.picked -width 20 -height 5 -setgrid 1
	pack $parent.choices $parent.picked -side left \
		-expand true -fill both

	# Selecting in choice moves items into picked
	bind $parent.choices.list <ButtonPress-1> \
		{ListSelectStart %W %y}
	bind $parent.choices.list <B1-Motion> \
		{ListSelectExtend %W %y}
	bind $parent.choices.list <ButtonRelease-1> \
		[list ListSelectEnd %W %y $parent.picked.list]

	# Selecting in picked deletes items
	bind $parent.picked.list <ButtonPress-1> \
		{ListSelectStart %W %y}
	bind $parent.picked.list <B1-Motion> \
		{ListSelectExtend %W %y}
	bind $parent.picked.list <ButtonRelease-1> \
		{ListDeleteEnd %W %y}

	# Insert all the choices
	# eval is used to construct a command where each
	# item in choices is a separate argument
	eval {$parent.choices.list insert 0} $choices
}

proc ListSelectStart { w y } {
	$w select anchor [$w nearest $y]
}
proc ListSelectExtend { w y } {
	$w select set anchor [$w nearest $y]
}
proc ListSelectEnd {w y list} {
	$w select set anchor [$w nearest $y]
	foreach i [$w curselection] {
		$list insert end [$w get $i]
	}
}

proc ListDeleteEnd {w y} {
	$w select set anchor [$w nearest $y]
	foreach i [lsort -decreasing [$w curselection]] {
		$w delete $i
	}
}
