1#---------------------------------------------------------------------------- 2# PLPLOT TK/TCL graphics renderer support procs 3# Maurice LeBrun 4# 1-Jul-1993 5# IFS, University of Texas at Austin 6# 7# Includes code borrowed from the TCL/TK widget demo. 8#---------------------------------------------------------------------------- 9 10#---------------------------------------------------------------------------- 11# plstdwin 12# 13# Does "standard" startup for a plframe-containing main window. 14# Use it or roll your own, but note: this may change in future versions. 15#---------------------------------------------------------------------------- 16 17proc plstdwin {w} { 18 global plstdwin_skip_startup 19 20# Only do global initialization once. 21 22 if { ! [info exists plstdwin_skip_startup]} { 23 24 # Set up configuration options. 25 # The first is to hold default values of everything, the second is for 26 # user customization. See pldefaults.tcl for more info. 27 28 pldefaults 29 plconfig 30 31 set plstdwin_skip_startup 1 32 } 33 34# Set min/max window sizes. 35 36 set root_width [winfo vrootwidth .] 37 set root_height [winfo vrootheight .] 38 39 wm minsize $w 300 240 40 wm maxsize $w [expr "$root_width/64*63"] [expr "$root_height/64*62"] 41 42# Set window geometry defaults. Try to get value from: 43# - option database, from app-defaults file 44# - global geometry var, from plconfig.tcl (legacy way) 45# - automatic: specified fraction of root window 46# 47# Typically we depart from the usual 4/3 ratio somewhat to account for the 48# menu bar. 49 50 global geometry 51 if [info exists geometry] { 52 set w_geom $geometry 53 } else { 54 set w_geom [option get $w geometry {}] 55 if { $w_geom == "auto" } { 56 set width [expr "$root_width / 16 * 10"] 57 set height [expr "$root_height / 16 * 11"] 58 set w_geom ${width}x${height} 59 } 60 } 61 if { $w_geom != "" } { 62 wm geometry $w $w_geom 63 } 64} 65 66#---------------------------------------------------------------------------- 67# null_command 68# 69# Invokes a dialog explaining that the real binding isn't written yet. 70#---------------------------------------------------------------------------- 71 72proc null_command {cmd_name} { 73 set dialog_args "-text {Command \"$cmd_name\" not yet implemented.} \ 74 -aspect 500 -justify left" 75 mkDialog .null $dialog_args {OK {}} 76 tkwait visibility .null 77 grab .null 78 tkwait window .null 79} 80 81#---------------------------------------------------------------------------- 82# bogue_out 83# 84# Invokes a dialog explaining that the user bogued out (messed up, blew 85# it, puked on the system console, etc). 86#---------------------------------------------------------------------------- 87 88proc bogue_out {msg} { 89 set dialog_args "-text \"$msg\" -aspect 800 -justify left" 90 mkDialog .bogus $dialog_args {OK {}} 91 tkwait visibility .bogus 92 grab .bogus 93 focus .bogus 94 tkwait window .bogus 95} 96 97#---------------------------------------------------------------------------- 98# dpos w 99# 100# Position a dialog box at a reasonable place on the screen. 101#---------------------------------------------------------------------------- 102 103proc dpos w { 104 set offx [expr "[winfo rootx .]+100"] 105 set offy [expr "[winfo rooty .]+100"] 106 wm geometry $w +$offx+$offy 107} 108 109#---------------------------------------------------------------------------- 110# normal_text_setup 111# 112# Sets up text widgets the way I like them. 113#---------------------------------------------------------------------------- 114 115proc normal_text_setup {w {width 60} {height 30}} { 116 global dialog_font dialog_bold_font 117 118 button $w.ok -text OK -command "destroy $w" 119 text $w.t -relief raised -bd 2 -yscrollcommand "$w.s set" -setgrid true \ 120 -width $width -height $height 121 scrollbar $w.s -relief flat -command "text_scroll $w.t" 122 pack append $w $w.ok {bottom fillx} $w.s {right filly} $w.t {expand fill} 123 focus $w.t 124 125# Set up display styles 126 127 $w.t tag configure normal -font $dialog_font 128 $w.t tag configure bold -font $dialog_bold_font 129 130 if {[winfo depth $w] == 1} { 131 $w.t tag configure color1 -background black -foreground white 132 $w.t tag configure color2 -background black -foreground white 133 $w.t tag configure raised -background white -relief raised \ 134 -borderwidth 1 135 $w.t tag configure sunken -background white -relief sunken \ 136 -borderwidth 1 137 } else { 138 $w.t tag configure color1 -background "#eed5b7" 139 $w.t tag configure color2 -foreground red 140 $w.t tag configure raised -background "#eed5b7" -relief raised \ 141 -borderwidth 1 142 $w.t tag configure sunken -background "#eed5b7" -relief sunken \ 143 -borderwidth 1 144 } 145 $w.t tag configure bgstipple -background black -borderwidth 0 \ 146 -bgstipple gray25 147 $w.t tag configure fgstipple -fgstipple gray50 148 $w.t tag configure underline -underline on 149 150# Set up bindings to be as useful as possible. 151 152 bind $w <Any-Enter> "focus $w.t" 153 154 bind $w.t <Return> "destroy $w" 155 156 bind $w.t <Down> "text_scroll_by_line $w.t + 1" 157 bind $w.t <Up> "text_scroll_by_line $w.t - 1" 158 159 bind $w.t <Next> "text_scroll_by_page $w.t + 1" 160 bind $w.t <space> "text_scroll_by_page $w.t + 1" 161 162 bind $w.t <Prior> "text_scroll_by_page $w.t - 1" 163 bind $w.t <BackSpace> "text_scroll_by_page $w.t - 1" 164 bind $w.t <Delete> "text_scroll_by_page $w.t - 1" 165} 166 167#---------------------------------------------------------------------------- 168# text_scroll 169# 170# Scrolls text widget vertically, updating various things 171#---------------------------------------------------------------------------- 172 173proc text_scroll {w line args} { 174 eval [list $w yview $line] $args 175 $w mark set insert [$w index @0,0] 176} 177 178#---------------------------------------------------------------------------- 179# text_scroll_by_line 180# 181# Scrolls text widget vertically by the given number of lines. 182#---------------------------------------------------------------------------- 183 184proc text_scroll_by_line {w sign delta} { 185 text_scroll $w [$w index "@0,0 $sign $delta lines"] 186} 187 188#---------------------------------------------------------------------------- 189# text_scroll_by_page 190# 191# Scrolls text widget vertically by the given number of pages (almost). 192#---------------------------------------------------------------------------- 193 194proc text_scroll_by_page {w sign delta} { 195 set height [lindex [$w config -height] 4] 196 set delta [expr $delta*($height-2)] 197 text_scroll $w [$w index "@0,0 $sign $delta lines"] 198} 199 200#---------------------------------------------------------------------------- 201# The procedure below inserts text into a given text widget and 202# applies one or more tags to that text. The arguments are: 203# 204# w Window in which to insert 205# text Text to insert (it's inserted at the "insert" mark) 206# args One or more tags to apply to text. If this is empty 207# then all tags are removed from the text. 208#---------------------------------------------------------------------------- 209 210proc insertWithTags {w text args} { 211 set start [$w index insert] 212 $w insert insert $text 213 foreach tag [$w tag names $start] { 214 $w tag remove $tag $start insert 215 } 216 foreach i $args { 217 $w tag add $i $start insert 218 } 219} 220 221#---------------------------------------------------------------------------- 222# Numeric utility procs: 223# 224# min returns minimum argument 225# max returns maximum argument 226# 227# Taken from utils.tcl by Tom Phelps (phelps@cs.Berkeley.EDU) 228#---------------------------------------------------------------------------- 229 230proc min {args} { 231 set x [lindex $args 0] 232 foreach i $args { 233 if {$i<$x} {set x $i} 234 } 235 return $x 236} 237 238proc max {args} { 239 set x [lindex $args 0] 240 foreach i $args { 241 if {$i>$x} {set x $i} 242 } 243 return $x 244} 245 246#---------------------------------------------------------------------------- 247# fileSelect 248# 249# Puts up a file selector. Uses iWidgets 3.0 File selector if available, 250# otherwise just getItem. 251# 252# I have to go through a bit of trickery to get "~" expanded, since the 253# Tcl glob doesn't expand it if the file doesn't already exist. 254#---------------------------------------------------------------------------- 255 256proc fileSelect {{filter {}}} { 257 global pl_iwidgets_package_name 258 259 # Use the Iwidgets file selector if available 260 if ![catch {eval package require $pl_iwidgets_package_name}] { 261 if {![winfo exist .fs]} { 262 iwidgets::fileselectiondialog .fs -modality application 263 } 264 265 if {$filter > ""} { 266 .fs configure -mask $filter 267 .fs filter 268 } 269 270 if {[.fs activate]} { 271 set file [.fs get] 272 } else { 273 set file "" 274 } 275 276 .fs deactivate 277 278 } else { 279 set file [getItem "Enter file name"] 280 } 281 282 if { [string index $file 0] == "~" } { 283 set file [glob ~][string trimleft $file ~] 284 } 285 286 return $file 287} 288 289#---------------------------------------------------------------------------- 290# getSaveFile 291# 292# Puts up a file selector for save file. 293#---------------------------------------------------------------------------- 294 295proc getSaveFile {devkey} { 296 297 set filter "*" 298 299 # Map device name to filter suffix. 300 # Add to this as desired. 301 switch "$devkey" \ 302 "ps" "set filter *.ps" \ 303 "psc" "set filter *.ps" \ 304 "plmeta" "set filter *.plm" \ 305 "xfig" "set filter *.fig" 306 307 return [fileSelect $filter] 308} 309 310#---------------------------------------------------------------------------- 311# getPaletteFile 312# 313# Puts up a file selector for a palette file. 314#---------------------------------------------------------------------------- 315 316proc getPaletteFile {} { 317 318 return [fileSelect *.pal] 319} 320 321#---------------------------------------------------------------------------- 322# getItem 323# 324# Asks user to input something, returning the result. 325# Selecting "Cancel" returns the empty string. 326#---------------------------------------------------------------------------- 327 328proc getItem {item} { 329 global dialog_font dialog_bold_font 330 global itemval 331 332 set w .entry 333 set itemval "" 334 335 catch {destroy $w} 336 toplevel $w 337 dpos $w 338 wm title $w "Entry" 339 wm iconname $w "Entry" 340 message $w.msg -font $dialog_font -aspect 800 -text $item 341 342 frame $w.frame -borderwidth 10 343 pack append $w.frame \ 344 [entry $w.frame.e1 -relief sunken] {top pady 10 fillx} 345 346 button $w.ok -text OK -command \ 347 "set itemval \[$w.frame.e1 get\]; destroy $w" 348 button $w.cancel -text Cancel -command "destroy $w" 349 350 bind $w.frame.e1 <Return> \ 351 "set itemval \[$w.frame.e1 get\]; destroy $w" 352 353 pack append $w $w.msg {top fill} $w.frame {top expand fill} \ 354 $w.ok {left expand fill} $w.cancel {left expand fill} 355 356 tkwait visibility $w 357 grab $w 358 focus $w.frame.e1 359 tkwait window $w 360 return $itemval 361} 362 363#---------------------------------------------------------------------------- 364# confirm 365# 366# Sure about that, buddy? 367#---------------------------------------------------------------------------- 368 369proc confirm {msg} { 370 global confirm_flag 371 set dialog_args "-text {$msg} \ 372 -aspect 500 -justify left" 373 mkDialog .confirm $dialog_args \ 374 "OK {set confirm_flag 1}" "Cancel {set confirm_flag 0}" 375 tkwait visibility .confirm 376 grab .confirm 377 focus .confirm 378 tkwait window .confirm 379 return $confirm_flag 380} 381 382#---------------------------------------------------------------------------- 383# mkDialog w msgArgs list list ... 384# 385# Create a dialog box with a message and any number of buttons at 386# the bottom. 387# 388# Arguments: 389# w - Name to use for new top-level window. 390# msgArgs - List of arguments to use when creating the message of the 391# dialog box (e.g. text, justifcation, etc.) 392# list - A two-element list that describes one of the buttons that 393# will appear at the bottom of the dialog. The first element 394# gives the text to be displayed in the button and the second 395# gives the command to be invoked when the button is invoked. 396#---------------------------------------------------------------------------- 397 398proc mkDialog {w msgArgs args} { 399 catch {destroy $w} 400 toplevel $w -class Dialog 401 dpos $w 402 wm title $w "Dialog box" 403 wm iconname $w "Dialog" 404 405# Create two frames in the main window. The top frame will hold the message 406# and the bottom one will hold the buttons. Arrange them one above the 407# other, with any extra vertical space split between them. 408 409 frame $w.top -relief raised -border 1 410 frame $w.bot -relief raised -border 1 411 pack append $w $w.top {top fill expand} $w.bot {top fill expand} 412 413# Create the message widget and arrange for it to be centered in the top 414# frame. 415 416 eval message $w.top.msg -justify center $msgArgs 417 pack append $w.top $w.top.msg {top expand padx 10 pady 10} 418 419# Create as many buttons as needed and arrange them from left to right in 420# the bottom frame. Embed the left button in an additional sunken frame to 421# indicate that it is the default button, and arrange for that button to be 422# invoked as the default action for clicks and returns in the dialog. 423 424 if {[llength $args] > 0} { 425 set arg [lindex $args 0] 426 frame $w.bot.0 -relief sunken -border 1 427 pack append $w.bot $w.bot.0 {left expand padx 20 pady 20} 428 button $w.bot.0.button -text [lindex $arg 0] \ 429 -command "[lindex $arg 1]; destroy $w" 430 pack append $w.bot.0 $w.bot.0.button {expand padx 12 pady 12} 431 bind $w <Return> "[lindex $arg 1]; destroy $w" 432 focus $w 433 434 set i 1 435 foreach arg [lrange $args 1 end] { 436 button $w.bot.$i -text [lindex $arg 0] \ 437 -command "[lindex $arg 1]; destroy $w" 438 pack append $w.bot $w.bot.$i {left expand padx 20} 439 set i [expr $i+1] 440 } 441 } 442 bind $w <Any-Enter> [list focus $w] 443 focus $w 444} 445 446#---------------------------------------------------------------------------- 447# Form2d 448# 449# Create a top-level window that displays a bunch of entries used for 450# entering window coordinates. 451# 452# Arguments: 453# w Name of top level window 454# desc Short description of coordinates to be entered. 455# 456# Global variables referenced: 457# fv00 fn00 458# fv01 fn01 459# fv10 fn10 460# fv11 fn11 461# 462# The global variables are modified by the entry widgets and may be 463# overwritten at any time so the caller must wait for the dialog to be 464# destroyed and then use them immediately. 465#---------------------------------------------------------------------------- 466 467proc Form2d {w desc} { 468 global dialog_font dialog_bold_font 469 global tabList 470 global fv00 fv01 fv10 fv11 471 global fn00 fn01 fn10 fn11 472 473 catch {destroy $w} 474 toplevel $w 475 dpos $w 476 477 wm title $w "Entry window" 478 wm iconname $w "Entry" 479 480 message $w.msg \ 481 -font $dialog_font \ 482 -aspect 700 \ 483 -text "$desc Click \"OK\" button when finished." 484 485 pack append $w \ 486 $w.msg {top fill} 487 488 set rows {0 1} 489 set cols {0 1} 490 set tabList "" 491 492 foreach i $rows { 493 frame $w.$i 494 495 foreach j $cols { 496 set name [set fn$i$j] 497 set value [set fv$i$j] 498 frame $w.$i.$j -bd 1m 499 500 entry $w.$i.$j.entry -relief sunken -width 10 501 $w.$i.$j.entry insert 0 $value 502 bind $w.$i.$j.entry <Tab> "Form2d_tab \$tabList" 503 bind $w.$i.$j.entry <Return> "Form2d_destroy $w" 504 set tabList [concat $tabList $w.$i.$j.entry] 505 506 label $w.$i.$j.label -width 10 507 $w.$i.$j.label config -text "$name:" 508 509 pack append $w.$i.$j \ 510 $w.$i.$j.entry right \ 511 $w.$i.$j.label left 512 513 pack append $w.$i \ 514 $w.$i.$j {left fillx} 515 } 516 517 pack append $w \ 518 $w.$i {top fillx} 519 } 520 521 button $w.ok -text OK -command "Form2d_destroy $w" 522 pack append $w \ 523 $w.ok {bottom fill} 524 525 tkwait visibility $w 526 grab $w 527 focus $w.0.0.entry 528} 529 530# This procedure is invoked when the top level entry dialog is destroyed. 531# It updates the global vars used to communicate the entry values then 532# destroys the window. 533 534proc Form2d_destroy {w} { 535 global fv00 fv01 fv10 fv11 536 537 set fv00 [$w.0.0.entry get] 538 set fv01 [$w.0.1.entry get] 539 set fv10 [$w.1.0.entry get] 540 set fv11 [$w.1.1.entry get] 541 542 destroy $w 543} 544 545# The procedure below is invoked in response to tabs in the entry 546# windows. It moves the focus to the next window in the tab list. 547# Arguments: 548# 549# list - Ordered list of windows to receive focus 550 551proc Form2d_tab {list} { 552 set i [lsearch $list [focus]] 553 if {$i < 0} { 554 set i 0 555 } else { 556 incr i 557 if {$i >= [llength $list]} { 558 set i 0 559 } 560 } 561 focus [lindex $list $i] 562} 563 564#---------------------------------------------------------------------------- 565# evalCmd w 566# 567# Create a top-level window containing a text widget that allows you 568# to enter a TCL command and have it executed. 569# 570# Arguments: 571# w - Name to use for new top-level window. 572#---------------------------------------------------------------------------- 573 574proc evalCmd {{w .eval}} { 575 catch {destroy $w} 576# -geometry unknown in 7.6 toplevels: toplevel $w -geometry 400x300 577 toplevel $w 578 wm geometry $w 400x300 579 dpos $w 580 wm title $w "Interpret command" 581 wm iconname $w "Interpret" 582 583 frame $w.cmd 584 label $w.cmd.label -text "Command:" -width 13 -anchor w 585 entry $w.cmd.entry -width 40 -relief sunken -bd 2 -textvariable command 586 button $w.cmd.button -text "Execute" \ 587 -command "eval \$command" 588 pack append $w.cmd $w.cmd.label left $w.cmd.entry left \ 589 $w.cmd.button {left pady 10 padx 20} 590 bind $w.cmd.entry <Return> "eval \$command" 591 592 text $w.t -relief raised -bd 2 -setgrid true 593 $w.t insert 0.0 {\ 594Type TCL command to be executed in the window above, then type <Return> 595or click on "Execute". 596} 597 $w.t mark set insert 0.0 598 bind $w <Any-Enter> "focus $w.cmd.entry" 599 600 button $w.ok -text OK -command "destroy $w" 601 602 pack append $w $w.cmd {top fill} \ 603 $w.ok {bottom fillx} $w.t {expand fill} 604} 605 606#---------------------------------------------------------------------------- 607# Used to get rid of sections of code during development. 608#---------------------------------------------------------------------------- 609 610proc ignore { args } {} 611 612#------------------------------------------------------------------------------ 613# Proc to set up debug bindings. 614#------------------------------------------------------------------------------ 615 616proc dbug_bind {w} { 617 618bind $w <Any-ButtonPress> {puts stderr "Widget event: ButtonPress"} 619bind $w <Any-ButtonRelease> {puts stderr "Widget event: ButtonRelease"} 620bind $w <Any-Circulate> {puts stderr "Widget event: Circulate"} 621bind $w <Any-CirculateRequest> {puts stderr "Widget event: CirculateRequest"} 622bind $w <Any-Colormap> {puts stderr "Widget event: Colormap"} 623bind $w <Any-Configure> {puts stderr "Widget event: Configure"} 624bind $w <Any-ConfigureRequest> {puts stderr "Widget event: ConfigureRequest"} 625bind $w <Any-Destroy> {puts stderr "Widget event: Destroy"} 626bind $w <Any-Enter> {puts stderr "Widget event: Enter"} 627bind $w <Any-Expose> {puts stderr "Widget event: Expose"} 628bind $w <Any-FocusIn> {puts stderr "Widget event: FocusIn"} 629bind $w <Any-FocusOut> {puts stderr "Widget event: FocusOut"} 630bind $w <Any-Gravity> {puts stderr "Widget event: Gravity"} 631bind $w <Any-Keymap> {puts stderr "Widget event: Keymap"} 632bind $w <Any-KeyPress> {puts stderr "Widget event: KeyPress"} 633bind $w <Any-KeyRelease> {puts stderr "Widget event: KeyRelease"} 634bind $w <Any-Leave> {puts stderr "Widget event: Leave"} 635bind $w <Any-Map> {puts stderr "Widget event: Map"} 636bind $w <Any-MapRequest> {puts stderr "Widget event: MapRequest"} 637#bind $w <Any-Motion> {puts stderr "Widget event: Motion"} 638bind $w <Any-Property> {puts stderr "Widget event: Property"} 639bind $w <Any-Reparent> {puts stderr "Widget event: Reparent"} 640bind $w <Any-ResizeRequest> {puts stderr "Widget event: ResizeRequest"} 641bind $w <Any-Unmap> {puts stderr "Widget event: Unmap"} 642bind $w <Any-Visibility> {puts stderr "Widget event: Visibility"} 643 644} 645