1
# $Id: pltools.tcl 8312 2008-03-22 16:23:58Z mlebrun $
3
#----------------------------------------------------------------------------
4
# PLPLOT TK/TCL graphics renderer support procs
7
# IFS, University of Texas at Austin
9
# Includes code borrowed from the TCL/TK widget demo.
10
#----------------------------------------------------------------------------
12
#----------------------------------------------------------------------------
15
# Does "standard" startup for a plframe-containing main window.
16
# Use it or roll your own, but note: this may change in future versions.
17
#----------------------------------------------------------------------------
20
global plstdwin_skip_startup
22
# Only do global initialization once.
24
if { ! [info exists plstdwin_skip_startup]} {
26
# Set up configuration options.
27
# The first is to hold default values of everything, the second is for
28
# user customization. See pldefaults.tcl for more info.
33
set plstdwin_skip_startup 1
36
# Set min/max window sizes.
38
set root_width [winfo vrootwidth .]
39
set root_height [winfo vrootheight .]
42
wm maxsize $w [expr "$root_width/64*63"] [expr "$root_height/64*62"]
44
# Set window geometry defaults. Try to get value from:
45
# - option database, from app-defaults file
46
# - global geometry var, from plconfig.tcl (legacy way)
47
# - automatic: specified fraction of root window
49
# Typically we depart from the usual 4/3 ratio somewhat to account for the
53
if [info exists geometry] {
56
set w_geom [option get $w geometry {}]
57
if { $w_geom == "auto" } {
58
set width [expr "$root_width / 16 * 10"]
59
set height [expr "$root_height / 16 * 11"]
60
set w_geom ${width}x${height}
63
if { $w_geom != "" } {
64
wm geometry $w $w_geom
68
#----------------------------------------------------------------------------
71
# Invokes a dialog explaining that the real binding isn't written yet.
72
#----------------------------------------------------------------------------
74
proc null_command {cmd_name} {
75
set dialog_args "-text {Command \"$cmd_name\" not yet implemented.} \
76
-aspect 500 -justify left"
77
mkDialog .null $dialog_args {OK {}}
78
tkwait visibility .null
83
#----------------------------------------------------------------------------
86
# Invokes a dialog explaining that the user bogued out (messed up, blew
87
# it, puked on the system console, etc).
88
#----------------------------------------------------------------------------
90
proc bogue_out {msg} {
91
set dialog_args "-text \"$msg\" -aspect 800 -justify left"
92
mkDialog .bogus $dialog_args {OK {}}
93
tkwait visibility .bogus
99
#----------------------------------------------------------------------------
102
# Position a dialog box at a reasonable place on the screen.
103
#----------------------------------------------------------------------------
106
set offx [expr "[winfo rootx .]+100"]
107
set offy [expr "[winfo rooty .]+100"]
108
wm geometry $w +$offx+$offy
111
#----------------------------------------------------------------------------
114
# Sets up text widgets the way I like them.
115
#----------------------------------------------------------------------------
117
proc normal_text_setup {w {width 60} {height 30}} {
118
global dialog_font dialog_bold_font
120
button $w.ok -text OK -command "destroy $w"
121
text $w.t -relief raised -bd 2 -yscrollcommand "$w.s set" -setgrid true \
122
-width $width -height $height
123
scrollbar $w.s -relief flat -command "text_scroll $w.t"
124
pack append $w $w.ok {bottom fillx} $w.s {right filly} $w.t {expand fill}
127
# Set up display styles
129
$w.t tag configure normal -font $dialog_font
130
$w.t tag configure bold -font $dialog_bold_font
132
if {[winfo depth $w] == 1} {
133
$w.t tag configure color1 -background black -foreground white
134
$w.t tag configure color2 -background black -foreground white
135
$w.t tag configure raised -background white -relief raised \
137
$w.t tag configure sunken -background white -relief sunken \
140
$w.t tag configure color1 -background "#eed5b7"
141
$w.t tag configure color2 -foreground red
142
$w.t tag configure raised -background "#eed5b7" -relief raised \
144
$w.t tag configure sunken -background "#eed5b7" -relief sunken \
147
$w.t tag configure bgstipple -background black -borderwidth 0 \
149
$w.t tag configure fgstipple -fgstipple gray50
150
$w.t tag configure underline -underline on
152
# Set up bindings to be as useful as possible.
154
bind $w <Any-Enter> "focus $w.t"
156
bind $w.t <Return> "destroy $w"
158
bind $w.t <Down> "text_scroll_by_line $w.t + 1"
159
bind $w.t <Up> "text_scroll_by_line $w.t - 1"
161
bind $w.t <Next> "text_scroll_by_page $w.t + 1"
162
bind $w.t <space> "text_scroll_by_page $w.t + 1"
164
bind $w.t <Prior> "text_scroll_by_page $w.t - 1"
165
bind $w.t <BackSpace> "text_scroll_by_page $w.t - 1"
166
bind $w.t <Delete> "text_scroll_by_page $w.t - 1"
169
#----------------------------------------------------------------------------
172
# Scrolls text widget vertically, updating various things
173
#----------------------------------------------------------------------------
175
proc text_scroll {w line args} {
176
eval [list $w yview $line] $args
177
$w mark set insert [$w index @0,0]
180
#----------------------------------------------------------------------------
181
# text_scroll_by_line
183
# Scrolls text widget vertically by the given number of lines.
184
#----------------------------------------------------------------------------
186
proc text_scroll_by_line {w sign delta} {
187
text_scroll $w [$w index "@0,0 $sign $delta lines"]
190
#----------------------------------------------------------------------------
191
# text_scroll_by_page
193
# Scrolls text widget vertically by the given number of pages (almost).
194
#----------------------------------------------------------------------------
196
proc text_scroll_by_page {w sign delta} {
197
set height [lindex [$w config -height] 4]
198
set delta [expr $delta*($height-2)]
199
text_scroll $w [$w index "@0,0 $sign $delta lines"]
202
#----------------------------------------------------------------------------
203
# The procedure below inserts text into a given text widget and
204
# applies one or more tags to that text. The arguments are:
206
# w Window in which to insert
207
# text Text to insert (it's inserted at the "insert" mark)
208
# args One or more tags to apply to text. If this is empty
209
# then all tags are removed from the text.
210
#----------------------------------------------------------------------------
212
proc insertWithTags {w text args} {
213
set start [$w index insert]
214
$w insert insert $text
215
foreach tag [$w tag names $start] {
216
$w tag remove $tag $start insert
219
$w tag add $i $start insert
223
#----------------------------------------------------------------------------
224
# Numeric utility procs:
226
# min returns minimum argument
227
# max returns maximum argument
229
# Taken from utils.tcl by Tom Phelps (phelps@cs.Berkeley.EDU)
230
#----------------------------------------------------------------------------
233
set x [lindex $args 0]
235
if {$i<$x} {set x $i}
241
set x [lindex $args 0]
243
if {$i>$x} {set x $i}
248
#----------------------------------------------------------------------------
251
# Puts up a file selector. Uses iWidgets 3.0 File selector if available,
252
# otherwise just getItem.
254
# I have to go through a bit of trickery to get "~" expanded, since the
255
# Tcl glob doesn't expand it if the file doesn't already exist.
256
#----------------------------------------------------------------------------
258
proc fileSelect {{filter {}}} {
260
# Use the Iwidgets file selector if available
261
if ![catch {package require Iwidgets}] {
262
if {![winfo exist .fs]} {
263
iwidgets::fileselectiondialog .fs -modality application
267
.fs configure -mask $filter
271
if {[.fs activate]} {
280
set file [getItem "Enter file name"]
283
if { [string index $file 0] == "~" } {
284
set file [glob ~][string trimleft $file ~]
290
#----------------------------------------------------------------------------
293
# Puts up a file selector for save file.
294
#----------------------------------------------------------------------------
296
proc getSaveFile {devkey} {
300
# Map device name to filter suffix.
301
# Add to this as desired.
303
"ps" "set filter *.ps" \
304
"psc" "set filter *.ps" \
305
"plmeta" "set filter *.plm" \
306
"xfig" "set filter *.fig"
308
return [fileSelect $filter]
311
#----------------------------------------------------------------------------
314
# Puts up a file selector for a palette file.
315
#----------------------------------------------------------------------------
317
proc getPaletteFile {} {
319
return [fileSelect *.pal]
322
#----------------------------------------------------------------------------
325
# Asks user to input something, returning the result.
326
# Selecting "Cancel" returns the empty string.
327
#----------------------------------------------------------------------------
329
proc getItem {item} {
330
global dialog_font dialog_bold_font
340
wm iconname $w "Entry"
341
message $w.msg -font $dialog_font -aspect 800 -text $item
343
frame $w.frame -borderwidth 10
344
pack append $w.frame \
345
[entry $w.frame.e1 -relief sunken] {top pady 10 fillx}
347
button $w.ok -text OK -command \
348
"set itemval \[$w.frame.e1 get\]; destroy $w"
349
button $w.cancel -text Cancel -command "destroy $w"
351
bind $w.frame.e1 <Return> \
352
"set itemval \[$w.frame.e1 get\]; destroy $w"
354
pack append $w $w.msg {top fill} $w.frame {top expand fill} \
355
$w.ok {left expand fill} $w.cancel {left expand fill}
364
#----------------------------------------------------------------------------
367
# Sure about that, buddy?
368
#----------------------------------------------------------------------------
372
set dialog_args "-text {$msg} \
373
-aspect 500 -justify left"
374
mkDialog .confirm $dialog_args \
375
"OK {set confirm_flag 1}" "Cancel {set confirm_flag 0}"
376
tkwait visibility .confirm
379
tkwait window .confirm
383
#----------------------------------------------------------------------------
384
# mkDialog w msgArgs list list ...
386
# Create a dialog box with a message and any number of buttons at
390
# w - Name to use for new top-level window.
391
# msgArgs - List of arguments to use when creating the message of the
392
# dialog box (e.g. text, justifcation, etc.)
393
# list - A two-element list that describes one of the buttons that
394
# will appear at the bottom of the dialog. The first element
395
# gives the text to be displayed in the button and the second
396
# gives the command to be invoked when the button is invoked.
397
#----------------------------------------------------------------------------
399
proc mkDialog {w msgArgs args} {
401
toplevel $w -class Dialog
403
wm title $w "Dialog box"
404
wm iconname $w "Dialog"
406
# Create two frames in the main window. The top frame will hold the message
407
# and the bottom one will hold the buttons. Arrange them one above the
408
# other, with any extra vertical space split between them.
410
frame $w.top -relief raised -border 1
411
frame $w.bot -relief raised -border 1
412
pack append $w $w.top {top fill expand} $w.bot {top fill expand}
414
# Create the message widget and arrange for it to be centered in the top
417
eval message $w.top.msg -justify center $msgArgs
418
pack append $w.top $w.top.msg {top expand padx 10 pady 10}
420
# Create as many buttons as needed and arrange them from left to right in
421
# the bottom frame. Embed the left button in an additional sunken frame to
422
# indicate that it is the default button, and arrange for that button to be
423
# invoked as the default action for clicks and returns in the dialog.
425
if {[llength $args] > 0} {
426
set arg [lindex $args 0]
427
frame $w.bot.0 -relief sunken -border 1
428
pack append $w.bot $w.bot.0 {left expand padx 20 pady 20}
429
button $w.bot.0.button -text [lindex $arg 0] \
430
-command "[lindex $arg 1]; destroy $w"
431
pack append $w.bot.0 $w.bot.0.button {expand padx 12 pady 12}
432
bind $w <Return> "[lindex $arg 1]; destroy $w"
436
foreach arg [lrange $args 1 end] {
437
button $w.bot.$i -text [lindex $arg 0] \
438
-command "[lindex $arg 1]; destroy $w"
439
pack append $w.bot $w.bot.$i {left expand padx 20}
443
bind $w <Any-Enter> [list focus $w]
447
#----------------------------------------------------------------------------
450
# Create a top-level window that displays a bunch of entries used for
451
# entering window coordinates.
454
# w Name of top level window
455
# desc Short description of coordinates to be entered.
457
# Global variables referenced:
463
# The global variables are modified by the entry widgets and may be
464
# overwritten at any time so the caller must wait for the dialog to be
465
# destroyed and then use them immediately.
466
#----------------------------------------------------------------------------
468
proc Form2d {w desc} {
469
global dialog_font dialog_bold_font
471
global fv00 fv01 fv10 fv11
472
global fn00 fn01 fn10 fn11
478
wm title $w "Entry window"
479
wm iconname $w "Entry"
484
-text "$desc Click \"OK\" button when finished."
497
set name [set fn$i$j]
498
set value [set fv$i$j]
499
frame $w.$i.$j -bd 1m
501
entry $w.$i.$j.entry -relief sunken -width 10
502
$w.$i.$j.entry insert 0 $value
503
bind $w.$i.$j.entry <Tab> "Form2d_tab \$tabList"
504
bind $w.$i.$j.entry <Return> "Form2d_destroy $w"
505
set tabList [concat $tabList $w.$i.$j.entry]
507
label $w.$i.$j.label -width 10
508
$w.$i.$j.label config -text "$name:"
510
pack append $w.$i.$j \
511
$w.$i.$j.entry right \
515
$w.$i.$j {left fillx}
522
button $w.ok -text OK -command "Form2d_destroy $w"
531
# This procedure is invoked when the top level entry dialog is destroyed.
532
# It updates the global vars used to communicate the entry values then
533
# destroys the window.
535
proc Form2d_destroy {w} {
536
global fv00 fv01 fv10 fv11
538
set fv00 [$w.0.0.entry get]
539
set fv01 [$w.0.1.entry get]
540
set fv10 [$w.1.0.entry get]
541
set fv11 [$w.1.1.entry get]
546
# The procedure below is invoked in response to tabs in the entry
547
# windows. It moves the focus to the next window in the tab list.
550
# list - Ordered list of windows to receive focus
552
proc Form2d_tab {list} {
553
set i [lsearch $list [focus]]
558
if {$i >= [llength $list]} {
562
focus [lindex $list $i]
565
#----------------------------------------------------------------------------
568
# Create a top-level window containing a text widget that allows you
569
# to enter a TCL command and have it executed.
572
# w - Name to use for new top-level window.
573
#----------------------------------------------------------------------------
575
proc evalCmd {{w .eval}} {
577
# -geometry unknown in 7.6 toplevels: toplevel $w -geometry 400x300
579
wm geometry $w 400x300
581
wm title $w "Interpret command"
582
wm iconname $w "Interpret"
585
label $w.cmd.label -text "Command:" -width 13 -anchor w
586
entry $w.cmd.entry -width 40 -relief sunken -bd 2 -textvariable command
587
button $w.cmd.button -text "Execute" \
588
-command "eval \$command"
589
pack append $w.cmd $w.cmd.label left $w.cmd.entry left \
590
$w.cmd.button {left pady 10 padx 20}
591
bind $w.cmd.entry <Return> "eval \$command"
593
text $w.t -relief raised -bd 2 -setgrid true
595
Type TCL command to be executed in the window above, then type <Return>
596
or click on "Execute".
598
$w.t mark set insert 0.0
599
bind $w <Any-Enter> "focus $w.cmd.entry"
601
button $w.ok -text OK -command "destroy $w"
603
pack append $w $w.cmd {top fill} \
604
$w.ok {bottom fillx} $w.t {expand fill}
607
#----------------------------------------------------------------------------
608
# Used to get rid of sections of code during development.
609
#----------------------------------------------------------------------------
611
proc ignore { args } {}
613
#------------------------------------------------------------------------------
614
# Proc to set up debug bindings.
615
#------------------------------------------------------------------------------
619
bind $w <Any-ButtonPress> {puts stderr "Widget event: ButtonPress"}
620
bind $w <Any-ButtonRelease> {puts stderr "Widget event: ButtonRelease"}
621
bind $w <Any-Circulate> {puts stderr "Widget event: Circulate"}
622
bind $w <Any-CirculateRequest> {puts stderr "Widget event: CirculateRequest"}
623
bind $w <Any-Colormap> {puts stderr "Widget event: Colormap"}
624
bind $w <Any-Configure> {puts stderr "Widget event: Configure"}
625
bind $w <Any-ConfigureRequest> {puts stderr "Widget event: ConfigureRequest"}
626
bind $w <Any-Destroy> {puts stderr "Widget event: Destroy"}
627
bind $w <Any-Enter> {puts stderr "Widget event: Enter"}
628
bind $w <Any-Expose> {puts stderr "Widget event: Expose"}
629
bind $w <Any-FocusIn> {puts stderr "Widget event: FocusIn"}
630
bind $w <Any-FocusOut> {puts stderr "Widget event: FocusOut"}
631
bind $w <Any-Gravity> {puts stderr "Widget event: Gravity"}
632
bind $w <Any-Keymap> {puts stderr "Widget event: Keymap"}
633
bind $w <Any-KeyPress> {puts stderr "Widget event: KeyPress"}
634
bind $w <Any-KeyRelease> {puts stderr "Widget event: KeyRelease"}
635
bind $w <Any-Leave> {puts stderr "Widget event: Leave"}
636
bind $w <Any-Map> {puts stderr "Widget event: Map"}
637
bind $w <Any-MapRequest> {puts stderr "Widget event: MapRequest"}
638
#bind $w <Any-Motion> {puts stderr "Widget event: Motion"}
639
bind $w <Any-Property> {puts stderr "Widget event: Property"}
640
bind $w <Any-Reparent> {puts stderr "Widget event: Reparent"}
641
bind $w <Any-ResizeRequest> {puts stderr "Widget event: ResizeRequest"}
642
bind $w <Any-Unmap> {puts stderr "Widget event: Unmap"}
643
bind $w <Any-Visibility> {puts stderr "Widget event: Visibility"}