1# Copyright (C) 1987-2015 by Jeffery P. Hansen 2# 3# This program is free software; you can redistribute it and/or modify 4# it under the terms of the GNU General Public License as published by 5# the Free Software Foundation; either version 2 of the License, or 6# (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License along 14# with this program; if not, write to the Free Software Foundation, Inc., 15# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 16# 17# Last edit by hansen on Sun Feb 1 17:56:08 2009 18# 19 20######################################################################## 21# 22# Function summary: 23# mr Get a message and apply [rescale] to it. 24# ul Underline position generator. 25# offsetgeometry Generate geometry string relative to another window. 26# okcancel Create an OK/Cancel bar for dialogs. 27# replaceExtension Replace the extension of a file name. 28# toolbutton Button for a toolbar 29# ldelete Remove a named item from a list. 30# lsubtract Do a list "set subtraction" option 31# lpop Pop an item from the end of a list 32# lscan Partition elements of a list 33# assoc Find an item from a list of pairs and return value. 34# assocn Generalized version of assoc 35# assocg Find an item from a list of lists and return indexed list. 36# assocset Find an item from a list of pairs and change its value 37# assocsetc Find an item from a list of pairs and change its value (create if necessary) 38# parseargs Parse an argument list. 39# viewFile View the contents of a file in a separate window. 40# min Minimum value 41# max Maximum value 42# ceil Ceiling function 43# floor Floor function 44# labelframe Labled groove frame 45# checkframe Labled groove frame with checkbutton label 46# radioframe Labled groove frame with radiobutton label 47# windowframe Labled groove frame with arbitrary window label 48# gifI Get a gif image from a file or from cache 49# start_splash Display the "splash" window 50# end_splash End the "splash" window. 51# yesno Generic yes/no dialog box 52# frb_trace Flat radio button variable change notifier 53# frb_setMouseOverBackground Set the mouseover background for flat radio buttons. 54# frb_seeB1press See a B1 mouse press on a flat radio button. 55# flatradiobutton Create a flat radio button. 56# paneDecoration Create the decoration for a resizable pane slider. 57# dialogImage Create the image bar for a dialog box. 58# gettoplevel Get the top level window from a path 59# Option:: Options management class 60# sfix Fix any special characters in a string befor saving it. 61# dialogLoad Load new option variables from the dialog box 62# dialogSave Save option variables to the dialog box 63# writePreferences Write current option settings to prefernces file. 64# new Declare a new option. 65# restoreDefaults Restore defaults of all options or of a class of options 66# TimeCheck Procedure timing check 67# begin Begin a timer 68# end End a timer 69# unqiueName Generate a unique name. 70# hexEntrySetup Setup for hex only entry widgets. 71# encodeBits Encode list of numbers into a single number 72# incdecEntry Numeric entry with inc/dec buttons 73# chooseInterval Choose an interval to use for a range 74# colortree Set background color of a window and all its children 75# packPad Add font-size scaled padding to the top and bottom of a frame. 76# linkVars Link two variables 77# 78 79proc mr {tag} { 80 return [rescale [m $tag]] 81} 82 83proc getFontScale {fontName baseEmSize} { 84 return [expr [font measure $fontName "M"] / ($baseEmSize+0.0)] 85} 86 87proc colortree {w args} { 88 if {[lindex $args 0] == "-list"} { 89 set args [lindex $args 1] 90 } 91 92 foreach {sw val} $args { 93 catch { $w configure $sw $val } 94 } 95 96 foreach cw [winfo children $w] { 97 colortree $cw -list $args 98 } 99} 100 101proc dobell args { 102 bell 103} 104 105proc ul {n} { 106 global lang 107 108 if { $lang == "en" } { 109 return $n 110 } else { 111 return -1 112 } 113} 114 115proc safeeval {bad cmd args} { 116 set L {} 117 set skip 0 118 foreach p $args { 119 if {[lsearch -exact $bad $p] >= 0} { 120 set skip 1 121 } elseif {$skip == 0} { 122 lappend L $p 123 } else { 124 set skip 0 125 } 126 } 127 eval $cmd $L 128} 129 130 131# offsetgeometry win dx dy 132# 133# Return a geomtry string with the specified offset from the specified window. 134# 135# 136proc offsetgeometry { win dx dy } { 137 set g [wm geometry $win] 138 set x [string range $g [expr [string first "+" $g] + 1] end] 139 set p [string first "+" $x] 140 set y [string range $x [expr $p + 1] end] 141 set x [string range $x 0 [expr $p - 1]] 142 return +[expr $x + $dx ]+[expr $y + $dy] 143} 144 145proc okcancel {w args} { 146 frame $w 147 148 149 set cancelcommand "destroy $w" 150 set okcommand "destroy $w" 151 set oktext [m b.ok] 152 set canceltext [m b.cancel] 153 set bd [option get $w TkgDialog.borderWidth {}] 154 set relief [option get $w TkgDialog.relief {}] 155 156 parseargs $args {-oktext -canceltext -okcommand -cancelcommand -bd} 157 158 $w configure -relief $relief -bd $bd 159 button $w.ok -text $oktext -command $okcommand 160 button $w.cancel -text $canceltext -command $cancelcommand 161 162 pack $w.cancel -side right -padx 5 -pady 5 163 pack $w.ok -side right -padx 5 -pady 5 164} 165 166# 167# Replace the extension of name with ext. "ext" should 168# include the '.' character if it is desired. 169# 170proc replaceExtension {name ext} { 171 set p [string last "." $name ] 172 if { $p >= 0 } { 173 set name [string range $name 0 [expr $p - 1]] 174 } 175 return "$name$ext" 176} 177 178# 179# Remove all elements from d from l 180# 181proc lsubtract {l d} { 182 foreach x $d { 183 set l [ldelete $l $x] 184 } 185 return $l 186} 187 188# 189# remove i from list l 190# 191proc ldelete {l i} { 192 set p [lsearch $l $i] 193 if { $p >= 0 } { 194 return [lreplace $l $p $p] 195 } { 196 return $l 197 } 198} 199 200# 201# Given a list of the form {{t1 v1} {t2 v2} ... } 202# return the value from the pair having the tag 'tag'. 203# 204proc assoc {tag l} { 205 set value "" 206 catch { 207 foreach p $l { 208 if {[lindex $p 0] == $tag } { 209 set value [lindex $p 1] 210 break 211 } 212 } 213 } 214 return $value 215} 216 217# 218# Given a list of the form {{a1 b1 ...} {a2 b2 ...} ... } return 219# the value for which l matches the nth (starting at zero) item 220# in a sub-list 221# 222proc assocn {tag n l} { 223 set value {} 224 catch { 225 foreach p $l { 226# puts "testing string equal [lindex $p $n] $tag" 227 if {[string equal [lindex $p $n] $tag]} { 228 set value $p 229 break 230 } 231 } 232 } 233 return $value 234} 235 236proc assocg {tag l} { 237 set value "" 238 catch { 239 foreach p $l { 240 if {[lindex $p 0] == $tag } { 241 set value $p 242 break 243 } 244 } 245 } 246 return $value 247} 248 249proc assocset {tag l newV} { 250 set value "" 251 252 set L {} 253 254 foreach p $l { 255 if {[lindex $p 0] == $tag } { 256 lappend L [list $tag $newV] 257 } else { 258 lappend L $p 259 } 260 } 261 return $L 262} 263 264proc assocsetc {tag l newV} { 265 set value "" 266 267 set L {} 268 set found 0 269 270 foreach p $l { 271 if {[lindex $p 0] == $tag } { 272 lappend L [list $tag $newV] 273 set found 1 274 } else { 275 lappend L $p 276 } 277 } 278 279 if {!$found} { 280 lappend L [list $tag $newV] 281 } 282 283 return $L 284} 285 286############################################################################## 287# 288# Parse an argument list 289# 290proc parseargs {argv nameset args} { 291 set R {} 292 set is_partial 0 293 set index "" 294 295 if {[lsearch $args "-partial"] >= 0} { 296 set is_partial 1 297 } 298 set array [lsearch $args "-array"] 299 if { $array >= 0} { 300 set index [lindex $args [expr $array+1]] 301 } 302 303 while { [llength $argv] > 0 } { 304 305 set sw [lindex $argv 0] 306 307 if { [lsearch -exact $nameset $sw] >= 0 } { 308 set vname [string range $sw 1 end] 309 set val [lindex $argv 1] 310 set argv [lrange $argv 2 end] 311 312 if { $index == "" } { 313 upvar $vname local_$vname 314 } else { 315 upvar ${vname}($index) local_$vname 316 } 317 set local_$vname $val 318 } elseif { $is_partial } { 319 lappend R $sw 320 set argv [lrange $argv 1 end] 321 } else { 322 error "bad option \"$sw\" must be one of: $nameset" 323 return 324 } 325 326 } 327 328 return $R 329} 330 331proc viewFile {label file} { 332 if {[catch { set f [open $file]}]} { 333 errmsg [format [m err.viewfile] $file] 334 return 335 } 336 337 338 set w .vfwin 339 set i 0 340 while { [catch { toplevel $w$i}] } { 341 incr i 342 } 343 set w $w$i 344 345 wm title $w $label 346 347 frame $w.main 348 text $w.main.text -yscrollcommand "$w.main.vb set" -xscrollcommand "$w.main.hb set" 349 scrollbar $w.main.vb -command "$w.main.text yview" 350 scrollbar $w.main.hb -orient horizontal -command "$w.main.text xview" 351 352 grid rowconfigure $w.main 0 -weight 1 353 grid columnconfigure $w.main 0 -weight 1 354 grid $w.main.text -row 0 -column 0 -sticky nsew 355 grid $w.main.vb -row 0 -column 1 -sticky ns 356 grid $w.main.hb -row 1 -column 0 -sticky ew 357 358 button $w.dismiss -text [m b.dismiss] -command "destroy $w" 359 360 pack $w.main -fill both -expand 1 361 pack $w.dismiss -fill x 362 363 catch { 364 $w.main.text insert end [read $f] 365 close $f 366 } 367 $w.main.text configure -state disabled 368} 369 370proc ceil {n} { 371 set n [format %f $n] 372 set d [string first "." $n] 373 if { $d < 0 } { 374 return $n 375 } 376 if { [string trim [string range $n [expr $d+1] end] "0"] == "" } { 377 return [expr [string range $n 0 $d] + 0.0] 378 } else { 379 return [expr [string range $n 0 $d] + 1.0] 380 } 381} 382 383proc floor {n} { 384 set n [format %f $n] 385 set d [string first "." $n] 386 if { $d < 0 } { 387 return $n 388 } 389 return [expr [string range $n 0 $d] + 0.0] 390} 391 392proc min args { 393 if {[llength $args] == 0 } { return 0 } 394 395 set m [lindex $args 0] 396 foreach v $args { 397 if {$v < $m} { set m $v } 398 } 399 return $m 400} 401 402proc max args { 403 if {[llength $args] == 0 } { return 0 } 404 405 set m [lindex $args 0] 406 foreach v $args { 407 if {$v > $m} { set m $v } 408 } 409 return $m 410} 411 412proc vmin {v} { 413 if {[llength $v] == 0} { 414 return "" 415 } 416 417 set M [lindex $v 0] 418 foreach e $v { 419 if { $e < $M } { set M $e } 420 } 421 return $M 422} 423 424proc vmax {v} { 425 if {[llength $v] == 0} { 426 return "" 427 } 428 429 set M [lindex $v 0] 430 foreach e $v { 431 if { $e > $M } { set M $e } 432 } 433 return $M 434} 435 436proc imin {args} { return [vmin $args]} 437proc imax {args} { return [vmax $args]} 438 439 440# 441# Create a labeled grooved frame. 442# 443proc labelframe {w lab args} { 444 frame $w 445 446 set borderwidth [option get $w LabelFrame.borderWidth {}] 447 set relief [option get $w LabelFrame.relief {}] 448 449 parseargs $args {-borderwidth -bd -relief} 450 if {[info exists bd]} {set borderwidth $bd} 451 452 $w configure -bd $borderwidth -relief $relief 453 454# eval "$w configure $args" 455# frame $w.labelframe_pad -height 10 456# pack $w.labelframe_pad 457 label ${w}_label -text $lab 458 place ${w}_label -in $w -x 10 -y -10 459} 460 461# 462# Create a labeled grooved frame with a checkbutton 463# 464proc checkframe {w lab args} { 465 466 frame $w 467 468 set borderwidth [option get $w LabelFrame.borderWidth {}] 469 set relief [option get $w LabelFrame.relief {}] 470 471 set variable "checkframe$w" 472 set command "" 473 parseargs $args {-bd -relief -variable -command} 474 if {[info exists bd]} {set borderwidth $bd} 475 476 $w configure -borderwidth $borderwidth -relief $relief 477 478 checkbutton ${w}_label -text $lab -variable $variable -command $command 479 place ${w}_label -in $w -x 10 -y -10 480} 481 482# 483# Create a labeled grooved frame with a radiobutton 484# 485proc radioframe {w lab args} { 486 frame $w 487 488 set borderwidth [option get $w LabelFrame.borderWidth {}] 489 set relief [option get $w LabelFrame.relief {}] 490 491 set variable "checkframe$w" 492 set value "0" 493 set command "" 494 parseargs $args {-bd -relief -variable -value -command} 495 if {[info exists bd]} {set borderwidth $bd} 496 497 $w configure -borderwidth $borderwidth -relief $relief 498 499 radiobutton ${w}_label -text $lab -variable $variable -value $value -command $command 500 place ${w}_label -in $w -x 10 -y -10 501} 502 503# 504# Create a grooved frame with another window as a label 505# 506proc windowframe {w lw args} { 507 508 frame $w 509 510 set borderwidth [option get $w LabelFrame.borderWidth {}] 511 set relief [option get $w LabelFrame.relief {}] 512 set dy 0 513 parseargs $args {-bd -relief -dy} 514 if {[info exists bd]} {set borderwidth $bd} 515 516 $w configure -borderwidth $borderwidth -relief $relief 517 518 place $lw -in $w -x 10 -y [expr -10 + $dy] 519 raise $lw 520} 521 522# 523# Create an image radiobutton with accompaning text and explaination. 524# 525proc imageRadioButton {w args} { 526 set onimage "" 527 set offimage "" 528 set variable "" 529 set label "" 530 set description "" 531 set value "" 532 set wraplength 200 533 534 parseargs $args {-onimage -offimage -variable -value -label -description -wraplength} 535 536 frame $w 537 radiobutton $w.button -image $offimage -selectimage $onimage -variable $variable -value $value -indicatoron 0 538 label $w.header -text $label -font dialogBigExpFont 539 label $w.details -text $description -justify left -wraplength $wraplength -font dialogExpFont 540 frame $w.pad -width 4 541 542 pack $w.button -side left -anchor nw 543 pack $w.pad -side left 544 pack $w.header -anchor nw 545 pack $w.details -anchor nw -pady 2 546} 547 548# 549# Create an image object from a .gif file name. 550# 551proc gifI {f} { 552 global bd 553 global gifTable 554 555 if { [string index $f 0] != "/" } { 556 set f "$bd/$f" 557 } 558 559 # 560 # Try to get the image from the image table first. If we don't find it, 561 # create the image and save it in the table. 562 # 563 catch { 564 return $gifTable($f) 565 } 566 567 if { [ catch { set gifTable($f) [image create photo -file $f] }]} { 568 set gifTable($f) [image create photo -file "$bd/broken-img.gif" ] 569 } 570 571 return $gifTable($f) 572} 573 574 575# 576# Post the splash window. 577# 578proc start_splash {} { 579 global sd bd splash_start_time tkg_doSplash 580 581 if { ! $tkg_doSplash} { return } 582 583 if {[catch { set splash_start_time [clock clicks -milliseconds] }]} { 584 set splash_start_time "rawdelay" 585 } 586 587 if {[catch { wm state . withdrawn }]} { 588 wm iconify . 589 } 590 591 update 592 593 toplevel .splash -class Splash 594 label .splash.logo -image [gifI "$bd/biggatelogo.gif"] 595 pack .splash.logo 596 wm overrideredirect .splash 1 597 wm transient .splash "" 598 599 set iwidth [image width [.splash.logo cget -image]] 600 set iheight [image height [.splash.logo cget -image]] 601 602 set x [expr ([winfo screenwidth .] - $iwidth)/2 ] 603 set y [expr ([winfo screenheight .] - $iheight)/2 ] 604 wm geometry .splash +${x}+${y} 605 update 606} 607 608# 609# Remove the splash window 610# 611proc end_splash {} { 612 global bd splash_start_time tkg_doSplash tkg_splashWait 613 614 if { ! $tkg_doSplash} { return } 615 616 if { $splash_start_time == "rawdelay" } { 617 set time_to_go 1000 618 } else { 619 set time_to_go [expr $tkg_splashWait - ([clock clicks -milliseconds] - $splash_start_time)] 620 } 621 622 if { $time_to_go < 1 } { set time_to_go 1 } 623 624 after $time_to_go { 625 update 626 destroy .splash 627 wm deiconify . 628 update 629 } 630} 631 632proc yesno {msg} { 633 return [tk_messageBox -default no -type yesno -icon warning -message $msg] 634} 635 636# 637# Respond to a variable change in a flatradiobutton 638# 639proc frb_trace {w v args} { 640 catch { 641 global flatradiobutton_details 642 set variable [assoc variable $flatradiobutton_details($w)] 643 global $variable 644 645 set v [set $variable] 646 647 set bg [assoc bg $flatradiobutton_details($w)] 648 set value [assoc value $flatradiobutton_details($w)] 649 650 if {$v == $value } { 651 $w configure -relief sunken 652 } else { 653 $w configure -relief flat 654 $w configure -bg $bg 655 } 656 } 657} 658 659# 660# Set brackground of flat radio button based on mouseover state 661# 662proc frb_setMouseOverBackground {w ismouseover} { 663 global flatradiobutton_details 664 665 set bg [assoc bg $flatradiobutton_details($w)] 666 set activebackground [assoc activebackground $flatradiobutton_details($w)] 667 set selectcolor [assoc selectcolor $flatradiobutton_details($w)] 668 set value [assoc value $flatradiobutton_details($w)] 669 set variable [assoc variable $flatradiobutton_details($w)] 670 global $variable 671 672 set v [set $variable] 673 674 if { $ismouseover } { 675 if { $v == $value } { 676 $w configure -bg $selectcolor -activebackground $selectcolor -relief raised 677 } else { 678 $w configure -bg $activebackground -activebackground $activebackground -relief raised 679 } 680 } else { 681 if { $v == $value } { 682 $w configure -bg $selectcolor -relief sunken 683 } else { 684 $w configure -bg $bg -relief flat 685 } 686 } 687} 688 689proc frb_seeB1press {w} { 690 global flatradiobutton_details 691 692 set command [assoc command $flatradiobutton_details($w)] 693 set value [assoc value $flatradiobutton_details($w)] 694 set var [assoc variable $flatradiobutton_details($w)] 695 696 global $var 697 set $var $value 698 699 frb_setMouseOverBackground $w 1 700 701 eval $command 702} 703 704# 705# tcl/tk 8.3 and earlier does not support flat radio buttons with "-indicatoron false". 706# This is a limited implementation and only supports the features we need for the mode 707# selectors. 708# 709proc flatradiobutton {w args} { 710 global flatradiobutton_details 711 712 set image "" 713 set variable "" 714 set value "" 715 set command "" 716 set selectcolor "\#aaaacc" 717 set activebackground [option get . FlatRadioButton.activeBackground {}] 718 set bg [option get . FlatRadioButton.background {}] 719 720 parseargs $args {-image -variable -value -command -selectcolor -bg -activebackground} 721 722 723 set flatradiobutton_details($w) {} 724 lappend flatradiobutton_details($w) [list image $image] 725 lappend flatradiobutton_details($w) [list variable $variable] 726 lappend flatradiobutton_details($w) [list value $value] 727 lappend flatradiobutton_details($w) [list command $command] 728 lappend flatradiobutton_details($w) [list selectcolor $selectcolor] 729 lappend flatradiobutton_details($w) [list bg $bg] 730 lappend flatradiobutton_details($w) [list activebackground $activebackground] 731 732 global $variable 733 734 if {[catch {button $w -takefocus 0 -image $image -bd 1 -relief flat -overrelief raised}]} { 735 button $w -takefocus 0 -image $image -bd 1 -relief flat 736 } 737 738 set v [set $variable] 739 if {$v == $value } { 740 $w configure -relief sunken 741 $w configure -bg $selectcolor 742 } else { 743 $w configure -relief flat 744 } 745 746 trace variable $variable w "frb_trace $w" 747 bind $w <Destroy> "trace vdelete $variable w \"frb_trace $w\"" 748 bind $w <ButtonPress-1> "frb_seeB1press $w" 749 750 bind $w <Enter> "+ frb_setMouseOverBackground %W 1" 751 bind $w <Leave> "+ frb_setMouseOverBackground %W 0" 752} 753 754proc paneDecoration {w args} { 755 set orient vertical 756 parseargs $args {-orient} 757 758 if { $orient == "vertical" } { 759 set width 50 760 set height 2 761 } else { 762 set width 2 763 set height 50 764 } 765 766 frame $w.v1 -bd 1 -relief raised -width $width -height $height 767 frame $w.v2 -bd 1 -relief raised -width $width -height $height 768 frame $w.v3 -bd 1 -relief raised -width $width -height $height 769 770 if { $orient == "vertical" } { 771 pack $w.v1 772 pack $w.v2 773 pack $w.v3 774 } else { 775 pack $w.v1 -side left 776 pack $w.v2 -side left 777 pack $w.v3 -side left 778 } 779 780} 781 782proc dialogImage {w args} { 783 global tkg_showDialogImage 784 set fontScale [getFontScale dialogExpFont 10] 785 786 set image "" 787 set caption "" 788 set font dialogCapFont 789 set bd 0 790 set width [rescale [m @opt.sidebar.width]] 791 set height 0 792 set relief flat 793 set explaination "" 794 set labelheight [rescale 50] 795 set imgbd 0 796 set force 0 797 set imgrelief flat 798 set expfont dialogExpFont 799 800 parseargs $args {-image -caption -font -bd -imgbd -imgrelief -width -relief -explaination -labelheight -force -expfont} 801 802 if {!$tkg_showDialogImage && !$force} { 803 frame $w 804 return 805 } 806 807 set iheight [image height $image] 808 set iwidth [image width $image] 809 810 set height [expr $iheight + 100 ] 811 812 frame $w -bd $bd -relief $relief -width $width -height $height 813 814 label $w.cap -text $caption -font $font 815 label $w.img -image $image -bd $imgbd -relief $imgrelief 816 # label $w.exp -text $explaination -justify left -wraplength [expr 155 * $fontScale] -font $expfont 817 label $w.exp -text $explaination -justify left -wraplength [expr $width - 10] -font $expfont 818 819 set x [expr $width/2] 820 set y [expr $labelheight/2] 821 822 place $w.cap -x $x -y $y -anchor center 823 set y [expr $y + $iheight/2 + $labelheight] 824 place $w.img -x $x -y $y -anchor center 825 set y [expr $y + [image height $image]/2 + 30] 826 place $w.exp -x $x -y $y -anchor n 827 828 set bottom [expr [winfo reqheight $w.exp] + $y + 15] 829 830 if { $bottom > $height } { 831 $w configure -height $bottom 832 } 833 834} 835 836# 837# Validate function for bit size selector. All chars must be digits, and there 838# is a 3 char maximum. 839# 840proc bsValidate {w act cur c newv} { 841# puts "bsValidate $w <$act> <$cur> <$c> <$newv>" 842# if {[string length $newv] == 0} { return 0 } 843 if {$act == 1} { 844 if {[string length $cur] > 2} { 845 return 0 846 } 847 return [string is digit $c] 848 } 849 850 return 1 851} 852 853proc bitsizeselector {w args} { 854 855 set entry 1 856 857 parseargs $args {-variable -value -width -entry -takefocus} 858 859 set argv {} 860 if {[info exists variable]} { lappend argv -variable $variable } 861 if {[info exists value]} { lappend argv -value $value } 862 if {[info exists width]} { lappend argv -width $width } 863 if {[info exists entry]} { lappend argv -entry $entry } 864 if {[info exists takefocus]} { lappend argv -takefocus $takefocus } 865 866 eval "Dropbox::new $w $argv -entry $entry -validatecommand bsValidate" 867 for { set i 1} { $i <= 32 } { incr i } { 868 Dropbox::itemadd $w $i 869 } 870} 871 872namespace eval TimeCheck { 873 variable timer 874 875 proc begin {e} { 876 variable timer 877 878 set timer($e) [clock clicks -milliseconds] 879 puts "begin $e" 880 } 881 proc end {e} { 882 variable timer 883 884 set t [clock clicks -milliseconds] 885 set dt [expr ($t - $timer($e) + 0.0)/1000.0] 886 puts "end $e $dt" 887 } 888} 889 890# 891# Fix name so as not to have special characters and make sure it does 892# not conflict with names in l. 893# 894proc unqiueName {name l} { 895 puts "unqiueName $name" 896 return $name 897} 898 899# 900# Setup for hex only entry widgets 901# 902proc hexEntrySetup {} { 903 bind HexEntry <Delete> { continue } 904 bind HexEntry <BackSpace> { continue } 905 bind HexEntry <Control-KeyPress> { continue } 906 bind HexEntry <KeyPress> { 907 set c [string tolower %A] 908 909 if { $c == "" } { continue } 910 911 if { [string first $c "0123456789abcdef"] < 0 } { break } 912 913 914 if {[%W selection present]} { 915 %W delete sel.first sel.last 916 } else { 917 %W delete insert 918 } 919 set L [string length [%W get]] 920 921 if { $L >= 8 } { break } 922 923 # 924 # Temporarily disable the "HexEntry" event handler and send a regular 925 # event to insert the character. 926 # 927 bindtags %W [lrange [bindtags %W] 1 end] 928 event generate %W <KeyPress> -keysym $c 929 bindtags %W [concat [list HexEntry] [bindtags %W]] 930 931 break 932 } 933} 934 935# 936# Setup for number only entry widgets 937# 938proc numEntrySetup {} { 939 bind NumEntry <Delete> { continue } 940 bind NumEntry <BackSpace> { continue } 941 bind NumEntry <Control-KeyPress> { continue } 942 bind NumEntry <KeyPress> { 943 set c [string tolower %A] 944 945 if { $c == "" } { continue } 946 947 if { [string first $c "0123456789"] < 0 } { break } 948 949 if {[%W selection present]} { 950 %W delete sel.first sel.last 951 } else { 952 %W delete insert 953 } 954 set L [string length [%W get]] 955 956 if { $L >= 8 } { break } 957 958 # 959 # Temporarily disable the "NumEntry" event handler and send a regular 960 # event to insert the character. 961 # 962 bindtags %W [lrange [bindtags %W] 1 end] 963 event generate %W <KeyPress> -keysym $c 964 bindtags %W [concat [list NumEntry] [bindtags %W]] 965 966 break 967 } 968} 969 970 971# 972# Setup for number only entry widgets 973# 974proc floatEntrySetup {} { 975 bind FloatEntry <Delete> { continue } 976 bind FloatEntry <BackSpace> { continue } 977 bind FloatEntry <Control-KeyPress> { continue } 978 bind FloatEntry <KeyPress> { 979 set c [string tolower %A] 980 981 if { $c == "" } { continue } 982 983 if { [string first $c "0123456789."] < 0 } { break } 984 985 if {[%W selection present]} { 986 %W delete sel.first sel.last 987 } else { 988 %W delete insert 989 } 990 set L [string length [%W get]] 991 992 if { $L >= 8 } { break } 993 994 # 995 # Temporarily disable the "FloatEntry" event handler and send a regular 996 # event to insert the character. 997 # 998 bindtags %W [lrange [bindtags %W] 1 end] 999 if { $c == "." } { set c period } 1000 event generate %W <KeyPress> -keysym $c 1001 bindtags %W [concat [list FloatEntry] [bindtags %W]] 1002 1003 break 1004 } 1005} 1006 1007############################################################################# 1008# 1009# Helping function for shellWindow. 1010# 1011############################################################################# 1012proc shellExec {args} { 1013 global shellCommand 1014 1015 set w .shell_win 1016 1017 $w.text insert end "${shellCommand}\n" cmd 1018 $w.text tag configure cmd -foreground blue 1019 1020 if {[catch { set result [namespace eval :: "$shellCommand"] } err]} { 1021 $w.text insert end "${err}\n" err 1022 $w.text tag configure err -foreground red 1023 } else { 1024 $w.text insert end "${result}\n" result 1025 $w.text tag configure result -foreground black 1026 } 1027 1028 $w.text see end 1029 1030 set shellCommand "" 1031} 1032 1033############################################################################# 1034# 1035# Create a shell window in which we can type an execute tcl commands for 1036# debugging purposes. 1037# 1038############################################################################# 1039proc shellWindow {} { 1040 set w .shell_win 1041 1042 if {[catch {toplevel $w}]} { 1043 raise $w 1044 return 1045 } 1046 1047 wm title $w "TKGate: Tcl Shell" 1048 1049 button $w.dismiss -text Dismiss -command "destroy $w" 1050 pack $w.dismiss -side bottom -anchor e -padx 5 -pady 5 1051 1052 frame $w.b 1053 pack $w.b -side bottom -fill x -expand 1 1054 1055 label $w.b.l -text "Command: " 1056 pack $w.b.l -side left -padx 5 -pady 5 1057 1058 entry $w.b.e -textvariable shellCommand 1059 pack $w.b.e -fill x -padx 5 -pady 5 -expand 1 1060 1061 bind $w.b.e <Return> shellExec 1062 1063 focus $w.b.e 1064 1065 text $w.text -bd 2 -relief sunken -width 60 -height 20 -yscrollcommand "$w.vb set" 1066 pack $w.text -padx 5 -pady 5 -fill both -expand 1 -side left 1067 1068 scrollbar $w.vb -orient vertical -command "$w.text yview" 1069 pack $w.vb -side right -padx 5 -pady 5 -fill y -expand 1 1070} 1071 1072############################################################################# 1073# 1074# Perform a standard wait for a dialog box. We update all events, set 1075# a grab on the dialog box and wait for the dialog box to be destroyed. 1076# We then release the grab and call gat_syncInterface to cause any 1077# internal circuit changes to be synchronized with tcl/tk elements. 1078# 1079############################################################################# 1080set dialogWaitStack {} 1081proc dialogWait {w args} { 1082 global dialogWaitStack 1083 set dosync 1 1084 1085 parseargs $args {-dosync} 1086 1087 # 1088 # Put window on stack 1089 # 1090 lappend dialogWaitStack $w 1091 1092 update 1093 grab set $w 1094 1095 tkwait window $w 1096 1097 if {[llength $dialogWaitStack] > 1 } { 1098 set dialogWaitStack [lrange $dialogWaitStack 0 end-1] 1099 set lastW [lindex $dialogWaitStack [expr [llength $dialogWaitStack]-1]] 1100 catch { grab release $w } 1101 grab set $lastW 1102 } else { 1103 catch { grab release $w } 1104 set dialogWaitStack {} 1105 } 1106 1107 if {$dosync} { 1108 gat_syncInterface 1109 } 1110} 1111 1112############################################################################# 1113# 1114# Return the top-level window that w is contained in. 1115# 1116proc gettoplevel {w} { 1117 while {1} { 1118 set pw [winfo parent $w] 1119 if { $pw == "" || $pw == "."} break 1120 set w $pw 1121 } 1122 return $w 1123} 1124 1125############################################################################# 1126# 1127# If a number is prepended with a '*', scale it by the current font scale. 1128# 1129proc rescale {n} { 1130 if {[string index $n 0] == "*"} { 1131 return [expr int([getFontScale dialogExpFont 13] * [string range $n 1 end])] 1132 } 1133 1134 return $n 1135} 1136 1137############################################################################# 1138# 1139# Return non-zero if $c is a character from a word ( alphanumeric or "_"). 1140# 1141proc iswordchar {c} { 1142 if { [string is alnum $c] || $c == "_" } { 1143 return 1 1144 } 1145 return 0 1146} 1147 1148############################################################################# 1149# 1150# Return non-zero if $c is a character from a word including task names ( alphanumeric, "_" or "$"). 1151# 1152proc istaskwordchar {c} { 1153 if { [string is alnum $c] || $c == "_" || $c == "\$" } { 1154 return 1 1155 } 1156 return 0 1157} 1158 1159############################################################################# 1160# 1161# Find the position of the first occurance of $word in $line with the 1162# restriction that $word must be surrounded by non-word characters or at the 1163# start or end of a line. Returns -1 if $word is not found 1164# 1165proc findword {line word} { 1166 set llen [string length $line] 1167 set wlen [string length $word] 1168 set p 0 1169 while {[set p [string first $word [string range $line $p end]]] >= 0 } { 1170 if { ($p == 0 || ! [iswordchar [string index $line [expr $p - 1 ]]]) \ 1171 && ($p+$wlen >= $llen || ! [iswordchar [string index $line [expr $p + $wlen ]]]) } { 1172 break 1173 } 1174 } 1175 1176 return $p 1177} 1178 1179 1180proc lpop {_l} { 1181 upvar $_l l 1182 1183 set l [lrange $l 0 [expr [llength $l] - 2]] 1184} 1185 1186proc lscan {l args} { 1187 set i 0 1188 1189 foreach v $args { 1190 upvar $v _v$i 1191 1192 set _v$i [lindex $l $i] 1193 incr i 1194 } 1195} 1196 1197proc llast {l} { 1198 set n [llength $l] 1199 if {$n > 0} { 1200 return [lindex $l [expr $n - 1]] 1201 } else { 1202 return "" 1203 } 1204} 1205 1206proc makeFriendlyChar {c} { 1207 if {[string is graph $c] || $c == " " } { return $c } 1208 set n 0 1209 binary scan $c c n 1210 1211 return \\[format %03o $n] 1212} 1213 1214proc findLibraryFile {name} { 1215 global tkg_simVLibPath 1216 1217 foreach directory $tkg_simVLibPath { 1218 set directory [namespace eval :: "eval concat $directory"] 1219 if {[file exists $directory/$name]} { 1220 return $directory/$name 1221 } 1222 if {[file exists $directory/$name.v]} { 1223 return $directory/$name.v 1224 } 1225 } 1226 1227 return "" 1228} 1229 1230proc encodeBits {b value} { 1231 set n [llength $value] 1232 1233 set out 0 1234 for {set i 0} {$i < $n} {incr i} { 1235 if {[lindex $value $i]} { 1236 set out [expr $out | (1 << $i)] 1237 } 1238 } 1239 return $out 1240} 1241 1242proc validate_hex {s} { 1243 if {[scan $s %x n] != 1} { 1244 set n 0 1245 } 1246 return $n 1247} 1248 1249proc validate_posint {s} { 1250 if {[scan $s %d n] != 1 || $n < 1} { 1251 set n 1 1252 } 1253 return $n 1254} 1255 1256proc validate_nonnegint {s} { 1257 if {[scan $s %d n] != 1 || $n < 0} { 1258 set n 0 1259 } 1260 return $n 1261} 1262 1263proc validate_int {s} { 1264 if {[scan $s %d n] != 1} { 1265 set n 0 1266 } 1267 return $n 1268} 1269 1270# 1271# Create a basic toolbar button 1272# 1273proc toolbutton {w img act help args} { 1274 set state normal 1275 1276 parseargs $args {-state} 1277 1278 if {[catch {button $w -image [gifI $img] -takefocus 0 -relief flat -command $act -overrelief raised -state $state}]} { 1279 button $w -image [gifI $img] -takefocus 0 -relief flat -command $act -state $state 1280 } 1281 1282 if { $help != ""} { 1283 helpon $w [m $help] 1284 } 1285} 1286 1287# 1288# Validate function for bit size selector. All chars must be digits, and there 1289# is a 3 char maximum. 1290# 1291proc hexValidate {w act cur c newv} { 1292 if {$act == 1} { 1293 return [string is xdigit $c] 1294 } 1295 1296 return 1 1297} 1298 1299proc _incdecDelta {varName args} { 1300 upvar \#0 $varName v 1301 1302 set min 0 1303 set max 2147483648 1304 set format %f 1305 set delta 1 1306 parseargs $args {-delta -min -max -format} 1307 1308 scan $v $format n 1309 1310 set newValue [expr $n + $delta] 1311 1312 if { $newValue < $min } { set newValue $min } 1313 if { $newValue > $max } { set newValue $max } 1314 set v [format $format $newValue] 1315} 1316 1317proc incdecEntry {w args} { 1318 frame $w 1319 1320 entry $w.e 1321 1322 set class "" 1323 set variable "" 1324 set min 0 1325 set max 1e20 1326 set width 8 1327 set format %f 1328 set justify right 1329 set validatecommand "" 1330 set font [$w.e cget -font] 1331 set delta 1 1332 parseargs $args {-variable -width -min -max -class -delta -format -justify -validatecommand -font} 1333 1334 if { $validatecommand != "" } { 1335 $w.e configure -bg white -width $width -textvariable $variable -justify $justify \ 1336 -validate key -validatecommand "$validatecommand %W %d %s %S %P" \ 1337 -invalidcommand bell -font $font 1338 } else { 1339 $w.e configure -bg white -width $width -textvariable $variable -justify $justify -font $font 1340 } 1341 button $w.up -image [gifI up.gif] -command "_incdecDelta $variable -delta $delta -max $max -min $min -format $format" 1342 button $w.dn -image [gifI down.gif] -command "_incdecDelta $variable -delta [expr -$delta] -max $max -min $min -format $format" 1343 1344 if { $class != "" } { 1345 bindtags $w.e [concat [list $class] [bindtags $w.e]] 1346 } 1347 1348 pack $w.e -side left 1349 pack $w.up -side top -fill y -expand 1 1350 pack $w.dn -side bottom -fill y -expand 1 1351} 1352 1353proc replaceSwitchValue {cmd sname value} { 1354 set i [lsearch $cmd $sname] 1355 if {$i < 0} return $cmd 1356 incr i 1357 return [lreplace $cmd $i $i $value] 1358} 1359 1360proc incdecEntry_configure {w args} { 1361 parseargs $args {-min -max -delta} 1362 1363 set upcommand [$w.up cget -command] 1364 set dncommand [$w.dn cget -command] 1365 1366 if {[info exists min]} { 1367 set upcommand [replaceSwitchValue $upcommand -min $min] 1368 set dncommand [replaceSwitchValue $dncommand -min $min] 1369 } 1370 if {[info exists max]} { 1371 set upcommand [replaceSwitchValue $upcommand -max $max] 1372 set dncommand [replaceSwitchValue $dncommand -max $max] 1373 } 1374 if {[info exists delta]} { 1375 set upcommand [replaceSwitchValue $upcommand -delta $delta] 1376 set dncommand [replaceSwitchValue $dncommand -delta [expr -$delta]] 1377 } 1378 1379 $w.up configure -command $upcommand 1380 $w.dn configure -command $dncommand 1381} 1382 1383proc chooseInterval {D} { 1384 1385 set G [expr exp(int(log($D)/log(10.0)+0.999999999)*log(10.0))] 1386 set Q [expr ($G-$D)/$G ] 1387 1388 if {$Q >= 0.8} { return [expr $G*0.02 ] } 1389 1390 if {$Q >= 0.6} { return [expr $G*0.05 ] } 1391 1392 return [expr $G*0.1 ] 1393} 1394 1395# 1396# add pads on the top and botton of a window packed with "pack" 1397# 1398proc packPad {w args} { 1399 1400 set toppad 10 1401 set bottompad 10 1402 1403 parseargs $args {-pad -toppad -bottompad} 1404 if {[info exists pad]} { 1405 set toppad $pad 1406 set bottompad $pad 1407 } 1408 1409 frame $w.pad_top -height [rescale *$toppad] 1410 frame $w.pad_bottom -height [rescale *$bottompad] 1411 pack $w.pad_top -side top 1412 pack $w.pad_bottom -side bottom 1413} 1414 1415proc linkVars_change {v1 v2 n args} { 1416 global linkVars_assoc 1417 upvar \#0 $v1 _v1 1418 upvar \#0 $v2 _v2 1419 1420 set assoc $linkVars_assoc($v1:$v2) 1421 1422 if {$n == 1} { 1423 set p [assocn $_v1 0 $assoc] 1424 set new_v2 [lindex $p 1] 1425# puts "$v1 changed to $_v1, $v2 will become $new_v2" 1426 if { $new_v2 != $_v2 } { 1427 set _v2 $new_v2 1428 } 1429 } else { 1430 set p [assocn $_v2 1 $assoc] 1431 set new_v1 [lindex $p 0] 1432# puts "$v2 changed to $_v2, $v1 will become $new_v1" 1433 if { $new_v1 != $_v1 } { 1434 set _v1 $new_v1 1435 } 1436 } 1437} 1438 1439############################################################################# 1440# 1441# Link values of v1 and v2 with an association list. When one variable 1442# changes, the other will change to reflect corresponding value in the 1443# association list. 1444# 1445proc linkVars {v1 v2 assoc} { 1446 global linkVars_assoc 1447 upvar \#0 $v1 _v1 1448 upvar \#0 $v2 _v2 1449 1450 set linkVars_assoc($v1:$v2) $assoc 1451 trace variable _v1 w "linkVars_change $v1 $v2 1" 1452 trace variable _v2 w "linkVars_change $v1 $v2 2" 1453} 1454 1455