# ---------------------------------------------------------------------- # EXAMPLE: HSB color editor # ---------------------------------------------------------------------- # Effective Tcl/Tk Programming # Mark Harrison, DSC Communications Corp. # Michael McLennan, Bell Labs Innovations for Lucent Technologies # Addison-Wesley Professional Computing Series # ====================================================================== # Copyright (c) 1996-1997 Lucent Technologies Inc. and Mark Harrison # ====================================================================== proc colordial_create {win} { global env cdInfo frame $win -class Colordial canvas $win.dial pack $win.dial -side bottom label $win.label -text "Color:" pack $win.label -side left frame $win.sample -width 15 -height 15 pack $win.sample -expand yes -fill both -padx 4 -pady 4 set fname [file join $env(TCLWEATHER_LIB) "colors.gif"] set imh [image create photo -file $fname] $win.dial create image 0 0 -anchor nw -image $imh $win.dial create oval 0 0 0 0 -fill black -tags hsval $win.dial create line 0 0 0 0 -width 4 -fill black -tags bval $win.dial configure -width [image width $imh] \ -height [image height $imh] bind $win.dial "button_press $win %x %y" bind $win.dial "button_press $win %x %y" set cdInfo($win-hue) 0 set cdInfo($win-saturation) 0 set cdInfo($win-brightness) 1 colordial_refresh $win return $win } proc button_press {win x y} { if {$x <= 150} { colordial_set_hs $win $x $y } else { colordial_set_b $win $y } } proc colordial_set_b {win y} { global cdInfo set bright [expr (145-$y)/140.0] if {$bright < 0} { set bright 0 } elseif {$bright > 1} { set bright 1 } set cdInfo($win-brightness) $bright colordial_refresh $win } proc colordial_set_hs {win x y} { global cdInfo set hs [colordial_xy2hs $x $y] set hue [lindex $hs 0] set sat [lindex $hs 1] if {$sat > 1} { set sat 1 } set cdInfo($win-hue) $hue set cdInfo($win-saturation) $sat colordial_refresh $win } proc colordial_refresh {win} { global cdInfo set angle $cdInfo($win-hue) set length $cdInfo($win-saturation) set x0 [expr 75 + cos($angle)*$length*70] set y0 [expr 75 - sin($angle)*$length*70] $win.dial coords hsval \ [expr $x0-4] [expr $y0-4] \ [expr $x0+4] [expr $y0+4] set bright $cdInfo($win-brightness) set y0 [expr 145-$bright*140] $win.dial coords bval 154 $y0 176 $y0 $win.sample configure -background [colordial_get $win] } proc colordial_get {win} { global cdInfo set h $cdInfo($win-hue) set s $cdInfo($win-saturation) set v $cdInfo($win-brightness) return [colordial_hsb2rgb $h $s $v] } proc colordial_xy2hs {x0 y0} { set wd 150 set ht 150 set margin 5 set x [expr $x0 - $wd/2] set y [expr $ht/2 - $y0] if {$x != 0} { set angle [expr atan($y/double($x))] if {$x < 0} { set angle [expr $angle+3.14159] } elseif {$y < 0} { set angle [expr $angle+6.28318] } set dx [expr 0.5*cos($angle)*($wd-2*$margin)] set dy [expr 0.5*sin($angle)*($ht-2*$margin)] set len [expr sqrt($dx*$dx+$dy*$dy)] set hue [expr $angle/3.14159*180] set sat [expr sqrt($x*$x+$y*$y)/$len] } elseif {$y > 0} { set hue 90 set len [expr 0.5*($ht-2*$margin)] set sat [expr $y/$len] } else { set hue 270 set len [expr 0.5*($ht-2*$margin)] set sat [expr -$y/$len] } set hue [expr $hue*3.14159/180.0] return [list $hue $sat] } proc colordial_hsb2rgb {h s v} { if {$s == 0} { set v [expr round(65535*$v)] set r $v set g $v set b $v } else { if {$h >= 6.28318} {set h [expr $h-6.28318]} set h [expr $h/1.0472] set f [expr $h-floor($h)] set p [expr round(255*$v*(1.0-$s))] set q [expr round(255*$v*(1.0-$s*$f))] set t [expr round(255*$v*(1.0-$s*(1.0-$f)))] set v [expr round(255*$v)] switch [expr int($h)] { 0 {set r $v; set g $t; set b $p} 1 {set r $q; set g $v; set b $p} 2 {set r $p; set g $v; set b $t} 3 {set r $p; set g $q; set b $v} 4 {set r $t; set g $p; set b $v} 5 {set r $v; set g $p; set b $q} } } return [format "#%.2x%.2x%.2x" $r $g $b] } proc colordial_set_rgb {win r g b} { global cdInfo if {$r < $g} { set min $r } else { set min $g } if {$b < $min} { set min $b } if {$r > $g} { set max $r } else { set max $g } if {$b > $max} { set max $b } set cdInfo($win-brightness) $max set delta [expr $max - $min] if {$max != 0 && $delta != 0} { set cdInfo($win-saturation) [expr $delta / $max] if {$r == $max} { set cdInfo($win-hue) [expr [expr $g - $b] / $delta] } elseif {$g == $max} { set cdInfo($win-hue) [expr 2 + [expr $b - $r] / $delta] } else { set cdInfo($win-hue) [expr 4 + [expr $r - $g] / $delta] } set cdInfo($win-hue) [expr $cdInfo($win-hue) * 3.14159 / 3.0] if {$cdInfo($win-hue) < 0} { set cdInfo($win-hue) [expr $cdInfo($win-hue) + 6.28318] } } else { set cdInfo($win-saturation) 0 set cdInfo($win-hue) 0 } colordial_refresh $win }