home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 3 / TheARMClub_PDCD3.iso / hensa / maths / plplot / plplot_2 / drivers / tk / plwidget.t < prev    next >
Encoding:
Text File  |  1994-08-25  |  28.0 KB  |  1,034 lines

  1. # $Id: plwidget.tcl,v 1.26 1994/08/25 04:01:23 mjl Exp $
  2. # $Log: plwidget.tcl,v $
  3. # Revision 1.26  1994/08/25  04:01:23  mjl
  4. # Simplified and sped up eop handling.
  5. #
  6. # Revision 1.25  1994/07/13  21:40:35  mjl
  7. # Put in status message while waiting for plot to be saved.  Reassures the
  8. # user that the program hasn't crashed, when saving very complicated plots.
  9. #
  10. # Revision 1.24  1994/06/09  20:24:57  mjl
  11. # Massive reorganization and cleaning up.  Main result is that the plplot
  12. # "megawidget" acts much more like a normal Tk widget.  Still not
  13. # configurable; this will require extending it using itcl.  But now,
  14. # creation and mapping is much more straightforward, both directly (from
  15. # plserver or an extended wish) and from the plplot/tk driver.  You can do
  16. # simply:
  17. #
  18. #     plxframe .plw
  19. #     pack append . .plw {bottom fill expand}
  20. #
  21. # and you get a plframe "megawidget", complete with plot menu (with dump,
  22. # zoom, etc) and status label.  Support widgets relevant for the plplot/tk
  23. # driver do not come up unless invoked from the tk driver (by specifying
  24. # a client to connect to).  The main drawback at this point with this method
  25. # is that direct plotting commands in Tcl must be specified using the syntax
  26. # (for the above example) ".plw.plwin cmd <command> <args>", whereas in
  27. # itcl is simply ".plw <command> <args>".
  28. #
  29.  
  30. #----------------------------------------------------------------------------
  31. # PLPLOT TK/TCL graphics renderer
  32. # plplot window initialization procs
  33. # Maurice LeBrun
  34. # IFS, University of Texas at Austin
  35. # 29-May-1993
  36. #
  37. # Note: to keep namespace problems to a minimum, all procs defined here begin
  38. # with "pl".  These are further subdivided into "plw_" for button- or
  39. # menu-accessible commands, or "pl_" for utility commands.
  40. #----------------------------------------------------------------------------
  41.  
  42. #----------------------------------------------------------------------------
  43. # plw_create
  44. #
  45. # Front-end routine to create plplot megawidget for use from PLplot tk
  46. # driver.  Right now does nothing special.
  47. #----------------------------------------------------------------------------
  48.  
  49. proc plw_create {w {client {}}} {
  50.     plxframe $w $client
  51. }
  52.  
  53. #----------------------------------------------------------------------------
  54. # plr_create
  55. #
  56. # A front-end to plw_create, used by plrender.
  57. #----------------------------------------------------------------------------
  58.  
  59. proc plr_create {w {client {}}} {
  60.     global is_plrender; set is_plrender 1
  61.     plw_create $w $client
  62. }
  63.  
  64. #----------------------------------------------------------------------------
  65. # plxframe
  66. #
  67. # Creates the "extended" plframe widget.  Eventually may be replaced with
  68. # a real megawidget capability, using itcl.  The actual plframe widget
  69. # is named $w.plwin.  Example usage:
  70. #
  71. # plxframe .plw
  72. # pack append . .plw {bottom fill expand}
  73. #
  74. # The PLplot/TK (or DP) driver works by fork/exec of a plserver (an
  75. # extended wish), and subsequent communication of graphics instructions
  76. # data from the driver via a FIFO or socket.  In this case the client
  77. # variable must be specified in the call.  In direct widget instantiation
  78. # the client variable should not be used.
  79. #----------------------------------------------------------------------------
  80.  
  81. proc plxframe {w {client {}}} {
  82.  
  83.     global is_plrender
  84.  
  85. # Make container frame.  It is mapped later.
  86.  
  87.     frame $w
  88.  
  89. # Create child plplot widget (plframe), and pack into parent.
  90.  
  91.     plframe $w.plwin -relief sunken
  92.     pack append $w \
  93.     $w.plwin {bottom expand fill}
  94.  
  95. # Make frame for top row widgets.
  96. # plframe widget must already have been created (the plframe is queried
  97. # for a list of the valid output devices for page dumps).
  98.  
  99.     plw_create_TopRow $w $client
  100.     pack append $w \
  101.     $w.ftop {top fill}
  102.  
  103. # Initialize plplot widget
  104. # Enable keyboard traversal when widget has the input focus.
  105. # Also grab the initial input focus.
  106.  
  107.     tk_bindForTraversal $w.plwin
  108.     focus $w.plwin
  109.  
  110. # Bindings
  111. #
  112. # Note: it is necessary here to protect the $client variable from becoming
  113. # two tokens if it has embedded spaces, such as occurs when you have
  114. # multiple copies running.  The [list $client] construct will enclose
  115. # $client with a pair of braces if necessary (can't do it directly since
  116. # braces prevent variable expansion).  The reason this is necessary is
  117. # because binding the command to a key causes it to be parsed by the
  118. # interpreter twice -- once during the bind and once during its execution.
  119.  
  120.     bind $w.plwin <Any-KeyPress> \
  121.     "key_filter $w [list $client] %K %N %A 0 0"
  122.  
  123.     bind $w.plwin <Shift-KeyPress> \
  124.     "key_filter $w [list $client] %K %N %A 1 0"
  125.  
  126.     bind $w.plwin <Control-KeyPress> \
  127.     "key_filter $w [list $client] %K %N %A 0 1"
  128.  
  129.     bind $w.plwin <Shift-Control-KeyPress> \
  130.     "key_filter $w [list $client] %K %N %A 1 1"
  131.  
  132.     bind $w.plwin <Any-ButtonPress> \
  133.     "plw_user_mouse $w [list $client] %b %s %x %y"
  134.  
  135.     bind $w.plwin <Any-Enter> \
  136.     "focus $w.plwin"
  137.  
  138. # Set up bop/eop signal and inform client of plplot widget name for widget
  139. # commands.
  140.  
  141.     if { $client != "" } then {
  142.     set bop_col [option get $w.ftop.leop off Label]
  143.     set eop_col [option get $w.ftop.leop on Label]
  144.  
  145.     $w.plwin configure -bopcmd "plw_flash $w $bop_col"
  146.     $w.plwin configure -eopcmd "plw_flash $w $eop_col"
  147.     client_cmd $client "set plwidget $w.plwin"
  148.     }
  149.  
  150.     return $w
  151. }
  152.  
  153. #----------------------------------------------------------------------------
  154. # plw_create_TopRow
  155. #
  156. # Create top row widgets.  Page-oriented widgets only have a meaning in
  157. # the context of the PLplot driver, so don't create them if $client is the
  158. # empty string (as occurs for direct widget instantiation).
  159. #----------------------------------------------------------------------------
  160.  
  161. proc plw_create_TopRow {w client} {
  162.     global is_plrender
  163.  
  164.     frame $w.ftop
  165.  
  166. # End of page indicator
  167.  
  168.     if { $client != "" } then {
  169.     pack append $w.ftop \
  170.         [label $w.ftop.leop -relief raised] \
  171.         {left fill padx 12}
  172.  
  173.     $w.ftop.leop config -bg [option get $w.ftop.leop on Label]
  174.     }
  175.  
  176. # Plot menu
  177.  
  178.     pack append $w.ftop \
  179.     [plw_create_pmenu $w] \
  180.     {left fill padx 12}
  181.  
  182. # Forward and backward (plrender only) page buttons.
  183.  
  184.     if { $client != "" } then {
  185.     if { [info exists is_plrender] } {
  186.         pack append $w.ftop \
  187.         [button $w.ftop.bp -text "<<" -relief raised] \
  188.         {left fill padx 10}
  189.  
  190.         $w.ftop.bp configure \
  191.         -command "client_cmd [list $client] {keypress BackSpace}"
  192.     }
  193.  
  194.     pack append $w.ftop \
  195.         [button $w.ftop.fp -text ">>" -relief raised] \
  196.         {left fill padx 10}
  197.  
  198.     $w.ftop.fp configure \
  199.         -command "client_cmd [list $client] {keypress Return}"
  200.     }
  201.  
  202. # Label widget for status messages.
  203.  
  204.     label $w.ftop.lstat -anchor w -relief raised
  205.     plw_label_reset $w
  206.     pack append $w.ftop $w.ftop.lstat \
  207.     {right expand fill} 
  208. }
  209.  
  210. #----------------------------------------------------------------------------
  211. # plw_create_pmenu
  212. #
  213. # Create plot menu.
  214. #
  215. # It is tempting to create buttons for some of these options, but buttons
  216. # are difficult to effectively place and extend.  Menus have a clear
  217. # placement mechanism and are easy to add to.  Further, TK menus can be
  218. # torn off (select menu with middle mouse button and move to where you
  219. # want it) which makes selecting top-level menu buttons easy.  Finally,
  220. # certain menu options have keyboard equivalents: zoom-select (z),
  221. # zoom-reset (r), print (p), and save-again (s).
  222. #----------------------------------------------------------------------------
  223.  
  224. proc plw_create_pmenu {w} {
  225.  
  226.     menubutton $w.ftop.pmenu -menu $w.ftop.pmenu.m \
  227.     -text "Plot" \
  228.     -relief raised
  229.  
  230.     menu $w.ftop.pmenu.m
  231.  
  232. #-------
  233. # Print
  234. #-------
  235.  
  236.     $w.ftop.pmenu.m add command \
  237.     -label "Print" \
  238.     -command "plw_print $w"
  239.  
  240. #-----------------
  241. # Save (cascade)
  242. #-----------------
  243.  
  244.     $w.ftop.pmenu.m add cascade \
  245.     -label "Save" \
  246.     -menu $w.ftop.pmenu.m.save
  247.  
  248.     menu $w.ftop.pmenu.m.save
  249.  
  250. # Save - As.. (another cascade)
  251.  
  252.     $w.ftop.pmenu.m.save add cascade \
  253.     -label "As" \
  254.     -menu $w.ftop.pmenu.m.save.as
  255.  
  256.     menu $w.ftop.pmenu.m.save.as
  257.  
  258. # Generate the device list in the "Save/As" widget menu, by querying the
  259. # plframe widget for the available output devices (which are listed).
  260.  
  261.     set j 0
  262.     foreach i [$w.plwin info devices] {
  263.     $w.ftop.pmenu.m.save.as add command \
  264.         -label $i \
  265.         -command "plw_saveas $w $j"
  266.     set j [expr "$j + 1"]
  267.     }
  268.  
  269. # Save - Again
  270.  
  271.     $w.ftop.pmenu.m.save add command \
  272.     -label "Again" \
  273.     -command "plw_save $w"
  274.  
  275. # Save - Close
  276.  
  277.     $w.ftop.pmenu.m.save add command \
  278.     -label "Close" \
  279.     -command "plw_close $w"
  280.  
  281. #-----------------
  282. # Orient (cascade)
  283. #-----------------
  284.  
  285.     $w.ftop.pmenu.m add cascade \
  286.     -label "Orient" \
  287.     -menu $w.ftop.pmenu.m.orient
  288.  
  289.     menu $w.ftop.pmenu.m.orient
  290.  
  291. # Orient - 0 degrees
  292.  
  293.     $w.ftop.pmenu.m.orient add radio \
  294.     -label "0 degrees" \
  295.     -command "plw_orient $w 0"
  296.  
  297. # Orient - 90 degrees
  298.  
  299.     $w.ftop.pmenu.m.orient add radio \
  300.     -label "90 degrees" \
  301.     -command "plw_orient $w 1"
  302.  
  303. # Orient - 180 degrees
  304.  
  305.     $w.ftop.pmenu.m.orient add radio \
  306.     -label "180 degrees" \
  307.     -command "plw_orient $w 2"
  308.  
  309. # Orient - 270 degrees
  310.  
  311.     $w.ftop.pmenu.m.orient add radio \
  312.     -label "270 degrees" \
  313.     -command "plw_orient $w 3"
  314.  
  315. #-----------------
  316. # Zoom (cascade)
  317. #-----------------
  318.  
  319.     $w.ftop.pmenu.m add cascade \
  320.     -label "Zoom" \
  321.     -menu $w.ftop.pmenu.m.zoom
  322.  
  323.     menu $w.ftop.pmenu.m.zoom
  324.  
  325. # Zoom - select (by mouse)
  326.  
  327.     $w.ftop.pmenu.m.zoom add command \
  328.     -label "Select" \
  329.     -command "plw_zoom_select $w"
  330.  
  331. # Zoom - enter bounds
  332.  
  333.     $w.ftop.pmenu.m.zoom add command \
  334.     -label "Enter bounds.." \
  335.     -command "plw_zoom_enter $w"
  336.  
  337. # Zoom - reset
  338.  
  339.     $w.ftop.pmenu.m.zoom add command \
  340.     -label "Reset" \
  341.     -command "plw_zoom_reset $w"
  342.  
  343. #------------------------
  344. # Set up page (cascade)
  345. #------------------------
  346.  
  347.     $w.ftop.pmenu.m add cascade \
  348.     -label "Page" \
  349.     -menu $w.ftop.pmenu.m.page
  350.  
  351.     menu $w.ftop.pmenu.m.page
  352.  
  353. # Page - enter bounds
  354.  
  355.     $w.ftop.pmenu.m.page add command \
  356.     -label "Setup.." \
  357.     -command "plw_page_enter $w"
  358.  
  359. # Page - reset
  360.  
  361.     $w.ftop.pmenu.m.page add command \
  362.     -label "Reset" \
  363.     -command "plw_page_reset $w"
  364.  
  365. #---------
  366. # Redraw (only for debugging)
  367. #---------
  368. #
  369. #    $w.ftop.pmenu.m add command \
  370. #    -label "Redraw" \
  371. #    -command "$w.plwin redraw"
  372.  
  373. #------------------
  374. # Options (cascade)
  375. #------------------
  376.  
  377.     $w.ftop.pmenu.m add cascade \
  378.     -label "Options" \
  379.     -menu $w.ftop.pmenu.m.options
  380.  
  381.     menu $w.ftop.pmenu.m.options
  382.  
  383.     $w.ftop.pmenu.m.options add command \
  384.     -label "Palette 0" \
  385.     -command "plcmap0_edit $w" 
  386.  
  387.     $w.ftop.pmenu.m.options add command \
  388.     -label "Palette 1" \
  389.     -command "plcmap1_edit $w" 
  390.  
  391. #    $w.ftop.pmenu.m.options add separator
  392.  
  393. #    $w.ftop.pmenu.m.options add command \
  394. #    -label "Load Configuration" \
  395. #    -command {null_command "Load Configuration"} 
  396.  
  397. #    $w.ftop.pmenu.m.options add command \
  398. #    -label "Save Configuration" \
  399. #    -command {null_command "Save Configuration"} 
  400.  
  401. #    $w.ftop.pmenu.m.options add command \
  402. #    -label "Save Configuration As..." \
  403. #    -command {null_command "Save Configuration As..."} 
  404.  
  405. # Los endos
  406.  
  407.     return $w.ftop.pmenu
  408. }
  409.  
  410. #----------------------------------------------------------------------------
  411. # plw_start
  412. #
  413. # Responsible for plplot graphics package initialization on the widget.
  414. # People driving the widget directly should just use pack themselves.
  415. #
  416. # Put here to reduce the possibility of a time out over a slow network --
  417. # the client program waits until the variable widget_is_ready is set.
  418. #----------------------------------------------------------------------------
  419.  
  420. proc plw_start {w {client {}}} {
  421.  
  422. # Manage widget hierarchy
  423.  
  424.     pack append [winfo parent $w] $w \
  425.     {bottom expand fill}
  426.  
  427.     update
  428.  
  429. # Inform client that we're done.
  430.  
  431.     if { $client != "" } then {
  432.     client_cmd $client "set widget_is_ready 1"
  433.     }
  434. }
  435.  
  436. #----------------------------------------------------------------------------
  437. # key_filter
  438. #
  439. # Front-end to key handler.
  440. # For supported operations it's best to modify the global key variables
  441. # to get the desired action.  More advanced stuff can be done with the
  442. # $user_key_filter proc.  Find anything particularly useful?  Let me know,
  443. # so it can be added to the default behavior.
  444. #----------------------------------------------------------------------------
  445.  
  446. proc key_filter {w client k n a shift control} {
  447.     global user_key_filter
  448.  
  449.     global key_zoom_select
  450.     global key_zoom_reset
  451.     global key_print
  452.     global key_save_again
  453.     global key_scroll_right
  454.     global key_scroll_left
  455.     global key_scroll_up
  456.     global key_scroll_down
  457.     global key_scroll_slow
  458.     global key_scroll_fast
  459.     global key_scroll_faster
  460.  
  461. #    puts "keypress: $k $n $a"
  462.  
  463.     if { [info exists user_key_filter] } then {
  464.     $user_key_filter $w $client $k $n $a
  465.     }
  466.  
  467.     if { $shift } then {
  468.     if { $control } then {
  469.         set s $key_scroll_faster
  470.     } else {
  471.         set s $key_scroll_fast
  472.     }
  473.     } else {
  474.     set s $key_scroll_slow
  475.     }
  476.  
  477.     switch $k \
  478.     $key_zoom_select    "plw_zoom_select $w" \
  479.     $key_zoom_reset        "plw_zoom_reset $w" \
  480.     $key_print        "plw_print $w" \
  481.     $key_save_again        "plw_save $w" \
  482.     $key_scroll_right    "plw_view_scroll $w  $s  0" \
  483.     $key_scroll_left    "plw_view_scroll $w -$s  0" \
  484.     $key_scroll_up        "plw_view_scroll $w  0 -$s" \
  485.     $key_scroll_down    "plw_view_scroll $w  0  $s" 
  486.  
  487.     if { $client != "" } then {
  488.     client_cmd [list $client] "keypress $k $n $a"
  489.     }
  490. }
  491.  
  492. #----------------------------------------------------------------------------
  493. # plw_flash
  494. #
  495. # Set eop button color to indicate page status.
  496. #----------------------------------------------------------------------------
  497.  
  498. proc plw_flash {w col} {
  499.     $w.ftop.leop config -bg $col
  500.     update idletasks
  501. }
  502.  
  503. #----------------------------------------------------------------------------
  504. # plw_end
  505. #
  506. # Executed as part of orderly shutdown procedure.  Eventually will just
  507. # destroy the plframe and surrounding widgets, and server will exit only
  508. # if all plotting widgets have been destroyed and it is a child of the
  509. # plplot/TK driver.
  510. #----------------------------------------------------------------------------
  511.  
  512. proc plw_end {w} {
  513.     exit
  514. }
  515.  
  516. #----------------------------------------------------------------------------
  517. # plw_print
  518. #
  519. # Prints plot.  Uses the "plpr" script, which must be set up for your site
  520. # as appropriate.  There are better ways to do it but this way is safest
  521. # for now.
  522. #----------------------------------------------------------------------------
  523.  
  524. proc plw_print {w} {
  525.     if { [catch "$w.plwin print" foo] } {
  526.     bogue_out "$foo"
  527.     } else {
  528.     status_msg $w "Plot printed."
  529.     }
  530. }
  531.  
  532. #----------------------------------------------------------------------------
  533. # plw_saveas
  534. #
  535. # Saves plot to specified device.
  536. # I have to go through a bit of trickery to get "~" expanded, since the
  537. # Tcl 7.0 glob no longer expands names if the file doesn't already exist.
  538. #----------------------------------------------------------------------------
  539.  
  540. proc plw_saveas {w dev} {
  541.     set file [getItem "Enter file name"]
  542.     if { [string index $file 0] == "~" } {
  543.     set file [glob ~][string trimleft $file ~]
  544.     }
  545.     if { [string length $file] > 0 } {
  546.     if { [file exists $file] } {
  547.         if { ! [confirm "File $file already exists.  Are you sure?"] } {
  548.         return
  549.         }
  550.     }
  551.     plw_label_set $w "Saving plot..."
  552.     update
  553.     if { [catch "$w.plwin save as $dev $file" foo] } {
  554.         plw_label_reset $w
  555.         bogue_out "$foo"
  556.     } else {
  557.         status_msg $w "Plot saved."
  558.     }
  559.     } else {
  560.     bogue_out "No file specified"
  561.     }
  562. }
  563.  
  564. #----------------------------------------------------------------------------
  565. # plw_save
  566. #
  567. # Saves plot to an already open file.  If none open, issues an error dialog.
  568. #----------------------------------------------------------------------------
  569.  
  570. proc plw_save {w} {
  571.     if { [catch "$w.plwin save" foo] } {
  572.     bogue_out "$foo"
  573.     } else {
  574.     status_msg $w "Plot saved."
  575.     }
  576. }
  577.  
  578. #----------------------------------------------------------------------------
  579. # plw_close
  580. #
  581. # Close save file.
  582. #----------------------------------------------------------------------------
  583.  
  584. proc plw_close {w} {
  585.     if { [catch "$w.plwin save close" foo] } {
  586.     bogue_out "$foo"
  587.     } else {
  588.     status_msg $w "Plot file closed."
  589.     }
  590. }
  591.  
  592. #----------------------------------------------------------------------------
  593. # plw_zoom_select
  594. #
  595. # Zooms plot in response to mouse selection.
  596. #----------------------------------------------------------------------------
  597.  
  598. proc plw_zoom_select {w} {
  599.     global def_button_cmd
  600.  
  601.     set def_button_cmd [bind $w.plwin <ButtonPress>]
  602.     plw_label_set $w "Zoom: Click on upper left hand corner of zoom region."
  603.     bind $w.plwin <ButtonPress> "plw_zoom_start $w %x %y"
  604. }
  605.  
  606. #----------------------------------------------------------------------------
  607. # plw_zoom_enter
  608. #
  609. # Zooms plot in response to text entry.
  610. #----------------------------------------------------------------------------
  611.  
  612. proc plw_zoom_enter {w} {
  613.     global fv00 fv01 fv10 fv11
  614.     global fn00 fn01 fn10 fn11
  615.  
  616.     set coords [$w.plwin view]
  617.  
  618.     set fv00 [lindex "$coords" 0]
  619.     set fv01 [lindex "$coords" 1]
  620.     set fv10 [lindex "$coords" 2]
  621.     set fv11 [lindex "$coords" 3]
  622.  
  623.     set fn00 xmin
  624.     set fn01 ymin
  625.     set fn10 xmax
  626.     set fn11 ymax
  627.  
  628.     Form2d .e "Enter window coordinates for zoom.  Each coordinate should range from 0 to 1, with (0,0) corresponding to the lower left hand corner."
  629.     tkwait window .e
  630.  
  631.     plw_view_select $w $fv00 $fv01 $fv10 $fv11
  632. }
  633.  
  634. #----------------------------------------------------------------------------
  635. # plw_zoom_reset
  636. #
  637. # Resets after zoom.
  638. # Note that an explicit redraw is not necessary since the packer issues a
  639. # resize after the scrollbars are unmapped.
  640. #----------------------------------------------------------------------------
  641.  
  642. proc plw_zoom_reset {w} {
  643.     global def_button_cmd
  644.  
  645.     plw_label_reset $w
  646.     bind $w.plwin <ButtonPress> $def_button_cmd
  647.     $w.plwin view reset
  648.     if { [winfo exists $w.hscroll] && [winfo ismapped $w.hscroll] } then {
  649.     pack unpack $w.hscroll
  650.     }
  651.     if { [winfo exists $w.vscroll] && [winfo exists $w.vscroll] } then {
  652.     pack unpack $w.vscroll
  653.     }
  654. }
  655.  
  656. #----------------------------------------------------------------------------
  657. # plw_orient
  658. #
  659. # Changes plot orientation.
  660. #----------------------------------------------------------------------------
  661.  
  662. proc plw_orient {w rot} {
  663.     $w.plwin orient $rot
  664. }
  665.  
  666. #----------------------------------------------------------------------------
  667. # plw_page_enter
  668. #
  669. # Changes output page parameters (margins, aspect ratio, justification).
  670. #----------------------------------------------------------------------------
  671.  
  672. proc plw_page_enter {w} {
  673.     global fv00 fv01 fv10 fv11
  674.     global fn00 fn01 fn10 fn11
  675.  
  676.     set coords [$w.plwin page]
  677.  
  678.     set fv00 [lindex "$coords" 0]
  679.     set fv01 [lindex "$coords" 1]
  680.     set fv10 [lindex "$coords" 2]
  681.     set fv11 [lindex "$coords" 3]
  682.  
  683.     set fn00 mar
  684.     set fn01 aspect
  685.     set fn10 jx
  686.     set fn11 jy
  687.  
  688.     Form2d .e "Enter page setup parameters.  mar denotes the fractional page area on each side to use as a margin (0 to 0.5).  jx and jy are the fractional justification relative to the center (-0.5 to 0.5).  aspect is the page aspect ratio (0 preserves original aspect ratio)."
  689.     tkwait window .e
  690.  
  691.     $w.plwin page $fv00 $fv01 $fv10 $fv11
  692. }
  693.  
  694. #----------------------------------------------------------------------------
  695. # plw_page_reset
  696. #
  697. # Resets page parameters.
  698. #----------------------------------------------------------------------------
  699.  
  700. proc plw_page_reset {w} {
  701.     $w.plwin page 0. 0. 0. 0.
  702. }
  703.  
  704. #----------------------------------------------------------------------------
  705. # plw_zoom_start
  706. #
  707. # Starts plot zoom.
  708. #----------------------------------------------------------------------------
  709.  
  710. proc plw_zoom_start {w wx wy} {
  711.     global def_button_cmd
  712.  
  713.     bind $w.plwin <ButtonPress> $def_button_cmd
  714.     plw_label_set $w "Select zoom region by dragging mouse, then release."
  715.  
  716.     $w.plwin draw init
  717.     bind $w.plwin <B1-Motion>        "plw_zoom_mouse_draw $w $wx $wy %x %y"
  718.     bind $w.plwin <B1-ButtonRelease> "plw_zoom_mouse_end $w $wx $wy %x %y"
  719. }
  720.  
  721. #----------------------------------------------------------------------------
  722. # plw_zoom_mouse_draw
  723. #
  724. # Draws zoom box in response to mouse motion (with button held down).
  725. #----------------------------------------------------------------------------
  726.  
  727. proc plw_zoom_mouse_draw {w wx0 wy0 wx1 wy1} {
  728.     $w.plwin draw rect $wx0 $wy0 $wx1 $wy1
  729. }
  730.  
  731. #----------------------------------------------------------------------------
  732. # plw_zoom_mouse_end
  733. #
  734. # Performs actual zoom, invoked when user releases mouse button.
  735. #----------------------------------------------------------------------------
  736.  
  737. proc plw_zoom_mouse_end {w wx0 wy0 wx1 wy1} {
  738.     
  739. # Finish rubber band draw
  740.  
  741.     bind $w.plwin <B1-ButtonRelease> {}
  742.     bind $w.plwin <B1-Motion> {}
  743.     plw_label_reset $w
  744.  
  745.     set wlx [winfo width $w.plwin]
  746.     set wly [winfo height $w.plwin]
  747.     set xl [expr "$wx0/$wlx."     ]
  748.     set xr [expr "$wx1/$wlx."     ]
  749.     set yl [expr "1 - $wy1/$wly." ]
  750.     set yr [expr "1 - $wy0/$wly." ]
  751.  
  752.     $w.plwin draw end
  753.  
  754. # Select new plot region
  755.  
  756.     plw_view_zoom $w $xl $yl $xr $yr
  757. }
  758.  
  759. #----------------------------------------------------------------------------
  760. # plw_view_select
  761. #
  762. # Handles change of view into plot.
  763. # Given in relative plot window coordinates.
  764. #----------------------------------------------------------------------------
  765.  
  766. proc plw_view_select {w x0 y0 x1 y1} {
  767.     
  768. # Adjust arguments to be in bounds and properly ordered (xl < xr, etc)
  769.  
  770.     set xl [min $x0 $x1]
  771.     set yl [min $y0 $y1]
  772.     set xr [max $x0 $x1]
  773.     set yr [max $y0 $y1]
  774.  
  775.     set xmin 0.
  776.     set ymin 0.
  777.     set xmax 1.
  778.     set ymax 1.
  779.  
  780.     set xl [max $xmin [min $xmax $xl]]
  781.     set yl [max $ymin [min $ymax $yl]]
  782.     set xr [max $xmin [min $xmax $xr]]
  783.     set yr [max $ymin [min $ymax $yr]]
  784.  
  785. # Only create scrollbars if really needed.
  786.  
  787.     if {($xl == $xmin) && ($xr == $xmax)} \
  788.     then {set hscroll 0} else {set hscroll 1}
  789.  
  790.     if {($yl == $xmin) && ($yr == $xmax)} \
  791.     then {set vscroll 0} else {set vscroll 1}
  792.  
  793.     if { ! ($hscroll || $vscroll)} {return}
  794.  
  795. # Select plot region
  796.  
  797.     $w.plwin view select $xl $yl $xr $yr
  798.  
  799. # Fix up view
  800.  
  801.     plw_fixview $w $hscroll $vscroll
  802. }
  803.  
  804. #----------------------------------------------------------------------------
  805. # plw_view_zoom
  806. #
  807. # Handles zoom.
  808. # Given in relative device coordinates.
  809. #----------------------------------------------------------------------------
  810.  
  811. proc plw_view_zoom {w x0 y0 x1 y1} {
  812.     
  813. # Adjust arguments to be in bounds and properly ordered (xl < xr, etc)
  814.  
  815.     set xl [min $x0 $x1]
  816.     set yl [min $y0 $y1]
  817.     set xr [max $x0 $x1]
  818.     set yr [max $y0 $y1]
  819.  
  820.     set bounds [$w.plwin view bounds]
  821.     set xmin [lindex "$bounds" 0]
  822.     set ymin [lindex "$bounds" 1]
  823.     set xmax [lindex "$bounds" 2]
  824.     set ymax [lindex "$bounds" 3]
  825.  
  826.     set xl [max $xmin [min $xmax $xl]]
  827.     set yl [max $ymin [min $ymax $yl]]
  828.     set xr [max $xmin [min $xmax $xr]]
  829.     set yr [max $ymin [min $ymax $yr]]
  830.  
  831. # Only create scrollbars if really needed.
  832.  
  833.     set hscroll [expr ($xl != $xmin) || ($xr != $xmax)]
  834.     set vscroll [expr ($yl != $ymin) || ($yr != $ymax)]
  835.  
  836.     if { ! ($hscroll || $vscroll)} then {
  837.     $w.plwin redraw
  838.     return
  839.     }
  840.  
  841. # Select plot region
  842.  
  843.     $w.plwin view zoom $xl $yl $xr $yr
  844.  
  845. # Fix up view
  846.  
  847.     plw_fixview $w $hscroll $vscroll
  848. }
  849.  
  850. #----------------------------------------------------------------------------
  851. # plw_view_scroll
  852. #
  853. # Scrolls view incrementally.
  854. # Similar to clicking on arrow at end of scrollbar (but speed is user
  855. # controllable).
  856. #----------------------------------------------------------------------------
  857.  
  858. proc plw_view_scroll {w dx dy} {
  859.     
  860.     if {($dx != 0) && \
  861.         [winfo exists $w.hscroll] && [winfo ismapped $w.hscroll] } then {
  862.  
  863.     set first  [lindex [$w.hscroll get] 2]
  864.     $w.plwin xscroll [expr $first+$dx]
  865.     }
  866.     if {($dy != 0) && \
  867.         [winfo exists $w.vscroll] && [winfo ismapped $w.vscroll] } then {
  868.  
  869.     set first  [lindex [$w.vscroll get] 2]
  870.     $w.plwin yscroll [expr $first+$dy]
  871.     }
  872. }
  873.  
  874. #----------------------------------------------------------------------------
  875. # plw_fixview
  876. #
  877. # Handles updates of scrollbars & plot after view change.
  878. #----------------------------------------------------------------------------
  879.  
  880. proc plw_fixview {w hscroll vscroll} {
  881.     
  882. # Create scrollbars if they don't already exist.
  883.  
  884.     set created_sb 0
  885.     if { $hscroll && ! [winfo exists $w.hscroll] } then {
  886.     set created_sb 1
  887.     scrollbar $w.hscroll -relief sunken -orient horiz \
  888.         -command "$w.plwin xscroll"
  889.     $w.plwin config -xscroll "$w.hscroll set"
  890.     }
  891.     if { $vscroll && ! [winfo exists $w.vscroll] } then {
  892.     set created_sb 1
  893.     scrollbar $w.vscroll -relief sunken \
  894.         -command "$w.plwin yscroll"
  895.     $w.plwin config -yscroll "$w.vscroll set"
  896.     }
  897.  
  898. # When scrollbars are first created, it may be necessary to unmap then map
  899. # the plframe widget so that it has a chance to initialize the scrollbars
  900. # before they are mapped.
  901.  
  902.     if { $created_sb } then {
  903.     pack unpack $w.plwin
  904.     pack append $w $w.plwin {left expand fill}
  905.     }
  906.  
  907. # Map scrollbars if not already mapped.
  908. # To get packing right, need to unmap then remap plot widget.
  909. # Otherwise need to do explicit redraw.
  910.  
  911.     if { ($hscroll && ! [winfo ismapped $w.hscroll]) || \
  912.          ($vscroll && ! [winfo ismapped $w.vscroll]) } then {
  913.  
  914.     update
  915.     pack unpack $w.plwin
  916.     if { $hscroll } then {
  917.         pack append $w $w.hscroll {bottom fillx}
  918.     }
  919.     if { $vscroll } then {
  920.         pack append $w $w.vscroll {right filly}
  921.     }
  922.     pack append $w $w.plwin {expand fill}
  923.  
  924.     } else {
  925.     $w.plwin redraw
  926.     }
  927. }
  928.  
  929. #----------------------------------------------------------------------------
  930. # plw_update_view
  931. #
  932. # Updates view.  Results in scrollbars being added if they are appropriate.
  933. # Does nothing if the plot window is unchanged from the default.
  934. #----------------------------------------------------------------------------
  935.  
  936. proc plw_update_view {w} {
  937.     set coords [$w.plwin view]
  938.  
  939.     set xl [lindex "$coords" 0]
  940.     set yl [lindex "$coords" 1]
  941.     set xr [lindex "$coords" 2]
  942.     set yr [lindex "$coords" 3]
  943.  
  944.     plw_view_select $w $xl $yl $xr $yr
  945. }
  946.  
  947. #----------------------------------------------------------------------------
  948. # status_msg
  949. #
  950. # Used for temporarily flashing a status message in the status bar.  Better
  951. # than a dialog because it can be ignored and will go away on its own.
  952. #----------------------------------------------------------------------------
  953.  
  954. proc status_msg {w msg} {
  955.  
  956.     plw_label_set $w $msg
  957.     after 2500 plw_label_reset $w
  958. }
  959.  
  960. #----------------------------------------------------------------------------
  961. # plw_label_reset
  962. #
  963. # Resets message in status bar to the default.
  964. #----------------------------------------------------------------------------
  965.  
  966. proc plw_label_reset {w} {
  967.  
  968.     $w.ftop.lstat configure -text " [string range $w 1 end]"
  969. }
  970.  
  971. #----------------------------------------------------------------------------
  972. # plw_label_set
  973. #
  974. # Sets message in status bar.
  975. #----------------------------------------------------------------------------
  976.  
  977. proc plw_label_set {w msg} {
  978.  
  979.     $w.ftop.lstat configure -text " $msg"
  980. }
  981.  
  982. #----------------------------------------------------------------------------
  983. # plw_user_mouse
  984. #
  985. # Passes buttonpress event information back to client.
  986. # Written by Radey Shouman
  987. #----------------------------------------------------------------------------
  988.  
  989. proc plw_user_mouse {w client button state x y} {
  990.  
  991. # calculate relative window coordinates.
  992.  
  993.     set xw [expr "$x / [winfo width $w.plwin]."]
  994.     set yw [expr "1.0 - $y / [winfo height $w.plwin]."]
  995.  
  996. # calculate normalized device coordinates into original window.
  997.  
  998.     set view [$w.plwin view]
  999.     set xrange [expr "[lindex $view 2] - [lindex $view 0]"]
  1000.     set xnd [expr "($xw * $xrange) + [lindex $view 0]"]
  1001.     set yrange [expr "[lindex $view 3] - [lindex $view 1]"]
  1002.     set ynd [expr "($yw * $yrange ) + [lindex $view 1]"]
  1003.     
  1004. # send them back to the client.
  1005.  
  1006.     if { $client != "" } then {
  1007.     client_cmd [list $client] [list mouse $button $state $xnd $ynd]
  1008.     }
  1009. }
  1010.  
  1011. #----------------------------------------------------------------------------
  1012. # plw_dplink
  1013. #
  1014. # Initializes socket data link between widget and client code.
  1015. # In addition, as this is the last client/server connection needed, I
  1016. # disable further connections.
  1017. #----------------------------------------------------------------------------
  1018.  
  1019. proc plw_dplink {w client} {
  1020.  
  1021.     global list_sock data_sock
  1022.  
  1023.     dp_Host +
  1024.     set rv [dp_connect -server 0]
  1025.     set list_sock [lindex $rv 0]
  1026.     set data_port [lindex $rv 1]
  1027.  
  1028.     dp_RDO $client set data_port $data_port
  1029.     set data_sock [lindex [dp_accept $list_sock] 0]
  1030.     $w.plwin openlink socket $data_sock
  1031.     dp_Host -
  1032. }
  1033.