1# 2# This software is Copyright by the Board of Trustees of Michigan 3# State University (c) Copyright 2005. 4# 5# You may use this software under the terms of the GNU public license 6# (GPL) ir the Tcl BSD derived license The terms of these licenses 7# are described at: 8# 9# GPL: http://www.gnu.org/licenses/gpl.txt 10# Tcl: http://www.tcl.tk/softare/tcltk/license.html 11# Start with the second paragraph under the Tcl/Tk License terms 12# as ownership is solely by Board of Trustees at Michigan State University. 13# 14# Author: 15# Ron Fox 16# NSCL 17# Michigan State University 18# East Lansing, MI 48824-1321 19# 20 21 22# Provide a megawidget that is a matrix of radio buttons 23# and a variable that is tracked. The idea is that this 24# can be used to control a device that has an enumerable 25# set of values. 26# 27# OPTIONS: 28# -orient Determines the order in which the radio buttons are 29# laid out: 30# vertical - buttons run from top to bottom then left to right. 31# horizontal - buttons run from left to right top to bottom. 32# -columns Number of columns. 33# -rows Number of rows. 34# -values Contains a list of values. Each element of the list is either 35# a single element, which represents the value of the button or 36# is a pair of values that represent a name/value pair for the button. 37# If -values is provided, only one of -rows/-columns can be provided. 38# If -values is not provided, both -rows and -columns must be provided 39# and the label name/value pairs are 1,2,3,4,5... 40# -variable Variable to track in the widget. 41# -command Script to run when a radio button is clicked. 42# 43# METHODS: 44# get - Gets the current button value. 45# set - Sets the current button value (-command is invoked if defined). 46# NOTES: 47# 1. See the constraints on the options described above. 48# 2. If, on entry, the variable (either global or fully namespace qualified 49# is set and matches a radio button value, that radio button is initially 50# lit. 51# 3. The geometric properties of the widget can only be established at 52# construction time, and are therefore static. 53 54package provide radioMatrix 1.0 55package require Tk 56package require snit 57package require bindDown 58 59namespace eval controlwidget { 60 namespace export radioMatrix 61} 62 63snit::widget ::controlwidget::radioMatrix { 64 65 delegate option -variable to label as -textvariable 66 delegate option * to hull 67 68 69 option -orient horizontal 70 option -rows {1} 71 option -columns {} 72 option -values [list] 73 option -command [list] 74 75 76 variable radioVariable; # for the radio button. 77 78 # Construct the widget. 79 80 constructor args { 81 82 # The buttons go in a frame just to make it easy to lay them out.: 83 84 set bf [frame $win.buttons] 85 install label using label $win.label 86 87 # Process the configuration. 88 89 $self configurelist $args 90 91 92 # Ensure that the option constraints are met. 93 94 $self errorIfConstraintsNotMet 95 96 # If the values have not been provided, then use the rows/columns 97 # to simluate them. 98 99 if {$options(-values) eq ""} { 100 set totalValues [expr $options(-columns) * $options(-rows)] 101 for {set i 0} {$i < $totalValues} {incr i} { 102 lappend options(-values) $i 103 } 104 } 105 106 # Top level layout decision based on orientation. 107 108 if {$options(-orient) eq "horizontal"} { 109 $self arrangeHorizontally 110 } elseif {$options(-orient) eq "vertical"} { 111 $self arrangeVertically 112 } else { 113 error "Invalid -orient value: $options(-orient)" 114 } 115 116 grid $bf 117 grid $win.label 118 119 # If the label has a text variable evaluate it to see 120 # if we can do a set with it: 121 122 set labelvar [$win.label cget -textvariable] 123 if {$labelvar ne ""} { 124 $self Set [set ::$labelvar] 125 } 126 bindDown $win $win 127 } 128 129 # Public methods: 130 131 method get {} { 132 return $radioVariable 133 } 134 method set value { 135 136 set radioVariable $value 137 138 } 139 140 141 # Private methods and procs. 142 143 # Ensure the constraints on the options are met. 144 145 method errorIfConstraintsNotMet {} { 146 if {$options(-values) eq "" && 147 ($options(-rows) eq "" || $options(-columns) eq "")} { 148 error "If -values is not supplied, but -rows and -coumns must be." 149 } 150 if {($options(-rows) ne "" && $options(-columns) ne "") && 151 $options(-values) ne ""} { 152 error "If both -rows and -coumns were supplied, -values cannot be" 153 } 154 } 155 156 157 # Process radio button change. 158 # 159 method onChange {} { 160 set script $options(-command) 161 if {$script ne ""} { 162 eval $script 163 } 164 } 165 # Manage horizontal layout 166 167 method arrangeHorizontally {} { 168 # 169 # Either both rows and columns are defined, or 170 # one is defined and the other must be computed from the 171 # length of the values list (which by god was defined). 172 # If both are defined, values was computed from them. 173 174 set rows $options(-rows) 175 set cols $options(-columns) 176 177 # Only really need # of cols. 178 179 set len [llength $options(-values)] 180 if {$cols eq ""} { 181 set cols [expr ($len + $rows - 1)/$rows] 182 } 183 set index 0 184 set rowNum 0 185 186 while {$index < $len} { 187 for {set i 0} {$i < $cols} {incr i} { 188 if {$index >= $len} { 189 break 190 } 191 set item [lindex $options(-values) $index] 192 193 if {[llength $item] > 1} { 194 set label [lindex $item 0] 195 set value [lindex $item 1] 196 } else { 197 set value [lindex $item 0] 198 set label $value 199 } 200 radiobutton $win.buttons.cb$index \ 201 -command [mymethod onChange] \ 202 -variable ${selfns}::radioVariable \ 203 -value $value -text $label 204 grid $win.buttons.cb$index -row $rowNum -column $i 205 incr index 206 } 207 incr rowNum 208 } 209 210 } 211 212 213 # manage vertical layout 214 215 method arrangeVertically {} { 216 # 217 # See arrangeHorizontally for the overall picture, just swap cols 218 # and rows. 219 220 set rows $options(-rows) 221 set cols $options(-columns) 222 223 set len [llength $options(-values)] 224 if {$rows eq ""} { 225 set rows [expr ($len + $cols -1)/$cols] 226 } 227 set index 0 228 set colNum 0 229 while {$index < $len} { 230 for {set i 0} {$i < $rows} {incr i} { 231 if {$index >= $len} { 232 break 233 } 234 set item [lindex $options(-values) $index] 235 if {[llength $item] > 1} { 236 set label [lindex $item 0] 237 set value [lindex $item 1] 238 } else { 239 set value [lindex $item 0] 240 set label $value 241 } 242 243 radiobutton $win.buttons.cb$index \ 244 -command [mymethod onChange] \ 245 -variable ${selfns}::radioVariable \ 246 -value $value -text $label 247 grid $win.buttons.cb$index -row $i -column $colNum 248 incr index 249 } 250 incr colNum 251 } 252 } 253} 254