| [32535cc] | 1 | package require Metawidget |
|---|
| 2 | |
|---|
| 3 | # name: Toolbar |
|---|
| 4 | # args: args: option-value pairs |
|---|
| 5 | # creates inner widgets and bindings. initializes variables. |
|---|
| 6 | metawidget create Toolbar { |
|---|
| 7 | # padding of 2 pixel between outer frame and the buttons |
|---|
| 8 | pack [frame $this.frm -border 2 -relief flat] -side top -fill both -expand 1 |
|---|
| 9 | |
|---|
| 10 | # popup menu for right mouse key |
|---|
| 11 | menu $this.menu -tearoff 0 |
|---|
| 12 | $this.menu add command -label Top -command "$this config -side top" |
|---|
| 13 | $this.menu add command -label Bottom -command "$this config -side bottom" |
|---|
| 14 | $this.menu add command -label Left -command "$this config -side left" |
|---|
| 15 | $this.menu add command -label Right -command "$this config -side right" |
|---|
| 16 | |
|---|
| 17 | # this is for X11 only. it's a noop on Windows and Mac |
|---|
| 18 | bind $this.menu <FocusOut> "$this.menu unpost" |
|---|
| 19 | |
|---|
| 20 | # new class bindings make Toolbar draggable |
|---|
| 21 | bind Toolbar$this <1> "$this _click" |
|---|
| 22 | bind Toolbar$this <B1-Motion> "$this _drag %X %Y" |
|---|
| 23 | bind Toolbar$this <3> "$this.menu post %X %Y; focus $this.menu" |
|---|
| 24 | |
|---|
| 25 | # buttons get a nice roll-over effect |
|---|
| 26 | bind Toolbutton$this <Enter> {%W config -relief raised} |
|---|
| 27 | bind Toolbutton$this <Leave> {%W config -relief flat} |
|---|
| 28 | |
|---|
| 29 | my wParent [winfo parent $this] |
|---|
| 30 | |
|---|
| 31 | # set options by calling their member functions |
|---|
| 32 | -side top |
|---|
| 33 | -state normal |
|---|
| 34 | } {} -default frm -border 1 -relief raised |
|---|
| 35 | |
|---|
| 36 | # name: _click |
|---|
| 37 | # args: - |
|---|
| 38 | # called when clicked. stores the coordinates of the parent window. |
|---|
| 39 | metawidget proc Toolbar _click {} { |
|---|
| 40 | my iX1 [expr [winfo rootx [my wParent]]+20] |
|---|
| 41 | my iY1 [expr [winfo rooty [my wParent]]+20] |
|---|
| 42 | my iX2 [expr [my iX1]+[winfo width [my wParent]]-40] |
|---|
| 43 | my iY2 [expr [my iY1]+[winfo height [my wParent]]-40] |
|---|
| 44 | } |
|---|
| 45 | |
|---|
| 46 | # name: _drag |
|---|
| 47 | # args: iPx, iPy: mouse coordinates |
|---|
| 48 | # called when dragged. detects if the mouse is outside of any of the four |
|---|
| 49 | # sides of the parent window and places the Toolbar accordingly. |
|---|
| 50 | metawidget proc Toolbar _drag { iPx iPy } { |
|---|
| 51 | if { $iPx < [my iX1] && [my -side] != "left" } { |
|---|
| 52 | -side left |
|---|
| 53 | } elseif { $iPx > [my iX2] && [my -side] != "right" } { |
|---|
| 54 | -side right |
|---|
| 55 | } elseif { $iPy < [my iY1] && [my -side] != "top" } { |
|---|
| 56 | -side top |
|---|
| 57 | } elseif { $iPy > [my iY2] && [my -side] != "bottom" } { |
|---|
| 58 | -side bottom |
|---|
| 59 | } |
|---|
| 60 | } |
|---|
| 61 | |
|---|
| 62 | # name: _checkItem |
|---|
| 63 | # args: sTag: item tag |
|---|
| 64 | # throws an exception if the given tag does not exists. tests on |
|---|
| 65 | # existence of a private variable. |
|---|
| 66 | metawidget proc Toolbar _checkItem { sTag } { |
|---|
| 67 | if { ! [myinfo exists _$sTag.wWidget] } { |
|---|
| 68 | error "Toolbar $this: Item $sTag does not exist." |
|---|
| 69 | } |
|---|
| 70 | } |
|---|
| 71 | |
|---|
| 72 | # name: _redraw |
|---|
| 73 | # args: - |
|---|
| 74 | # redraws the Toolbar. computes the values for the -fill and -side options |
|---|
| 75 | # and the first child of the parent. packs the Toolbar before that child. |
|---|
| 76 | metawidget proc Toolbar _redraw {} { |
|---|
| 77 | set sFill [mkw.decode [my -side] "top x bottom x left y right y"] |
|---|
| 78 | set sInner [mkw.decode [my -side] "top left bottom left left top right top"] |
|---|
| 79 | set sFirst [lindex [pack slaves [my wParent]] 0] |
|---|
| 80 | |
|---|
| 81 | # pack Toolbar *before* first child (if any) |
|---|
| 82 | if { $sFirst == {} } { |
|---|
| 83 | pack $this -side [my -side] -fill $sFill |
|---|
| 84 | } elseif { [lsearch [bindtags $sFirst] "Statusbar"] != -1 } { |
|---|
| 85 | pack $this -side [my -side] -fill $sFill -after $sFirst |
|---|
| 86 | } else { |
|---|
| 87 | pack $this -side [my -side] -fill $sFill -before $sFirst |
|---|
| 88 | } |
|---|
| 89 | |
|---|
| 90 | # pack the buttons inside the Toolbar. |
|---|
| 91 | foreach sWidget [winfo children $this.frm] { |
|---|
| 92 | if { [winfo class $sWidget] == "Frame" } { |
|---|
| 93 | # special treatment for separator frames |
|---|
| 94 | if { $sFill == "x" } { |
|---|
| 95 | pack $sWidget -side $sInner -fill y -padx 4 -pady 1 |
|---|
| 96 | } else { |
|---|
| 97 | pack $sWidget -side $sInner -fill x -padx 1 -pady 4 |
|---|
| 98 | } |
|---|
| 99 | } else { |
|---|
| 100 | # all other buttons |
|---|
| 101 | pack $sWidget -side $sInner -fill both |
|---|
| 102 | } |
|---|
| 103 | } |
|---|
| 104 | } |
|---|
| 105 | |
|---|
| 106 | # name: _bindTag |
|---|
| 107 | # args: sWhat: operation (extend or shrink) |
|---|
| 108 | # wWidget: widget to modify |
|---|
| 109 | # sBindTag: bindtag to add or remove |
|---|
| 110 | # adds or removes a bindtag to a widget. |
|---|
| 111 | metawidget proc Toolbar _bindTag { sWhat wWidget sBindTag } { |
|---|
| 112 | bindtags $wWidget [mkw.l$sWhat [bindtags $wWidget] $sBindTag] |
|---|
| 113 | } |
|---|
| 114 | |
|---|
| 115 | # name: _checkButton |
|---|
| 116 | # args: sTag: item tag |
|---|
| 117 | # iState: optional new state (boolean) |
|---|
| 118 | # handles checkbuttons. makes them look "checked" (=sunken) respectively |
|---|
| 119 | # normal again. |
|---|
| 120 | metawidget proc Toolbar _checkButton { sTag {iState {}} } { |
|---|
| 121 | # either toggle state or set new state from iState |
|---|
| 122 | if { $iState == {} } { |
|---|
| 123 | my _$sTag.iState [expr ! [my _$sTag.iState]] |
|---|
| 124 | } else { |
|---|
| 125 | my _$sTag.iState [mkw.complete $iState {on off yes no 1 0}] |
|---|
| 126 | } |
|---|
| 127 | |
|---|
| 128 | # change relief and add resp. remove bind tag for roll-over effect |
|---|
| 129 | if { [my _$sTag.iState] } { |
|---|
| 130 | [my _$sTag.wWidget] config -relief sunken |
|---|
| 131 | _bindTag shrink [my _$sTag.wWidget] Toolbutton$this |
|---|
| 132 | } else { |
|---|
| 133 | [my _$sTag.wWidget] config -relief flat |
|---|
| 134 | _bindTag extend [my _$sTag.wWidget] Toolbutton$this |
|---|
| 135 | } |
|---|
| 136 | } |
|---|
| 137 | |
|---|
| 138 | # name: _radioButton |
|---|
| 139 | # args: sTag: item tag |
|---|
| 140 | # handles radiobuttons. sets all buttons of a group to normal state and |
|---|
| 141 | # then makes the clicked one look checked. |
|---|
| 142 | metawidget proc Toolbar _radioButton { sTag } { |
|---|
| 143 | set wButton $this.frm._$sTag |
|---|
| 144 | |
|---|
| 145 | # reset all radiobuttons of the group |
|---|
| 146 | foreach sGroupTag [my __[my _$sTag.sGroup]] { |
|---|
| 147 | $this.frm._$sGroupTag config -relief flat |
|---|
| 148 | _bindTag extend $this.frm._$sGroupTag Toolbutton$this |
|---|
| 149 | } |
|---|
| 150 | |
|---|
| 151 | # then check the activated button |
|---|
| 152 | [my _$sTag.wWidget] config -relief sunken |
|---|
| 153 | _bindTag shrink [my _$sTag.wWidget] Toolbutton$this |
|---|
| 154 | } |
|---|
| 155 | |
|---|
| 156 | # name: -side |
|---|
| 157 | # args: sSide: side to place Toolbar on |
|---|
| 158 | # option member. repositions the Toolbar. |
|---|
| 159 | metawidget proc Toolbar -side { sSide } { |
|---|
| 160 | my -side [mkw.complete $sSide {top bottom left right}] |
|---|
| 161 | _redraw |
|---|
| 162 | } |
|---|
| 163 | |
|---|
| 164 | # name: -state |
|---|
| 165 | # args: sState: new state for the Toolbar |
|---|
| 166 | # option member. lets a Toolbar disappear or disables dragging. |
|---|
| 167 | metawidget proc Toolbar -state { sState } { |
|---|
| 168 | my -state [mkw.complete $sState {normal fixed withdrawn}] |
|---|
| 169 | |
|---|
| 170 | switch [my -state] { |
|---|
| 171 | normal { |
|---|
| 172 | _bindTag extend $this.frm Toolbar$this |
|---|
| 173 | -side [my -side] |
|---|
| 174 | } |
|---|
| 175 | fixed { |
|---|
| 176 | _bindTag shrink $this.frm Toolbar$this |
|---|
| 177 | -side [my -side] |
|---|
| 178 | } |
|---|
| 179 | withdrawn { |
|---|
| 180 | pack forget $this |
|---|
| 181 | } |
|---|
| 182 | } |
|---|
| 183 | } |
|---|
| 184 | |
|---|
| 185 | # name: add |
|---|
| 186 | # args: sType: type of new object |
|---|
| 187 | # sTag: unique item tag |
|---|
| 188 | # args: option-value pairs |
|---|
| 189 | # adds a new button, checkbutton, radiobutton or separator. |
|---|
| 190 | metawidget proc Toolbar add { sType sTag args } { |
|---|
| 191 | if { [myinfo exists _$sTag.wWidget] } { |
|---|
| 192 | error "Toolbar $this: Item $sTag already exists." |
|---|
| 193 | } |
|---|
| 194 | |
|---|
| 195 | set sType [mkw.complete $sType {button checkbutton radiobutton separator}] |
|---|
| 196 | set wWidget $this.frm._$sTag |
|---|
| 197 | |
|---|
| 198 | # store item attributes in private variables |
|---|
| 199 | my _$sTag.sTag $sTag |
|---|
| 200 | my _$sTag.sType $sType |
|---|
| 201 | my _$sTag.wWidget $wWidget |
|---|
| 202 | my _$sTag.iState 0 |
|---|
| 203 | |
|---|
| 204 | if { $sType == "separator" } { |
|---|
| 205 | frame $wWidget -border 1 -relief sunken -width 2 -height 2 |
|---|
| 206 | _bindTag extend $wWidget Toolbar$this |
|---|
| 207 | } else { |
|---|
| 208 | button $wWidget -border 1 -relief flat -padx 0 -pady 0 -takefocus 0 |
|---|
| 209 | _bindTag extend $wWidget Toolbutton$this |
|---|
| 210 | |
|---|
| 211 | if { $sType == "checkbutton" } { |
|---|
| 212 | bind $wWidget <1> "$this _checkButton $sTag" |
|---|
| 213 | } elseif { $sType == "radiobutton" } { |
|---|
| 214 | bind $wWidget <1> "$this _radioButton $sTag" |
|---|
| 215 | |
|---|
| 216 | # extract -group option and append it to a list |
|---|
| 217 | set args [mkw.options $args * {-group *}] |
|---|
| 218 | if { ! [info exists -group] } { |
|---|
| 219 | set -group default |
|---|
| 220 | } |
|---|
| 221 | |
|---|
| 222 | my _$sTag.sGroup ${-group} |
|---|
| 223 | if { [myinfo exists __${-group}] } { |
|---|
| 224 | my __${-group} [linsert [my __${-group}] end $sTag] |
|---|
| 225 | } else { |
|---|
| 226 | my __${-group} $sTag |
|---|
| 227 | } |
|---|
| 228 | } |
|---|
| 229 | } |
|---|
| 230 | |
|---|
| 231 | eval itemconf {$sTag} $args |
|---|
| 232 | |
|---|
| 233 | if { [my -state] != "withdrawn" } { |
|---|
| 234 | _redraw |
|---|
| 235 | } |
|---|
| 236 | |
|---|
| 237 | return $wWidget |
|---|
| 238 | } |
|---|
| 239 | |
|---|
| 240 | # name: delete |
|---|
| 241 | # args: args: list of item tags |
|---|
| 242 | # deletes Toolbar objects. |
|---|
| 243 | metawidget proc Toolbar delete { args } { |
|---|
| 244 | foreach sTag $args { |
|---|
| 245 | if { [my _$sTag.sType] == "radiobutton" } { |
|---|
| 246 | my __[my _$sTag.sGroup] [mkw.lshrink [my __[my _$sTag.sGroup]] $sTag] |
|---|
| 247 | } |
|---|
| 248 | |
|---|
| 249 | destroy [my _$sTag.wWidget] |
|---|
| 250 | unmy _$sTag.sTag _$sTag.sType _$sTag.wWidget _$sTag.iState _$sTag.sGroup |
|---|
| 251 | } |
|---|
| 252 | |
|---|
| 253 | _redraw |
|---|
| 254 | } |
|---|
| 255 | |
|---|
| 256 | # name: itemconf |
|---|
| 257 | # args: sTag: item tag |
|---|
| 258 | # args: option-value pairs |
|---|
| 259 | # configures a Toolbar object. |
|---|
| 260 | metawidget proc Toolbar itemconf { sTag args } { |
|---|
| 261 | _checkItem $sTag |
|---|
| 262 | eval {$this.frm._$sTag} config $args |
|---|
| 263 | } |
|---|
| 264 | |
|---|
| 265 | # name: itemcget |
|---|
| 266 | # args: sTag: item tag |
|---|
| 267 | # sOption: option to query |
|---|
| 268 | # returns an option value of a Toolbar object. |
|---|
| 269 | metawidget proc Toolbar itemcget { sTag sOption } { |
|---|
| 270 | _checkItem $sTag |
|---|
| 271 | $this.frm._$sTag cget $sOption |
|---|
| 272 | } |
|---|
| 273 | |
|---|
| 274 | # name: set |
|---|
| 275 | # args: sTag: item tag |
|---|
| 276 | # iState: new state for checkbuttons |
|---|
| 277 | # similar to invoke, but the button's command is not invoked, |
|---|
| 278 | # just the toolbutton is set. |
|---|
| 279 | metawidget proc Toolbar set_ { sTag {iState {}} } { |
|---|
| 280 | _checkItem $sTag |
|---|
| 281 | |
|---|
| 282 | if { [my _$sTag.sType] == "checkbutton" } { |
|---|
| 283 | _checkButton $sTag $iState |
|---|
| 284 | } elseif { [my _$sTag.sType] == "radiobutton" } { |
|---|
| 285 | _radioButton $sTag |
|---|
| 286 | } |
|---|
| 287 | } |
|---|
| 288 | |
|---|
| 289 | # name: get |
|---|
| 290 | # args: sTag: item tag |
|---|
| 291 | # returns the state of a button. always 0 for regular buttons. |
|---|
| 292 | # 0 or 1 for check- and radiobuttons. |
|---|
| 293 | metawidget proc Toolbar get { sTag } { |
|---|
| 294 | _checkItem $sTag |
|---|
| 295 | return [my _$sTag.iState] |
|---|
| 296 | } |
|---|
| 297 | |
|---|
| 298 | # name: invoke |
|---|
| 299 | # args: sTag: item tag |
|---|
| 300 | # iState: new state for checkbuttons |
|---|
| 301 | # invokes a button. if iState is specified, it sets a checkbutton to the |
|---|
| 302 | # corresponding value. does not apply for buttons and radiobuttons, since |
|---|
| 303 | # there state is always known. |
|---|
| 304 | metawidget proc Toolbar invoke { sTag {iState {}} } { |
|---|
| 305 | _checkItem $sTag |
|---|
| 306 | set_ $sTag $iState |
|---|
| 307 | $this.frm._$sTag invoke |
|---|
| 308 | } |
|---|
| 309 | |
|---|
| 310 | # name: menu |
|---|
| 311 | # args: args: arguments for the regular menu command. |
|---|
| 312 | # simply passes all arguments to the popup menu. |
|---|
| 313 | metawidget proc Toolbar menu_ { args } { |
|---|
| 314 | eval $this.menu $args |
|---|
| 315 | } |
|---|
| 316 | |
|---|
| 317 | # name: names |
|---|
| 318 | # args: - |
|---|
| 319 | # returns the tags of all toolbar buttons |
|---|
| 320 | metawidget proc Toolbar names { {sPattern *} } { |
|---|
| 321 | set lTags {} |
|---|
| 322 | |
|---|
| 323 | foreach sVar [myinfo vars _*.sTag] { |
|---|
| 324 | if { ! [string match $sPattern [my $sVar]] } continue |
|---|
| 325 | lappend lTags [my $sVar] |
|---|
| 326 | } |
|---|
| 327 | |
|---|
| 328 | return $lTags |
|---|
| 329 | } |
|---|
| 330 | |
|---|
| 331 | metawidget command Toolbar _click _click |
|---|
| 332 | metawidget command Toolbar _drag _drag |
|---|
| 333 | metawidget command Toolbar _checkButton _checkButton |
|---|
| 334 | metawidget command Toolbar _radioButton _radioButton |
|---|
| 335 | |
|---|
| 336 | metawidget command Toolbar add add |
|---|
| 337 | metawidget command Toolbar delete delete |
|---|
| 338 | metawidget command Toolbar itemconf itemconf |
|---|
| 339 | metawidget command Toolbar itemcget itemcget |
|---|
| 340 | metawidget command Toolbar set set_ |
|---|
| 341 | metawidget command Toolbar get get |
|---|
| 342 | metawidget command Toolbar invoke invoke |
|---|
| 343 | metawidget command Toolbar menu menu_ |
|---|
| 344 | metawidget command Toolbar names names |
|---|
| 345 | |
|---|
| 346 | metawidget option Toolbar -side -side |
|---|
| 347 | metawidget option Toolbar -state -state |
|---|
| 348 | |
|---|
| 349 | proc test {} { |
|---|
| 350 | wm minsize . 320 250 |
|---|
| 351 | |
|---|
| 352 | image create photo p1 -file ./demos/images/Notebook.gif |
|---|
| 353 | image create photo p2 -file ./demos/images/Compass.gif |
|---|
| 354 | |
|---|
| 355 | pack [frame .work -bg gray50] -fill both -expand 1 |
|---|
| 356 | grid [frame .test] -in .work |
|---|
| 357 | |
|---|
| 358 | pack [text .test.text -width 40 -height 10 -wrap word] |
|---|
| 359 | toolbar .test.tbar -state fixed -side bottom -relief sunken |
|---|
| 360 | .test.text insert end "Above are regular buttons, checkbuttons and radiobuttons." |
|---|
| 361 | .test.text insert end "The Toolbars can be dragged to the four window sides." |
|---|
| 362 | .test.text insert end "The right mouse button will invoke a menu.\n" |
|---|
| 363 | |
|---|
| 364 | .test.tbar add button b1 -image p1 -command {.test.text delete 1.0 end } |
|---|
| 365 | .test.tbar add check b2 -image p2 -command { |
|---|
| 366 | if { [.test.tbar get b2] } { |
|---|
| 367 | .test.text config -bg black -fg white |
|---|
| 368 | } else { |
|---|
| 369 | .test.text config -bg white -fg black |
|---|
| 370 | } |
|---|
| 371 | } |
|---|
| 372 | |
|---|
| 373 | toolbar .tbar1 |
|---|
| 374 | .tbar1 add button button1 -image p2 -command {.test.text insert end "button1 clicked\n"; .test.text see end } |
|---|
| 375 | .tbar1 add button button2 -image p2 -command {.test.text insert end "button2 clicked\n"; .test.text see end } |
|---|
| 376 | .tbar1 add separator s1 |
|---|
| 377 | .tbar1 add checkbutton check1 -image p1 -command {.test.text insert end "check1 clicked\n"; .test.text see end } |
|---|
| 378 | .tbar1 add checkbutton check2 -image p1 -command {.test.text insert end "check2 clicked\n"; .test.text see end } |
|---|
| 379 | .tbar1 add separator s2 |
|---|
| 380 | .tbar1 add radiobutton radio1 -image p1 -command {.test.text insert end "radio1 clicked\n"; .test.text see end } |
|---|
| 381 | .tbar1 add radiobutton radio2 -image p2 -command {.test.text insert end "radio2 clicked\n"; .test.text see end } |
|---|
| 382 | .tbar1 add radiobutton radio3 -image p1 -command {.test.text insert end "radio3 clicked\n"; .test.text see end } |
|---|
| 383 | .tbar1 add radiobutton radio4 -image p2 -command {.test.text insert end "radio4 clicked\n"; .test.text see end } |
|---|
| 384 | |
|---|
| 385 | toolbar .t2 -side bottom |
|---|
| 386 | .t2 add button b1 -image p1 -bg red |
|---|
| 387 | .t2 add button b2 -image p2 -bg green |
|---|
| 388 | .t2 add button b3 -image p1 -bg yellow |
|---|
| 389 | .t2 add button b4 -image p2 -bg blue |
|---|
| 390 | .t2 add button b5 -image p1 -bg white |
|---|
| 391 | .t2 add button b6 -image p2 -bg black |
|---|
| 392 | } |
|---|
| 393 | |
|---|
| 394 | #test |
|---|
| 395 | |
|---|