home *** CD-ROM | disk | FTP | other *** search
Wrap
Text File | 1994-08-25 | 28.0 KB | 1,034 lines
# $Id: plwidget.tcl,v 1.26 1994/08/25 04:01:23 mjl Exp $ # $Log: plwidget.tcl,v $ # Revision 1.26 1994/08/25 04:01:23 mjl # Simplified and sped up eop handling. # # Revision 1.25 1994/07/13 21:40:35 mjl # Put in status message while waiting for plot to be saved. Reassures the # user that the program hasn't crashed, when saving very complicated plots. # # Revision 1.24 1994/06/09 20:24:57 mjl # Massive reorganization and cleaning up. Main result is that the plplot # "megawidget" acts much more like a normal Tk widget. Still not # configurable; this will require extending it using itcl. But now, # creation and mapping is much more straightforward, both directly (from # plserver or an extended wish) and from the plplot/tk driver. You can do # simply: # # plxframe .plw # pack append . .plw {bottom fill expand} # # and you get a plframe "megawidget", complete with plot menu (with dump, # zoom, etc) and status label. Support widgets relevant for the plplot/tk # driver do not come up unless invoked from the tk driver (by specifying # a client to connect to). The main drawback at this point with this method # is that direct plotting commands in Tcl must be specified using the syntax # (for the above example) ".plw.plwin cmd <command> <args>", whereas in # itcl is simply ".plw <command> <args>". # #---------------------------------------------------------------------------- # PLPLOT TK/TCL graphics renderer # plplot window initialization procs # # Maurice LeBrun # IFS, University of Texas at Austin # 29-May-1993 # # Note: to keep namespace problems to a minimum, all procs defined here begin # with "pl". These are further subdivided into "plw_" for button- or # menu-accessible commands, or "pl_" for utility commands. #---------------------------------------------------------------------------- #---------------------------------------------------------------------------- # plw_create # # Front-end routine to create plplot megawidget for use from PLplot tk # driver. Right now does nothing special. #---------------------------------------------------------------------------- proc plw_create {w {client {}}} { plxframe $w $client } #---------------------------------------------------------------------------- # plr_create # # A front-end to plw_create, used by plrender. #---------------------------------------------------------------------------- proc plr_create {w {client {}}} { global is_plrender; set is_plrender 1 plw_create $w $client } #---------------------------------------------------------------------------- # plxframe # # Creates the "extended" plframe widget. Eventually may be replaced with # a real megawidget capability, using itcl. The actual plframe widget # is named $w.plwin. Example usage: # # plxframe .plw # pack append . .plw {bottom fill expand} # # The PLplot/TK (or DP) driver works by fork/exec of a plserver (an # extended wish), and subsequent communication of graphics instructions # data from the driver via a FIFO or socket. In this case the client # variable must be specified in the call. In direct widget instantiation # the client variable should not be used. #---------------------------------------------------------------------------- proc plxframe {w {client {}}} { global is_plrender # Make container frame. It is mapped later. frame $w # Create child plplot widget (plframe), and pack into parent. plframe $w.plwin -relief sunken pack append $w \ $w.plwin {bottom expand fill} # Make frame for top row widgets. # plframe widget must already have been created (the plframe is queried # for a list of the valid output devices for page dumps). plw_create_TopRow $w $client pack append $w \ $w.ftop {top fill} # Initialize plplot widget # Enable keyboard traversal when widget has the input focus. # Also grab the initial input focus. tk_bindForTraversal $w.plwin focus $w.plwin # Bindings # # Note: it is necessary here to protect the $client variable from becoming # two tokens if it has embedded spaces, such as occurs when you have # multiple copies running. The [list $client] construct will enclose # $client with a pair of braces if necessary (can't do it directly since # braces prevent variable expansion). The reason this is necessary is # because binding the command to a key causes it to be parsed by the # interpreter twice -- once during the bind and once during its execution. bind $w.plwin <Any-KeyPress> \ "key_filter $w [list $client] %K %N %A 0 0" bind $w.plwin <Shift-KeyPress> \ "key_filter $w [list $client] %K %N %A 1 0" bind $w.plwin <Control-KeyPress> \ "key_filter $w [list $client] %K %N %A 0 1" bind $w.plwin <Shift-Control-KeyPress> \ "key_filter $w [list $client] %K %N %A 1 1" bind $w.plwin <Any-ButtonPress> \ "plw_user_mouse $w [list $client] %b %s %x %y" bind $w.plwin <Any-Enter> \ "focus $w.plwin" # Set up bop/eop signal and inform client of plplot widget name for widget # commands. if { $client != "" } then { set bop_col [option get $w.ftop.leop off Label] set eop_col [option get $w.ftop.leop on Label] $w.plwin configure -bopcmd "plw_flash $w $bop_col" $w.plwin configure -eopcmd "plw_flash $w $eop_col" client_cmd $client "set plwidget $w.plwin" } return $w } #---------------------------------------------------------------------------- # plw_create_TopRow # # Create top row widgets. Page-oriented widgets only have a meaning in # the context of the PLplot driver, so don't create them if $client is the # empty string (as occurs for direct widget instantiation). #---------------------------------------------------------------------------- proc plw_create_TopRow {w client} { global is_plrender frame $w.ftop # End of page indicator if { $client != "" } then { pack append $w.ftop \ [label $w.ftop.leop -relief raised] \ {left fill padx 12} $w.ftop.leop config -bg [option get $w.ftop.leop on Label] } # Plot menu pack append $w.ftop \ [plw_create_pmenu $w] \ {left fill padx 12} # Forward and backward (plrender only) page buttons. if { $client != "" } then { if { [info exists is_plrender] } { pack append $w.ftop \ [button $w.ftop.bp -text "<<" -relief raised] \ {left fill padx 10} $w.ftop.bp configure \ -command "client_cmd [list $client] {keypress BackSpace}" } pack append $w.ftop \ [button $w.ftop.fp -text ">>" -relief raised] \ {left fill padx 10} $w.ftop.fp configure \ -command "client_cmd [list $client] {keypress Return}" } # Label widget for status messages. label $w.ftop.lstat -anchor w -relief raised plw_label_reset $w pack append $w.ftop $w.ftop.lstat \ {right expand fill} } #---------------------------------------------------------------------------- # plw_create_pmenu # # Create plot menu. # # It is tempting to create buttons for some of these options, but buttons # are difficult to effectively place and extend. Menus have a clear # placement mechanism and are easy to add to. Further, TK menus can be # torn off (select menu with middle mouse button and move to where you # want it) which makes selecting top-level menu buttons easy. Finally, # certain menu options have keyboard equivalents: zoom-select (z), # zoom-reset (r), print (p), and save-again (s). #---------------------------------------------------------------------------- proc plw_create_pmenu {w} { menubutton $w.ftop.pmenu -menu $w.ftop.pmenu.m \ -text "Plot" \ -relief raised menu $w.ftop.pmenu.m #------- # Print #------- $w.ftop.pmenu.m add command \ -label "Print" \ -command "plw_print $w" #----------------- # Save (cascade) #----------------- $w.ftop.pmenu.m add cascade \ -label "Save" \ -menu $w.ftop.pmenu.m.save menu $w.ftop.pmenu.m.save # Save - As.. (another cascade) $w.ftop.pmenu.m.save add cascade \ -label "As" \ -menu $w.ftop.pmenu.m.save.as menu $w.ftop.pmenu.m.save.as # Generate the device list in the "Save/As" widget menu, by querying the # plframe widget for the available output devices (which are listed). set j 0 foreach i [$w.plwin info devices] { $w.ftop.pmenu.m.save.as add command \ -label $i \ -command "plw_saveas $w $j" set j [expr "$j + 1"] } # Save - Again $w.ftop.pmenu.m.save add command \ -label "Again" \ -command "plw_save $w" # Save - Close $w.ftop.pmenu.m.save add command \ -label "Close" \ -command "plw_close $w" #----------------- # Orient (cascade) #----------------- $w.ftop.pmenu.m add cascade \ -label "Orient" \ -menu $w.ftop.pmenu.m.orient menu $w.ftop.pmenu.m.orient # Orient - 0 degrees $w.ftop.pmenu.m.orient add radio \ -label "0 degrees" \ -command "plw_orient $w 0" # Orient - 90 degrees $w.ftop.pmenu.m.orient add radio \ -label "90 degrees" \ -command "plw_orient $w 1" # Orient - 180 degrees $w.ftop.pmenu.m.orient add radio \ -label "180 degrees" \ -command "plw_orient $w 2" # Orient - 270 degrees $w.ftop.pmenu.m.orient add radio \ -label "270 degrees" \ -command "plw_orient $w 3" #----------------- # Zoom (cascade) #----------------- $w.ftop.pmenu.m add cascade \ -label "Zoom" \ -menu $w.ftop.pmenu.m.zoom menu $w.ftop.pmenu.m.zoom # Zoom - select (by mouse) $w.ftop.pmenu.m.zoom add command \ -label "Select" \ -command "plw_zoom_select $w" # Zoom - enter bounds $w.ftop.pmenu.m.zoom add command \ -label "Enter bounds.." \ -command "plw_zoom_enter $w" # Zoom - reset $w.ftop.pmenu.m.zoom add command \ -label "Reset" \ -command "plw_zoom_reset $w" #------------------------ # Set up page (cascade) #------------------------ $w.ftop.pmenu.m add cascade \ -label "Page" \ -menu $w.ftop.pmenu.m.page menu $w.ftop.pmenu.m.page # Page - enter bounds $w.ftop.pmenu.m.page add command \ -label "Setup.." \ -command "plw_page_enter $w" # Page - reset $w.ftop.pmenu.m.page add command \ -label "Reset" \ -command "plw_page_reset $w" #--------- # Redraw (only for debugging) #--------- # # $w.ftop.pmenu.m add command \ # -label "Redraw" \ # -command "$w.plwin redraw" #------------------ # Options (cascade) #------------------ $w.ftop.pmenu.m add cascade \ -label "Options" \ -menu $w.ftop.pmenu.m.options menu $w.ftop.pmenu.m.options $w.ftop.pmenu.m.options add command \ -label "Palette 0" \ -command "plcmap0_edit $w" $w.ftop.pmenu.m.options add command \ -label "Palette 1" \ -command "plcmap1_edit $w" # $w.ftop.pmenu.m.options add separator # $w.ftop.pmenu.m.options add command \ # -label "Load Configuration" \ # -command {null_command "Load Configuration"} # $w.ftop.pmenu.m.options add command \ # -label "Save Configuration" \ # -command {null_command "Save Configuration"} # $w.ftop.pmenu.m.options add command \ # -label "Save Configuration As..." \ # -command {null_command "Save Configuration As..."} # Los endos return $w.ftop.pmenu } #---------------------------------------------------------------------------- # plw_start # # Responsible for plplot graphics package initialization on the widget. # People driving the widget directly should just use pack themselves. # # Put here to reduce the possibility of a time out over a slow network -- # the client program waits until the variable widget_is_ready is set. #---------------------------------------------------------------------------- proc plw_start {w {client {}}} { # Manage widget hierarchy pack append [winfo parent $w] $w \ {bottom expand fill} update # Inform client that we're done. if { $client != "" } then { client_cmd $client "set widget_is_ready 1" } } #---------------------------------------------------------------------------- # key_filter # # Front-end to key handler. # For supported operations it's best to modify the global key variables # to get the desired action. More advanced stuff can be done with the # $user_key_filter proc. Find anything particularly useful? Let me know, # so it can be added to the default behavior. #---------------------------------------------------------------------------- proc key_filter {w client k n a shift control} { global user_key_filter global key_zoom_select global key_zoom_reset global key_print global key_save_again global key_scroll_right global key_scroll_left global key_scroll_up global key_scroll_down global key_scroll_slow global key_scroll_fast global key_scroll_faster # puts "keypress: $k $n $a" if { [info exists user_key_filter] } then { $user_key_filter $w $client $k $n $a } if { $shift } then { if { $control } then { set s $key_scroll_faster } else { set s $key_scroll_fast } } else { set s $key_scroll_slow } switch $k \ $key_zoom_select "plw_zoom_select $w" \ $key_zoom_reset "plw_zoom_reset $w" \ $key_print "plw_print $w" \ $key_save_again "plw_save $w" \ $key_scroll_right "plw_view_scroll $w $s 0" \ $key_scroll_left "plw_view_scroll $w -$s 0" \ $key_scroll_up "plw_view_scroll $w 0 -$s" \ $key_scroll_down "plw_view_scroll $w 0 $s" if { $client != "" } then { client_cmd [list $client] "keypress $k $n $a" } } #---------------------------------------------------------------------------- # plw_flash # # Set eop button color to indicate page status. #---------------------------------------------------------------------------- proc plw_flash {w col} { $w.ftop.leop config -bg $col update idletasks } #---------------------------------------------------------------------------- # plw_end # # Executed as part of orderly shutdown procedure. Eventually will just # destroy the plframe and surrounding widgets, and server will exit only # if all plotting widgets have been destroyed and it is a child of the # plplot/TK driver. #---------------------------------------------------------------------------- proc plw_end {w} { exit } #---------------------------------------------------------------------------- # plw_print # # Prints plot. Uses the "plpr" script, which must be set up for your site # as appropriate. There are better ways to do it but this way is safest # for now. #---------------------------------------------------------------------------- proc plw_print {w} { if { [catch "$w.plwin print" foo] } { bogue_out "$foo" } else { status_msg $w "Plot printed." } } #---------------------------------------------------------------------------- # plw_saveas # # Saves plot to specified device. # I have to go through a bit of trickery to get "~" expanded, since the # Tcl 7.0 glob no longer expands names if the file doesn't already exist. #---------------------------------------------------------------------------- proc plw_saveas {w dev} { set file [getItem "Enter file name"] if { [string index $file 0] == "~" } { set file [glob ~][string trimleft $file ~] } if { [string length $file] > 0 } { if { [file exists $file] } { if { ! [confirm "File $file already exists. Are you sure?"] } { return } } plw_label_set $w "Saving plot..." update if { [catch "$w.plwin save as $dev $file" foo] } { plw_label_reset $w bogue_out "$foo" } else { status_msg $w "Plot saved." } } else { bogue_out "No file specified" } } #---------------------------------------------------------------------------- # plw_save # # Saves plot to an already open file. If none open, issues an error dialog. #---------------------------------------------------------------------------- proc plw_save {w} { if { [catch "$w.plwin save" foo] } { bogue_out "$foo" } else { status_msg $w "Plot saved." } } #---------------------------------------------------------------------------- # plw_close # # Close save file. #---------------------------------------------------------------------------- proc plw_close {w} { if { [catch "$w.plwin save close" foo] } { bogue_out "$foo" } else { status_msg $w "Plot file closed." } } #---------------------------------------------------------------------------- # plw_zoom_select # # Zooms plot in response to mouse selection. #---------------------------------------------------------------------------- proc plw_zoom_select {w} { global def_button_cmd set def_button_cmd [bind $w.plwin <ButtonPress>] plw_label_set $w "Zoom: Click on upper left hand corner of zoom region." bind $w.plwin <ButtonPress> "plw_zoom_start $w %x %y" } #---------------------------------------------------------------------------- # plw_zoom_enter # # Zooms plot in response to text entry. #---------------------------------------------------------------------------- proc plw_zoom_enter {w} { global fv00 fv01 fv10 fv11 global fn00 fn01 fn10 fn11 set coords [$w.plwin view] set fv00 [lindex "$coords" 0] set fv01 [lindex "$coords" 1] set fv10 [lindex "$coords" 2] set fv11 [lindex "$coords" 3] set fn00 xmin set fn01 ymin set fn10 xmax set fn11 ymax 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." tkwait window .e plw_view_select $w $fv00 $fv01 $fv10 $fv11 } #---------------------------------------------------------------------------- # plw_zoom_reset # # Resets after zoom. # Note that an explicit redraw is not necessary since the packer issues a # resize after the scrollbars are unmapped. #---------------------------------------------------------------------------- proc plw_zoom_reset {w} { global def_button_cmd plw_label_reset $w bind $w.plwin <ButtonPress> $def_button_cmd $w.plwin view reset if { [winfo exists $w.hscroll] && [winfo ismapped $w.hscroll] } then { pack unpack $w.hscroll } if { [winfo exists $w.vscroll] && [winfo exists $w.vscroll] } then { pack unpack $w.vscroll } } #---------------------------------------------------------------------------- # plw_orient # # Changes plot orientation. #---------------------------------------------------------------------------- proc plw_orient {w rot} { $w.plwin orient $rot } #---------------------------------------------------------------------------- # plw_page_enter # # Changes output page parameters (margins, aspect ratio, justification). #---------------------------------------------------------------------------- proc plw_page_enter {w} { global fv00 fv01 fv10 fv11 global fn00 fn01 fn10 fn11 set coords [$w.plwin page] set fv00 [lindex "$coords" 0] set fv01 [lindex "$coords" 1] set fv10 [lindex "$coords" 2] set fv11 [lindex "$coords" 3] set fn00 mar set fn01 aspect set fn10 jx set fn11 jy 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)." tkwait window .e $w.plwin page $fv00 $fv01 $fv10 $fv11 } #---------------------------------------------------------------------------- # plw_page_reset # # Resets page parameters. #---------------------------------------------------------------------------- proc plw_page_reset {w} { $w.plwin page 0. 0. 0. 0. } #---------------------------------------------------------------------------- # plw_zoom_start # # Starts plot zoom. #---------------------------------------------------------------------------- proc plw_zoom_start {w wx wy} { global def_button_cmd bind $w.plwin <ButtonPress> $def_button_cmd plw_label_set $w "Select zoom region by dragging mouse, then release." $w.plwin draw init bind $w.plwin <B1-Motion> "plw_zoom_mouse_draw $w $wx $wy %x %y" bind $w.plwin <B1-ButtonRelease> "plw_zoom_mouse_end $w $wx $wy %x %y" } #---------------------------------------------------------------------------- # plw_zoom_mouse_draw # # Draws zoom box in response to mouse motion (with button held down). #---------------------------------------------------------------------------- proc plw_zoom_mouse_draw {w wx0 wy0 wx1 wy1} { $w.plwin draw rect $wx0 $wy0 $wx1 $wy1 } #---------------------------------------------------------------------------- # plw_zoom_mouse_end # # Performs actual zoom, invoked when user releases mouse button. #---------------------------------------------------------------------------- proc plw_zoom_mouse_end {w wx0 wy0 wx1 wy1} { # Finish rubber band draw bind $w.plwin <B1-ButtonRelease> {} bind $w.plwin <B1-Motion> {} plw_label_reset $w set wlx [winfo width $w.plwin] set wly [winfo height $w.plwin] set xl [expr "$wx0/$wlx." ] set xr [expr "$wx1/$wlx." ] set yl [expr "1 - $wy1/$wly." ] set yr [expr "1 - $wy0/$wly." ] $w.plwin draw end # Select new plot region plw_view_zoom $w $xl $yl $xr $yr } #---------------------------------------------------------------------------- # plw_view_select # # Handles change of view into plot. # Given in relative plot window coordinates. #---------------------------------------------------------------------------- proc plw_view_select {w x0 y0 x1 y1} { # Adjust arguments to be in bounds and properly ordered (xl < xr, etc) set xl [min $x0 $x1] set yl [min $y0 $y1] set xr [max $x0 $x1] set yr [max $y0 $y1] set xmin 0. set ymin 0. set xmax 1. set ymax 1. set xl [max $xmin [min $xmax $xl]] set yl [max $ymin [min $ymax $yl]] set xr [max $xmin [min $xmax $xr]] set yr [max $ymin [min $ymax $yr]] # Only create scrollbars if really needed. if {($xl == $xmin) && ($xr == $xmax)} \ then {set hscroll 0} else {set hscroll 1} if {($yl == $xmin) && ($yr == $xmax)} \ then {set vscroll 0} else {set vscroll 1} if { ! ($hscroll || $vscroll)} {return} # Select plot region $w.plwin view select $xl $yl $xr $yr # Fix up view plw_fixview $w $hscroll $vscroll } #---------------------------------------------------------------------------- # plw_view_zoom # # Handles zoom. # Given in relative device coordinates. #---------------------------------------------------------------------------- proc plw_view_zoom {w x0 y0 x1 y1} { # Adjust arguments to be in bounds and properly ordered (xl < xr, etc) set xl [min $x0 $x1] set yl [min $y0 $y1] set xr [max $x0 $x1] set yr [max $y0 $y1] set bounds [$w.plwin view bounds] set xmin [lindex "$bounds" 0] set ymin [lindex "$bounds" 1] set xmax [lindex "$bounds" 2] set ymax [lindex "$bounds" 3] set xl [max $xmin [min $xmax $xl]] set yl [max $ymin [min $ymax $yl]] set xr [max $xmin [min $xmax $xr]] set yr [max $ymin [min $ymax $yr]] # Only create scrollbars if really needed. set hscroll [expr ($xl != $xmin) || ($xr != $xmax)] set vscroll [expr ($yl != $ymin) || ($yr != $ymax)] if { ! ($hscroll || $vscroll)} then { $w.plwin redraw return } # Select plot region $w.plwin view zoom $xl $yl $xr $yr # Fix up view plw_fixview $w $hscroll $vscroll } #---------------------------------------------------------------------------- # plw_view_scroll # # Scrolls view incrementally. # Similar to clicking on arrow at end of scrollbar (but speed is user # controllable). #---------------------------------------------------------------------------- proc plw_view_scroll {w dx dy} { if {($dx != 0) && \ [winfo exists $w.hscroll] && [winfo ismapped $w.hscroll] } then { set first [lindex [$w.hscroll get] 2] $w.plwin xscroll [expr $first+$dx] } if {($dy != 0) && \ [winfo exists $w.vscroll] && [winfo ismapped $w.vscroll] } then { set first [lindex [$w.vscroll get] 2] $w.plwin yscroll [expr $first+$dy] } } #---------------------------------------------------------------------------- # plw_fixview # # Handles updates of scrollbars & plot after view change. #---------------------------------------------------------------------------- proc plw_fixview {w hscroll vscroll} { # Create scrollbars if they don't already exist. set created_sb 0 if { $hscroll && ! [winfo exists $w.hscroll] } then { set created_sb 1 scrollbar $w.hscroll -relief sunken -orient horiz \ -command "$w.plwin xscroll" $w.plwin config -xscroll "$w.hscroll set" } if { $vscroll && ! [winfo exists $w.vscroll] } then { set created_sb 1 scrollbar $w.vscroll -relief sunken \ -command "$w.plwin yscroll" $w.plwin config -yscroll "$w.vscroll set" } # When scrollbars are first created, it may be necessary to unmap then map # the plframe widget so that it has a chance to initialize the scrollbars # before they are mapped. if { $created_sb } then { pack unpack $w.plwin pack append $w $w.plwin {left expand fill} } # Map scrollbars if not already mapped. # To get packing right, need to unmap then remap plot widget. # Otherwise need to do explicit redraw. if { ($hscroll && ! [winfo ismapped $w.hscroll]) || \ ($vscroll && ! [winfo ismapped $w.vscroll]) } then { update pack unpack $w.plwin if { $hscroll } then { pack append $w $w.hscroll {bottom fillx} } if { $vscroll } then { pack append $w $w.vscroll {right filly} } pack append $w $w.plwin {expand fill} } else { $w.plwin redraw } } #---------------------------------------------------------------------------- # plw_update_view # # Updates view. Results in scrollbars being added if they are appropriate. # Does nothing if the plot window is unchanged from the default. #---------------------------------------------------------------------------- proc plw_update_view {w} { set coords [$w.plwin view] set xl [lindex "$coords" 0] set yl [lindex "$coords" 1] set xr [lindex "$coords" 2] set yr [lindex "$coords" 3] plw_view_select $w $xl $yl $xr $yr } #---------------------------------------------------------------------------- # status_msg # # Used for temporarily flashing a status message in the status bar. Better # than a dialog because it can be ignored and will go away on its own. #---------------------------------------------------------------------------- proc status_msg {w msg} { plw_label_set $w $msg after 2500 plw_label_reset $w } #---------------------------------------------------------------------------- # plw_label_reset # # Resets message in status bar to the default. #---------------------------------------------------------------------------- proc plw_label_reset {w} { $w.ftop.lstat configure -text " [string range $w 1 end]" } #---------------------------------------------------------------------------- # plw_label_set # # Sets message in status bar. #---------------------------------------------------------------------------- proc plw_label_set {w msg} { $w.ftop.lstat configure -text " $msg" } #---------------------------------------------------------------------------- # plw_user_mouse # # Passes buttonpress event information back to client. # Written by Radey Shouman #---------------------------------------------------------------------------- proc plw_user_mouse {w client button state x y} { # calculate relative window coordinates. set xw [expr "$x / [winfo width $w.plwin]."] set yw [expr "1.0 - $y / [winfo height $w.plwin]."] # calculate normalized device coordinates into original window. set view [$w.plwin view] set xrange [expr "[lindex $view 2] - [lindex $view 0]"] set xnd [expr "($xw * $xrange) + [lindex $view 0]"] set yrange [expr "[lindex $view 3] - [lindex $view 1]"] set ynd [expr "($yw * $yrange ) + [lindex $view 1]"] # send them back to the client. if { $client != "" } then { client_cmd [list $client] [list mouse $button $state $xnd $ynd] } } #---------------------------------------------------------------------------- # plw_dplink # # Initializes socket data link between widget and client code. # In addition, as this is the last client/server connection needed, I # disable further connections. #---------------------------------------------------------------------------- proc plw_dplink {w client} { global list_sock data_sock dp_Host + set rv [dp_connect -server 0] set list_sock [lindex $rv 0] set data_port [lindex $rv 1] dp_RDO $client set data_port $data_port set data_sock [lindex [dp_accept $list_sock] 0] $w.plwin openlink socket $data_sock dp_Host - }