source: trunk/gui/scripts/vtkstreamlinesviewer.tcl @ 3392

Last change on this file since 3392 was 3392, checked in by gah, 12 years ago

fixes for new stats file

File size: 90.5 KB
Line 
1# -*- mode: tcl; indent-tabs-mode: nil -*-
2# ----------------------------------------------------------------------
3#  COMPONENT: vtkviewer - Vtk drawing object viewer
4#
5#  It connects to the Vtk server running on a rendering farm,
6#  transmits data, and displays the results.
7# ======================================================================
8#  AUTHOR:  Michael McLennan, Purdue University
9#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
10#
11#  See the file "license.terms" for information on usage and
12#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13# ======================================================================
14package require Itk
15package require BLT
16package require Img
17
18option add *VtkStreamlinesViewer.width 4i widgetDefault
19option add *VtkStreamlinesViewer*cursor crosshair widgetDefault
20option add *VtkStreamlinesViewer.height 4i widgetDefault
21option add *VtkStreamlinesViewer.foreground black widgetDefault
22option add *VtkStreamlinesViewer.controlBackground gray widgetDefault
23option add *VtkStreamlinesViewer.controlDarkBackground #999999 widgetDefault
24option add *VtkStreamlinesViewer.plotBackground black widgetDefault
25option add *VtkStreamlinesViewer.plotForeground white widgetDefault
26option add *VtkStreamlinesViewer.font \
27    -*-helvetica-medium-r-normal-*-12-* widgetDefault
28
29# must use this name -- plugs into Rappture::resources::load
30proc VtkStreamlinesViewer_init_resources {} {
31    Rappture::resources::register \
32        vtkvis_server Rappture::VtkStreamlinesViewer::SetServerList
33}
34
35itcl::class Rappture::VtkStreamlinesViewer {
36    inherit Rappture::VisViewer
37
38    itk_option define -plotforeground plotForeground Foreground ""
39    itk_option define -plotbackground plotBackground Background ""
40
41    constructor { hostlist args } {
42        Rappture::VisViewer::constructor $hostlist
43    } {
44        # defined below
45    }
46    destructor {
47        # defined below
48    }
49    public proc SetServerList { namelist } {
50        Rappture::VisViewer::SetServerList "vtkvis" $namelist
51    }
52    public method add {dataobj {settings ""}}
53    public method camera {option args}
54    public method delete {args}
55    public method disconnect {}
56    public method download {option args}
57    public method get {args}
58    public method isconnected {}
59    public method limits { colormap }
60    public method sendto { string }
61    public method parameters {title args} {
62        # do nothing
63    }
64    public method scale {args}
65
66    protected method Connect {}
67    protected method CurrentDatasets {args}
68    protected method Disconnect {}
69    protected method DoResize {}
70    protected method DoReseed {}
71    protected method DoRotate {}
72    protected method AdjustSetting {what {value ""}}
73    protected method InitSettings { args  }
74    protected method Pan {option x y}
75    protected method Pick {x y}
76    protected method Rebuild {}
77    protected method ReceiveDataset { args }
78    protected method ReceiveImage { args }
79    protected method ReceiveLegend { colormap title vmin vmax size }
80    protected method Rotate {option x y}
81    protected method SendCmd {string}
82    protected method SendCmdNoSplash {string}
83    protected method Zoom {option}
84
85    # The following methods are only used by this class.
86    private method BuildAxisTab {}
87    private method BuildCameraTab {}
88    private method BuildColormap { name colors }
89    private method BuildCutplaneTab {}
90    private method BuildDownloadPopup { widget command }
91    private method BuildStreamsTab {}
92    private method BuildVolumeTab {}
93    private method ConvertToVtkData { dataobj comp }
94    private method DrawLegend { title }
95    private method Combo { option }
96    private method EnterLegend { x y }
97    private method EventuallyResize { w h }
98    private method EventuallyReseed { numPoints }
99    private method EventuallyRotate { q }
100    private method EventuallySetCutplane { axis args }
101    private method GetImage { args }
102    private method GetVtkData { args }
103    private method IsValidObject { dataobj }
104    private method LeaveLegend {}
105    private method MotionLegend { x y }
106    private method PanCamera {}
107    private method RequestLegend {}
108    private method SetColormap { dataobj comp }
109    private method ChangeColormap { dataobj comp color }
110    private method SetLegendTip { x y }
111    private method SetObjectStyle { dataobj comp }
112    private method Slice {option args}
113
114    private variable _arcball ""
115    private variable _outbuf       ;    # buffer for outgoing commands
116
117    private variable _dlist ""     ;    # list of data objects
118    private variable _obj2datasets
119    private variable _obj2ovride   ;    # maps dataobj => style override
120    private variable _datasets     ;    # contains all the dataobj-component
121                                   ;    # datasets in the server
122    private variable _colormaps    ;    # contains all the colormaps
123                                   ;    # in the server.
124    private variable _dataset2style    ;# maps dataobj-component to transfunc
125
126    private variable _click        ;    # info used for rotate operations
127    private variable _limits       ;    # autoscale min/max for all axes
128    private variable _view         ;    # view params for 3D view
129    private variable _settings
130    private variable _style;            # Array of current component styles.
131    private variable _initialStyle;     # Array of initial component styles.
132    private variable _reset 1;          # indicates if camera needs to be reset
133                                        # to starting position.
134
135    private variable _first ""     ;    # This is the topmost dataset.
136    private variable _start 0
137    private variable _buffering 0
138    private variable _title ""
139    private variable _seeds
140
141    common _downloadPopup;              # download options from popup
142    private common _hardcopy
143    private variable _width 0
144    private variable _height 0
145    private variable _resizePending 0
146    private variable _reseedPending 0
147    private variable _rotatePending 0
148    private variable _cutplanePending 0
149    private variable _legendPending 0
150    private variable _outline
151    private variable _vectorFields
152    private variable _scalarFields
153    private variable _fields
154    private variable _currentField ""
155    private variable _field      ""
156    private variable _numSeeds 200
157    private variable _colorMode "vmag";#  Mode of colormap (vmag or scalar)
158}
159
160itk::usual VtkStreamlinesViewer {
161    keep -background -foreground -cursor -font
162    keep -plotbackground -plotforeground
163}
164
165# ----------------------------------------------------------------------
166# CONSTRUCTOR
167# ----------------------------------------------------------------------
168itcl::body Rappture::VtkStreamlinesViewer::constructor {hostlist args} {
169    package require vtk
170    set _serverType "vtkvis"
171
172    # Rebuild event
173    $_dispatcher register !rebuild
174    $_dispatcher dispatch $this !rebuild "[itcl::code $this Rebuild]; list"
175
176    # Resize event
177    $_dispatcher register !resize
178    $_dispatcher dispatch $this !resize "[itcl::code $this DoResize]; list"
179
180    # Reseed event
181    $_dispatcher register !reseed
182    $_dispatcher dispatch $this !reseed "[itcl::code $this DoReseed]; list"
183
184    # Rotate event
185    $_dispatcher register !rotate
186    $_dispatcher dispatch $this !rotate "[itcl::code $this DoRotate]; list"
187
188    # Legend event
189    $_dispatcher register !legend
190    $_dispatcher dispatch $this !legend "[itcl::code $this RequestLegend]; list"
191
192    # X-Cutplane event
193    $_dispatcher register !xcutplane
194    $_dispatcher dispatch $this !xcutplane \
195        "[itcl::code $this AdjustSetting cutplaneXPosition]; list"
196
197    # Y-Cutplane event
198    $_dispatcher register !ycutplane
199    $_dispatcher dispatch $this !ycutplane \
200        "[itcl::code $this AdjustSetting cutplaneYPosition]; list"
201
202    # Z-Cutplane event
203    $_dispatcher register !zcutplane
204    $_dispatcher dispatch $this !zcutplane \
205        "[itcl::code $this AdjustSetting cutplaneZPosition]; list"
206
207    #
208    # Populate parser with commands handle incoming requests
209    #
210    $_parser alias image [itcl::code $this ReceiveImage]
211    $_parser alias dataset [itcl::code $this ReceiveDataset]
212    $_parser alias legend [itcl::code $this ReceiveLegend]
213
214    array set _outline {
215        id -1
216        afterId -1
217        x1 -1
218        y1 -1
219        x2 -1
220        y2 -1
221    }
222    # Initialize the view to some default parameters.
223    array set _view {
224        qw              0.853553
225        qx              -0.353553
226        qy              0.353553
227        qz              0.146447
228        zoom            1.0
229        xpan            0
230        ypan            0
231        ortho           0
232    }
233    set _arcball [blt::arcball create 100 100]
234    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
235    $_arcball quaternion $q
236
237    set _limits(zmin) 0.0
238    set _limits(zmax) 1.0
239
240    array set _settings [subst {
241        axesVisible             1
242        axisLabelsVisible       1
243        axisXGrid               0
244        axisYGrid               0
245        axisZGrid               0
246        cutplaneEdges           0
247        cutplaneLighting        1
248        cutplaneOpacity         100
249        cutplaneVisible         0
250        cutplaneWireframe       0
251        cutplaneXPosition       50
252        cutplaneXVisible        1
253        cutplaneYPosition       50
254        cutplaneYVisible        1
255        cutplaneZPosition       50
256        cutplaneZVisible        1
257        legendVisible           1
258        streamlinesLighting     1
259        streamlinesMode         lines
260        streamlinesNumSeeds     200
261        streamlinesOpacity      100
262        streamlinesScale        1
263        streamlinesSeedsVisible 0
264        streamlinesVisible      1
265        volumeEdges             0
266        volumeLighting          1
267        volumeOpacity           40
268        volumeVisible           1
269        volumeWireframe         0
270    }]
271
272    itk_component add view {
273        canvas $itk_component(plotarea).view \
274            -highlightthickness 0 -borderwidth 0
275    } {
276        usual
277        ignore -highlightthickness -borderwidth  -background
278    }
279
280    itk_component add fieldmenu {
281        menu $itk_component(plotarea).menu -bg black -fg white -relief flat \
282            -tearoff no
283    } {
284        usual
285        ignore -background -foreground -relief -tearoff
286    }
287    set c $itk_component(view)
288    bind $c <Configure> [itcl::code $this EventuallyResize %w %h]
289    bind $c <4> [itcl::code $this Zoom in 0.25]
290    bind $c <5> [itcl::code $this Zoom out 0.25]
291    bind $c <KeyPress-Left>  [list %W xview scroll 10 units]
292    bind $c <KeyPress-Right> [list %W xview scroll -10 units]
293    bind $c <KeyPress-Up>    [list %W yview scroll 10 units]
294    bind $c <KeyPress-Down>  [list %W yview scroll -10 units]
295    bind $c <Enter> "focus %W"
296    bind $c <Control-F1> [itcl::code $this ToggleConsole]
297
298    # Fix the scrollregion in case we go off screen
299    $c configure -scrollregion [$c bbox all]
300
301    set _map(id) [$c create image 0 0 -anchor nw -image $_image(plot)]
302    set _map(cwidth) -1
303    set _map(cheight) -1
304    set _map(zoom) 1.0
305    set _map(original) ""
306
307    set f [$itk_component(main) component controls]
308    itk_component add reset {
309        button $f.reset -borderwidth 1 -padx 1 -pady 1 \
310            -highlightthickness 0 \
311            -image [Rappture::icon reset-view] \
312            -command [itcl::code $this Zoom reset]
313    } {
314        usual
315        ignore -highlightthickness
316    }
317    pack $itk_component(reset) -side top -padx 2 -pady 2
318    Rappture::Tooltip::for $itk_component(reset) "Reset the view to the default zoom level"
319
320    itk_component add zoomin {
321        button $f.zin -borderwidth 1 -padx 1 -pady 1 \
322            -highlightthickness 0 \
323            -image [Rappture::icon zoom-in] \
324            -command [itcl::code $this Zoom in]
325    } {
326        usual
327        ignore -highlightthickness
328    }
329    pack $itk_component(zoomin) -side top -padx 2 -pady 2
330    Rappture::Tooltip::for $itk_component(zoomin) "Zoom in"
331
332    itk_component add zoomout {
333        button $f.zout -borderwidth 1 -padx 1 -pady 1 \
334            -highlightthickness 0 \
335            -image [Rappture::icon zoom-out] \
336            -command [itcl::code $this Zoom out]
337    } {
338        usual
339        ignore -highlightthickness
340    }
341    pack $itk_component(zoomout) -side top -padx 2 -pady 2
342    Rappture::Tooltip::for $itk_component(zoomout) "Zoom out"
343
344    itk_component add volume {
345        Rappture::PushButton $f.volume \
346            -onimage [Rappture::icon volume-on] \
347            -offimage [Rappture::icon volume-off] \
348            -variable [itcl::scope _settings(volumeVisible)] \
349            -command [itcl::code $this AdjustSetting volumeVisible]
350    }
351    $itk_component(volume) select
352    Rappture::Tooltip::for $itk_component(volume) \
353        "Don't display the volume"
354    pack $itk_component(volume) -padx 2 -pady 2
355
356    itk_component add streamlines {
357        Rappture::PushButton $f.streamlines \
358            -onimage [Rappture::icon streamlines-on] \
359            -offimage [Rappture::icon streamlines-off] \
360            -variable [itcl::scope _settings(streamlinesVisible)] \
361            -command [itcl::code $this AdjustSetting streamlinesVisible] \
362    }
363    $itk_component(streamlines) select
364    Rappture::Tooltip::for $itk_component(streamlines) \
365        "Toggle the streamlines on/off"
366    pack $itk_component(streamlines) -padx 2 -pady 2
367
368    itk_component add cutplane {
369        Rappture::PushButton $f.cutplane \
370            -onimage [Rappture::icon cutbutton] \
371            -offimage [Rappture::icon cutbutton] \
372            -variable [itcl::scope _settings(cutplaneVisible)] \
373            -command [itcl::code $this AdjustSetting cutplaneVisible]
374    }
375    Rappture::Tooltip::for $itk_component(cutplane) \
376        "Show/Hide cutplanes"
377    pack $itk_component(cutplane) -padx 2 -pady 2
378
379
380    if { [catch {
381        BuildVolumeTab
382        BuildStreamsTab
383        BuildCutplaneTab
384        BuildAxisTab
385        BuildCameraTab
386    } errs] != 0 } {
387        puts stderr errs=$errs
388    }
389    # Legend
390
391    set _image(legend) [image create photo]
392    itk_component add legend {
393        canvas $itk_component(plotarea).legend -width 50 -highlightthickness 0
394    } {
395        usual
396        ignore -highlightthickness
397        rename -background -plotbackground plotBackground Background
398    }
399
400    # Hack around the Tk panewindow.  The problem is that the requested
401    # size of the 3d view isn't set until an image is retrieved from
402    # the server.  So the panewindow uses the tiny size.
403    set w 10000
404    pack forget $itk_component(view)
405    blt::table $itk_component(plotarea) \
406        0,0 $itk_component(view) -fill both -reqwidth $w
407    blt::table configure $itk_component(plotarea) c1 -resize none
408
409    # Bindings for rotation via mouse
410    bind $itk_component(view) <ButtonPress-1> \
411        [itcl::code $this Rotate click %x %y]
412    bind $itk_component(view) <B1-Motion> \
413        [itcl::code $this Rotate drag %x %y]
414    bind $itk_component(view) <ButtonRelease-1> \
415        [itcl::code $this Rotate release %x %y]
416    bind $itk_component(view) <Configure> \
417        [itcl::code $this EventuallyResize %w %h]
418
419    if 0 {
420    bind $itk_component(view) <Configure> \
421        [itcl::code $this EventuallyResize %w %h]
422    }
423    # Bindings for panning via mouse
424    bind $itk_component(view) <ButtonPress-2> \
425        [itcl::code $this Pan click %x %y]
426    bind $itk_component(view) <B2-Motion> \
427        [itcl::code $this Pan drag %x %y]
428    bind $itk_component(view) <ButtonRelease-2> \
429        [itcl::code $this Pan release %x %y]
430
431    bind $itk_component(view) <ButtonRelease-3> \
432        [itcl::code $this Pick %x %y]
433
434    # Bindings for panning via keyboard
435    bind $itk_component(view) <KeyPress-Left> \
436        [itcl::code $this Pan set -10 0]
437    bind $itk_component(view) <KeyPress-Right> \
438        [itcl::code $this Pan set 10 0]
439    bind $itk_component(view) <KeyPress-Up> \
440        [itcl::code $this Pan set 0 -10]
441    bind $itk_component(view) <KeyPress-Down> \
442        [itcl::code $this Pan set 0 10]
443    bind $itk_component(view) <Shift-KeyPress-Left> \
444        [itcl::code $this Pan set -2 0]
445    bind $itk_component(view) <Shift-KeyPress-Right> \
446        [itcl::code $this Pan set 2 0]
447    bind $itk_component(view) <Shift-KeyPress-Up> \
448        [itcl::code $this Pan set 0 -2]
449    bind $itk_component(view) <Shift-KeyPress-Down> \
450        [itcl::code $this Pan set 0 2]
451
452    # Bindings for zoom via keyboard
453    bind $itk_component(view) <KeyPress-Prior> \
454        [itcl::code $this Zoom out]
455    bind $itk_component(view) <KeyPress-Next> \
456        [itcl::code $this Zoom in]
457
458    bind $itk_component(view) <Enter> "focus $itk_component(view)"
459
460    if {[string equal "x11" [tk windowingsystem]]} {
461        # Bindings for zoom via mouse
462        bind $itk_component(view) <4> [itcl::code $this Zoom out]
463        bind $itk_component(view) <5> [itcl::code $this Zoom in]
464    }
465
466    set _image(download) [image create photo]
467
468    eval itk_initialize $args
469    Connect
470    update
471}
472
473# ----------------------------------------------------------------------
474# DESTRUCTOR
475# ----------------------------------------------------------------------
476itcl::body Rappture::VtkStreamlinesViewer::destructor {} {
477    Disconnect
478    image delete $_image(plot)
479    image delete $_image(download)
480    catch { blt::arcball destroy $_arcball }
481}
482
483itcl::body Rappture::VtkStreamlinesViewer::DoResize {} {
484    if { $_width < 2 } {
485        set _width 500
486    }
487    if { $_height < 2 } {
488        set _height 500
489    }
490    set _start [clock clicks -milliseconds]
491    SendCmd "screen size $_width $_height"
492    set _legendPending 1
493
494    #SendCmd "imgflush"
495
496    # Must reset camera to have object scaling to take effect.
497    #SendCmd "camera reset"
498    #SendCmd "camera zoom $_view(zoom)"
499    set _resizePending 0
500}
501
502itcl::body Rappture::VtkStreamlinesViewer::DoRotate {} {
503    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
504    SendCmd "camera orient $q"
505    set _rotatePending 0
506}
507
508itcl::body Rappture::VtkStreamlinesViewer::DoReseed {} {
509    foreach dataset [CurrentDatasets -visible] {
510        foreach {dataobj comp} [split $dataset -] break
511        # This command works for either random or fmesh seeds
512        SendCmd "streamlines seed numpts $_numSeeds $dataset"
513    }
514    set _reseedPending 0
515}
516
517itcl::body Rappture::VtkStreamlinesViewer::EventuallyResize { w h } {
518    set _width $w
519    set _height $h
520    $_arcball resize $w $h
521    if { !$_resizePending } {
522        set _resizePending 1
523        $_dispatcher event -after 400 !resize
524    }
525}
526
527itcl::body Rappture::VtkStreamlinesViewer::EventuallyReseed { numPoints } {
528    set _numSeeds $numPoints
529    if { !$_reseedPending } {
530        set _reseedPending 1
531        $_dispatcher event -after 600 !reseed
532    }
533}
534
535set rotate_delay 100
536
537itcl::body Rappture::VtkStreamlinesViewer::EventuallyRotate { q } {
538    foreach { _view(qw) _view(qx) _view(qy) _view(qz) } $q break
539    if { !$_rotatePending } {
540        set _rotatePending 1
541        global rotate_delay
542        $_dispatcher event -after $rotate_delay !rotate
543    }
544}
545
546itcl::body Rappture::VtkStreamlinesViewer::EventuallySetCutplane { axis args } {
547    if { !$_cutplanePending } {
548        set _cutplanePending 1
549        $_dispatcher event -after 100 !${axis}cutplane
550    }
551}
552
553# ----------------------------------------------------------------------
554# USAGE: add <dataobj> ?<settings>?
555#
556# Clients use this to add a data object to the plot.  The optional
557# <settings> are used to configure the plot.  Allowed settings are
558# -color, -brightness, -width, -linestyle, and -raise.
559# ----------------------------------------------------------------------
560itcl::body Rappture::VtkStreamlinesViewer::add {dataobj {settings ""}} {
561    array set params {
562        -color auto
563        -width 1
564        -linestyle solid
565        -brightness 0
566        -raise 0
567        -description ""
568        -param ""
569        -type ""
570    }
571    array set params $settings
572    set params(-description) ""
573    set params(-param) ""
574    foreach {opt val} $settings {
575        if {![info exists params($opt)]} {
576            error "bad setting \"$opt\": should be [join [lsort [array names params]] {, }]"
577        }
578        set params($opt) $val
579    }
580    if {$params(-color) == "auto" || $params(-color) == "autoreset"} {
581        # can't handle -autocolors yet
582        set params(-color) black
583    }
584    set pos [lsearch -exact $dataobj $_dlist]
585    if {$pos < 0} {
586        lappend _dlist $dataobj
587    }
588    set _obj2ovride($dataobj-color) $params(-color)
589    set _obj2ovride($dataobj-width) $params(-width)
590    set _obj2ovride($dataobj-raise) $params(-raise)
591    $_dispatcher event -idle !rebuild
592}
593
594
595# ----------------------------------------------------------------------
596# USAGE: delete ?<dataobj1> <dataobj2> ...?
597#
598#       Clients use this to delete a dataobj from the plot.  If no dataobjs
599#       are specified, then all dataobjs are deleted.  No data objects are
600#       deleted.  They are only removed from the display list.
601#
602# ----------------------------------------------------------------------
603itcl::body Rappture::VtkStreamlinesViewer::delete {args} {
604    if { [llength $args] == 0} {
605        set args $_dlist
606    }
607    # Delete all specified dataobjs
608    set changed 0
609    foreach dataobj $args {
610        set pos [lsearch -exact $_dlist $dataobj]
611        if { $pos < 0 } {
612            continue;                   # Don't know anything about it.
613        }
614        # Remove it from the dataobj list.
615        set _dlist [lreplace $_dlist $pos $pos]
616        SendCmd "dataset visible 0"
617        array unset _obj2ovride $dataobj-*
618        array unset _settings $dataobj-*
619        # Append to the end of the dataobj list.
620        lappend _dlist $dataobj
621        set changed 1
622    }
623    # If anything changed, then rebuild the plot
624    if { $changed } {
625        $_dispatcher event -idle !rebuild
626    }
627}
628
629# ----------------------------------------------------------------------
630# USAGE: get ?-objects?
631# USAGE: get ?-visible?
632# USAGE: get ?-image view?
633#
634# Clients use this to query the list of objects being plotted, in
635# order from bottom to top of this result.  The optional "-image"
636# flag can also request the internal images being shown.
637# ----------------------------------------------------------------------
638itcl::body Rappture::VtkStreamlinesViewer::get {args} {
639    if {[llength $args] == 0} {
640        set args "-objects"
641    }
642
643    set op [lindex $args 0]
644    switch -- $op {
645        "-objects" {
646            # put the dataobj list in order according to -raise options
647            set dlist {}
648            foreach dataobj $_dlist {
649                if { ![IsValidObject $dataobj] } {
650                    continue
651                }
652                if {[info exists _obj2ovride($dataobj-raise)] &&
653                    $_obj2ovride($dataobj-raise)} {
654                    set dlist [linsert $dlist 0 $dataobj]
655                } else {
656                    lappend dlist $dataobj
657                }
658            }
659            return $dlist
660        }
661        "-visible" {
662            set dlist {}
663            foreach dataobj $_dlist {
664                if { ![IsValidObject $dataobj] } {
665                    continue
666                }
667                if { ![info exists _obj2ovride($dataobj-raise)] } {
668                    # No setting indicates that the object isn't visible.
669                    continue
670                }
671                # Otherwise use the -raise parameter to put the object to
672                # the front of the list.
673                if { $_obj2ovride($dataobj-raise) } {
674                    set dlist [linsert $dlist 0 $dataobj]
675                } else {
676                    lappend dlist $dataobj
677                }
678            }
679            return $dlist
680        }           
681        -image {
682            if {[llength $args] != 2} {
683                error "wrong # args: should be \"get -image view\""
684            }
685            switch -- [lindex $args end] {
686                view {
687                    return $_image(plot)
688                }
689                default {
690                    error "bad image name \"[lindex $args end]\": should be view"
691                }
692            }
693        }
694        default {
695            error "bad option \"$op\": should be -objects or -image"
696        }
697    }
698}
699
700# ----------------------------------------------------------------------
701# USAGE: scale ?<data1> <data2> ...?
702#
703# Sets the default limits for the overall plot according to the
704# limits of the data for all of the given <data> objects.  This
705# accounts for all objects--even those not showing on the screen.
706# Because of this, the limits are appropriate for all objects as
707# the user scans through data in the ResultSet viewer.
708# ----------------------------------------------------------------------
709itcl::body Rappture::VtkStreamlinesViewer::scale {args} {
710    array unset _limits
711    foreach dataobj $args {
712        set string [limits $dataobj]
713        if { $string == "" } {
714            continue
715        }
716        array set bounds $string
717        if {![info exists _limits(xmin)] || $_limits(xmin) > $bounds(xmin)} {
718            set _limits(xmin) $bounds(xmin)
719        }
720        if {![info exists _limits(xmax)] || $_limits(xmax) < $bounds(xmax)} {
721            set _limits(xmax) $bounds(xmax)
722        }
723
724        if {![info exists _limits(ymin)] || $_limits(ymin) > $bounds(ymin)} {
725            set _limits(ymin) $bounds(ymin)
726        }
727        if {![info exists _limits(ymax)] || $_limits(ymax) < $bounds(ymax)} {
728            set _limits(ymax) $bounds(ymax)
729        }
730
731        if {![info exists _limits(zmin)] || $_limits(zmin) > $bounds(zmin)} {
732            set _limits(zmin) $bounds(zmin)
733        }
734        if {![info exists _limits(zmax)] || $_limits(zmax) < $bounds(zmax)} {
735            set _limits(zmax) $bounds(zmax)
736        }
737    }
738}
739
740# ----------------------------------------------------------------------
741# USAGE: download coming
742# USAGE: download controls <downloadCommand>
743# USAGE: download now
744#
745# Clients use this method to create a downloadable representation
746# of the plot.  Returns a list of the form {ext string}, where
747# "ext" is the file extension (indicating the type of data) and
748# "string" is the data itself.
749# ----------------------------------------------------------------------
750itcl::body Rappture::VtkStreamlinesViewer::download {option args} {
751    switch $option {
752        coming {
753            if {[catch {
754                blt::winop snap $itk_component(plotarea) $_image(download)
755            }]} {
756                $_image(download) configure -width 1 -height 1
757                $_image(download) put #000000
758            }
759        }
760        controls {
761            set popup .vtkviewerdownload
762            if { ![winfo exists .vtkviewerdownload] } {
763                set inner [BuildDownloadPopup $popup [lindex $args 0]]
764            } else {
765                set inner [$popup component inner]
766            }
767            set _downloadPopup(image_controls) $inner.image_frame
768            set num [llength [get]]
769            set num [expr {($num == 1) ? "1 result" : "$num results"}]
770            set word [Rappture::filexfer::label downloadWord]
771            $inner.summary configure -text "$word $num in the following format:"
772            update idletasks            ;# Fix initial sizes
773            return $popup
774        }
775        now {
776            set popup .vtkviewerdownload
777            if {[winfo exists .vtkviewerdownload]} {
778                $popup deactivate
779            }
780            switch -- $_downloadPopup(format) {
781                "image" {
782                    return [$this GetImage [lindex $args 0]]
783                }
784                "vtk" {
785                    return [$this GetVtkData [lindex $args 0]]
786                }
787            }
788            return ""
789        }
790        default {
791            error "bad option \"$option\": should be coming, controls, now"
792        }
793    }
794}
795
796# ----------------------------------------------------------------------
797# USAGE: Connect ?<host:port>,<host:port>...?
798#
799# Clients use this method to establish a connection to a new
800# server, or to reestablish a connection to the previous server.
801# Any existing connection is automatically closed.
802# ----------------------------------------------------------------------
803itcl::body Rappture::VtkStreamlinesViewer::Connect {} {
804    set _hosts [GetServerList "vtkvis"]
805    if { "" == $_hosts } {
806        return 0
807    }
808    set result [VisViewer::Connect $_hosts]
809    if { $result } {
810        set w [winfo width $itk_component(view)]
811        set h [winfo height $itk_component(view)]
812        EventuallyResize $w $h
813    }
814    return $result
815}
816
817#
818# isconnected --
819#
820#       Indicates if we are currently connected to the visualization server.
821#
822itcl::body Rappture::VtkStreamlinesViewer::isconnected {} {
823    return [VisViewer::IsConnected]
824}
825
826#
827# disconnect --
828#
829itcl::body Rappture::VtkStreamlinesViewer::disconnect {} {
830    Disconnect
831    set _reset 1
832}
833
834#
835# Disconnect --
836#
837#       Clients use this method to disconnect from the current rendering
838#       server.
839#
840itcl::body Rappture::VtkStreamlinesViewer::Disconnect {} {
841    VisViewer::Disconnect
842
843    $_dispatcher cancel !rebuild
844    $_dispatcher cancel !resize
845    $_dispatcher cancel !reseed
846    $_dispatcher cancel !rotate
847    $_dispatcher cancel !xcutplane
848    $_dispatcher cancel !ycutplane
849    $_dispatcher cancel !zcutplane
850    $_dispatcher cancel !legend
851    # disconnected -- no more data sitting on server
852    set _outbuf ""
853    array unset _datasets
854    array unset _data
855    array unset _colormaps
856    array unset _seeds
857    array unset _dataset2style
858    array unset _obj2datasets
859}
860
861#
862# sendto --
863#
864itcl::body Rappture::VtkStreamlinesViewer::sendto { bytes } {
865    SendBytes "$bytes\n"
866    StartWaiting
867}
868
869#
870# SendCmd
871#
872#       Send commands off to the rendering server.  If we're currently
873#       sending data objects to the server, buffer the commands to be
874#       sent later.
875#
876itcl::body Rappture::VtkStreamlinesViewer::SendCmd {string} {
877    if { $_buffering } {
878        append _outbuf $string "\n"
879    } else {
880        SendBytes "$string\n"
881        StartWaiting
882    }
883}
884
885#
886# SendCmdNoSplash
887#
888#       Send commands off to the rendering server.  This method
889#       doesn't initiate the slash screen.
890#
891itcl::body Rappture::VtkStreamlinesViewer::SendCmdNoSplash {string} {
892    if { $_buffering } {
893        append _outbuf $string "\n"
894    } else {
895        SendBytes "$string\n"
896    }
897}
898
899# ----------------------------------------------------------------------
900# USAGE: ReceiveImage -bytes <size> -type <type> -token <token>
901#
902# Invoked automatically whenever the "image" command comes in from
903# the rendering server.  Indicates that binary image data with the
904# specified <size> will follow.
905# ----------------------------------------------------------------------
906itcl::body Rappture::VtkStreamlinesViewer::ReceiveImage { args } {
907    array set info {
908        -token "???"
909        -bytes 0
910        -type image
911    }
912    array set info $args
913    set bytes [ReceiveBytes $info(-bytes)]
914    StopWaiting
915    if { $info(-type) == "image" } {
916        if 0 {
917            set f [open "last.ppm" "w"]
918            puts $f $bytes
919            close $f
920        }
921        $_image(plot) configure -data $bytes
922        set time [clock seconds]
923        set date [clock format $time]
924        #puts stderr "$date: received image [image width $_image(plot)]x[image height $_image(plot)] image>"       
925        if { $_start > 0 } {
926            set finish [clock clicks -milliseconds]
927            #puts stderr "round trip time [expr $finish -$_start] milliseconds"
928            set _start 0
929        }
930    } elseif { $info(type) == "print" } {
931        set tag $this-print-$info(-token)
932        set _hardcopy($tag) $bytes
933    }
934    if { $_legendPending } {
935        RequestLegend
936    }
937}
938
939#
940# ReceiveDataset --
941#
942itcl::body Rappture::VtkStreamlinesViewer::ReceiveDataset { args } {
943    if { ![isconnected] } {
944        return
945    }
946    set option [lindex $args 0]
947    switch -- $option {
948        "scalar" {
949            set option [lindex $args 1]
950            switch -- $option {
951                "world" {
952                    foreach { x y z value tag } [lrange $args 2 end] break
953                }
954                "pixel" {
955                    foreach { x y value tag } [lrange $args 2 end] break
956                }
957            }
958        }
959        "vector" {
960            set option [lindex $args 1]
961            switch -- $option {
962                "world" {
963                    foreach { x y z vx vy vz tag } [lrange $args 2 end] break
964                }
965                "pixel" {
966                    foreach { x y vx vy vz tag } [lrange $args 2 end] break
967                }
968            }
969        }
970        "names" {
971            foreach { name } [lindex $args 1] {
972                #puts stderr "Dataset: $name"
973            }
974        }
975        default {
976            error "unknown dataset option \"$option\" from server"
977        }
978    }
979}
980
981# ----------------------------------------------------------------------
982# USAGE: Rebuild
983#
984# Called automatically whenever something changes that affects the
985# data in the widget.  Clears any existing data and rebuilds the
986# widget to display new data.
987# ----------------------------------------------------------------------
988itcl::body Rappture::VtkStreamlinesViewer::Rebuild {} {
989    update
990    set w [winfo width $itk_component(view)]
991    set h [winfo height $itk_component(view)]
992    if { $w < 2 || $h < 2 } {
993        $_dispatcher event -idle !rebuild
994        return
995    }
996
997    set _buffering 1
998    set _legendPending 1
999    # Turn on buffering of commands to the server.  We don't want to
1000    # be preempted by a server disconnect/reconnect (which automatically
1001    # generates a new call to Rebuild).   
1002
1003    set _first ""
1004    if { $_reset } {
1005        if 1 {
1006            # Tell the server the name of the tool, the version, and dataset
1007            # that we are rendering.  Have to do it here because we don't know
1008            # what data objects are using the renderer until be get here.
1009            global env
1010
1011            set info {}
1012            set user "???"
1013            if { [info exists env(USER)] } {
1014                set user $env(USER)
1015            }
1016            set session "???"
1017            if { [info exists env(SESSION)] } {
1018                set session $env(SESSION)
1019            }
1020            lappend info "hub" [exec hostname]
1021            lappend info "client" "vtkstreamlinesviewer"
1022            lappend info "user" $user
1023            lappend info "session" $session
1024            SendCmd "clientinfo [list $info]"
1025        }
1026        set _width $w
1027        set _height $h
1028        $_arcball resize $w $h
1029        DoResize
1030        InitSettings axisXGrid axisYGrid axisZGrid axis-mode \
1031            axesVisible axisLabelsVisible \
1032    }
1033    #SendCmd "imgflush"
1034
1035    set _limits(zmin) ""
1036    set _limits(zmax) ""
1037    set _first ""
1038    foreach dataobj [get -objects] {
1039        if { [info exists _obj2ovride($dataobj-raise)] &&  $_first == "" } {
1040            set _first $dataobj
1041        }
1042        set _obj2datasets($dataobj) ""
1043        foreach comp [$dataobj components] {
1044            set tag $dataobj-$comp
1045            if { ![info exists _datasets($tag)] } {
1046                set bytes [$dataobj vtkdata $comp]
1047                set length [string length $bytes]
1048                if 1 {
1049                    set info {}
1050                    lappend info "tool_id"       [$dataobj hints toolId]
1051                    lappend info "tool_name"     [$dataobj hints toolName]
1052                    lappend info "tool_version"  [$dataobj hints toolRevision]
1053                    lappend info "tool_title"    [$dataobj hints toolTitle]
1054                    lappend info "dataset_label" [$dataobj hints label]
1055                    lappend info "dataset_size"  $length
1056                    SendCmd "clientinfo [list $info]"
1057                }
1058                append _outbuf "dataset add $tag data follows $length\n"
1059                append _outbuf $bytes
1060                set _datasets($tag) 1
1061                SetObjectStyle $dataobj $comp
1062            }
1063            lappend _obj2datasets($dataobj) $tag
1064            if { [info exists _obj2ovride($dataobj-raise)] } {
1065                SendCmd "dataset visible 1 $tag"
1066            } else {
1067                SendCmd "dataset visible 0 $tag"
1068            }
1069        }
1070    }
1071    if {"" != $_first} {
1072        set location [$_first hints camera]
1073        if { $location != "" } {
1074            array set view $location
1075        }
1076        foreach axis { x y z } {
1077            set label [$_first hints ${axis}label]
1078            if { $label != "" } {
1079                SendCmd "axis name $axis $label"
1080            }
1081            set units [$_first hints ${axis}units]
1082            if { $units != "" } {
1083                SendCmd "axis units $axis $units"
1084            }
1085        }
1086        array unset _scalarFields
1087        array unset _vectorFields
1088        set _currentField [$_first hints default]
1089        $itk_component(field) choices delete 0 end
1090        $itk_component(fieldmenu) delete 0 end
1091        array unset _fields
1092        foreach { name title units } [$_first hints vectors] {
1093            set _vectorFields($title) $name
1094            $itk_component(field) choices insert end "$name" "$title"
1095            $itk_component(fieldmenu) add radiobutton -label "$title" \
1096                -value $title -variable [itcl::scope _currentField] \
1097                -selectcolor red \
1098                -activebackground black \
1099                -activeforeground white \
1100                -font "Arial 8" \
1101                -command [itcl::code $this Combo invoke]
1102            set _fields($name) [list $title $units]
1103        }
1104        foreach { name title units } [$_first hints scalars] {
1105            set _scalarFields($title) $name
1106            $itk_component(field) choices insert end "$name" "$title"
1107            $itk_component(fieldmenu) add radiobutton -label "$title" \
1108                -value $title -variable [itcl::scope _currentField] \
1109                -selectcolor red \
1110                -activebackground black \
1111                -activeforeground white \
1112                -font "Arial 8" \
1113                -command [itcl::code $this Combo invoke]
1114            set _fields($name) [list $title $units]
1115        }
1116        $itk_component(field) value $_currentField
1117    }
1118
1119    InitSettings streamlinesVisible streamlines-palette volumeVisible
1120
1121    if { $_reset } {
1122        InitSettings streamlinesSeedsVisible streamlinesOpacity \
1123            streamlinesNumSeeds streamlinesLighting \
1124            streamlines-palette streamlines-field \
1125            volumeEdges volumeLighting volumeOpacity volumeWireframe \
1126            cutplaneVisible \
1127            cutplaneXPosition cutplaneYPosition cutplaneZPosition \
1128            cutplaneXVisible cutplaneYVisible cutplaneZVisible
1129        #
1130        # Reset the camera and other view parameters
1131        #
1132        set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
1133        $_arcball quaternion $q
1134        if {$_view(ortho)} {
1135            SendCmd "camera mode ortho"
1136        } else {
1137            SendCmd "camera mode persp"
1138        }
1139        DoRotate
1140        PanCamera
1141        Zoom reset
1142        set _reset 0
1143    }
1144    set _buffering 0;                        # Turn off buffering.
1145
1146    # Actually write the commands to the server socket.  If it fails, we don't
1147    # care.  We're finished here.
1148    blt::busy hold $itk_component(hull)
1149    sendto $_outbuf;                       
1150    blt::busy release $itk_component(hull)
1151    set _outbuf "";                        # Clear the buffer.               
1152}
1153
1154# ----------------------------------------------------------------------
1155# USAGE: CurrentDatasets ?-all -visible? ?dataobjs?
1156#
1157# Returns a list of server IDs for the current datasets being displayed.  This
1158# is normally a single ID, but it might be a list of IDs if the current data
1159# object has multiple components.
1160# ----------------------------------------------------------------------
1161itcl::body Rappture::VtkStreamlinesViewer::CurrentDatasets {args} {
1162    set flag [lindex $args 0]
1163    switch -- $flag {
1164        "-all" {
1165            if { [llength $args] > 1 } {
1166                error "CurrentDatasets: can't specify dataobj after \"-all\""
1167            }
1168            set dlist [get -objects]
1169        }
1170        "-visible" {
1171            if { [llength $args] > 1 } {
1172                set dlist {}
1173                set args [lrange $args 1 end]
1174                foreach dataobj $args {
1175                    if { [info exists _obj2ovride($dataobj-raise)] } {
1176                        lappend dlist $dataobj
1177                    }
1178                }
1179            } else {
1180                set dlist [get -visible]
1181            }
1182        }           
1183        default {
1184            set dlist $args
1185        }
1186    }
1187    set rlist ""
1188    foreach dataobj $dlist {
1189        foreach comp [$dataobj components] {
1190            set tag $dataobj-$comp
1191            if { [info exists _datasets($tag)] && $_datasets($tag) } {
1192                lappend rlist $tag
1193            }
1194        }
1195    }
1196    return $rlist
1197}
1198
1199# ----------------------------------------------------------------------
1200# USAGE: Zoom in
1201# USAGE: Zoom out
1202# USAGE: Zoom reset
1203#
1204# Called automatically when the user clicks on one of the zoom
1205# controls for this widget.  Changes the zoom for the current view.
1206# ----------------------------------------------------------------------
1207itcl::body Rappture::VtkStreamlinesViewer::Zoom {option} {
1208    switch -- $option {
1209        "in" {
1210            set _view(zoom) [expr {$_view(zoom)*1.25}]
1211            SendCmd "camera zoom $_view(zoom)"
1212        }
1213        "out" {
1214            set _view(zoom) [expr {$_view(zoom)*0.8}]
1215            SendCmd "camera zoom $_view(zoom)"
1216        }
1217        "reset" {
1218            array set _view {
1219                qw              0.853553
1220                qx              -0.353553
1221                qy              0.353553
1222                qz              0.146447
1223                zoom    1.0
1224                xpan   0
1225                ypan   0
1226            }
1227            SendCmd "camera reset all"
1228            if { $_first != "" } {
1229                set location [$_first hints camera]
1230                if { $location != "" } {
1231                    array set _view $location
1232                }
1233            }
1234            set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
1235            $_arcball quaternion $q
1236            DoRotate
1237        }
1238    }
1239}
1240
1241itcl::body Rappture::VtkStreamlinesViewer::PanCamera {} {
1242    set x $_view(xpan)
1243    set y $_view(ypan)
1244    SendCmd "camera pan $x $y"
1245}
1246
1247
1248# ----------------------------------------------------------------------
1249# USAGE: Rotate click <x> <y>
1250# USAGE: Rotate drag <x> <y>
1251# USAGE: Rotate release <x> <y>
1252#
1253# Called automatically when the user clicks/drags/releases in the
1254# plot area.  Moves the plot according to the user's actions.
1255# ----------------------------------------------------------------------
1256itcl::body Rappture::VtkStreamlinesViewer::Rotate {option x y} {
1257    switch -- $option {
1258        "click" {
1259            $itk_component(view) configure -cursor fleur
1260            set _click(x) $x
1261            set _click(y) $y
1262        }
1263        "drag" {
1264            if {[array size _click] == 0} {
1265                Rotate click $x $y
1266            } else {
1267                set w [winfo width $itk_component(view)]
1268                set h [winfo height $itk_component(view)]
1269                if {$w <= 0 || $h <= 0} {
1270                    return
1271                }
1272
1273                if {[catch {
1274                    # this fails sometimes for no apparent reason
1275                    set dx [expr {double($x-$_click(x))/$w}]
1276                    set dy [expr {double($y-$_click(y))/$h}]
1277                }]} {
1278                    return
1279                }
1280                if { $dx == 0 && $dy == 0 } {
1281                    return
1282                }
1283                set q [$_arcball rotate $x $y $_click(x) $_click(y)]
1284                EventuallyRotate $q
1285                set _click(x) $x
1286                set _click(y) $y
1287            }
1288        }
1289        "release" {
1290            Rotate drag $x $y
1291            $itk_component(view) configure -cursor ""
1292            catch {unset _click}
1293        }
1294        default {
1295            error "bad option \"$option\": should be click, drag, release"
1296        }
1297    }
1298}
1299
1300itcl::body Rappture::VtkStreamlinesViewer::Pick {x y} {
1301    foreach tag [CurrentDatasets -visible] {
1302        SendCmdNoSplash "dataset getscalar pixel $x $y $tag"
1303    }
1304}
1305
1306# ----------------------------------------------------------------------
1307# USAGE: $this Pan click x y
1308#        $this Pan drag x y
1309#        $this Pan release x y
1310#
1311# Called automatically when the user clicks on one of the zoom
1312# controls for this widget.  Changes the zoom for the current view.
1313# ----------------------------------------------------------------------
1314itcl::body Rappture::VtkStreamlinesViewer::Pan {option x y} {
1315    switch -- $option {
1316        "set" {
1317            set w [winfo width $itk_component(view)]
1318            set h [winfo height $itk_component(view)]
1319            set x [expr $x / double($w)]
1320            set y [expr $y / double($h)]
1321            set _view(xpan) [expr $_view(xpan) + $x]
1322            set _view(ypan) [expr $_view(ypan) + $y]
1323            PanCamera
1324            return
1325        }
1326        "click" {
1327            set _click(x) $x
1328            set _click(y) $y
1329            $itk_component(view) configure -cursor hand1
1330        }
1331        "drag" {
1332            if { ![info exists _click(x)] } {
1333                set _click(x) $x
1334            }
1335            if { ![info exists _click(y)] } {
1336                set _click(y) $y
1337            }
1338            set w [winfo width $itk_component(view)]
1339            set h [winfo height $itk_component(view)]
1340            set dx [expr ($_click(x) - $x)/double($w)]
1341            set dy [expr ($_click(y) - $y)/double($h)]
1342            set _click(x) $x
1343            set _click(y) $y
1344            set _view(xpan) [expr $_view(xpan) - $dx]
1345            set _view(ypan) [expr $_view(ypan) - $dy]
1346            PanCamera
1347        }
1348        "release" {
1349            Pan drag $x $y
1350            $itk_component(view) configure -cursor ""
1351        }
1352        default {
1353            error "unknown option \"$option\": should set, click, drag, or release"
1354        }
1355    }
1356}
1357
1358# ----------------------------------------------------------------------
1359# USAGE: InitSettings <what> ?<value>?
1360#
1361# Used internally to update rendering settings whenever parameters
1362# change in the popup settings panel.  Sends the new settings off
1363# to the back end.
1364# ----------------------------------------------------------------------
1365itcl::body Rappture::VtkStreamlinesViewer::InitSettings { args } {
1366    foreach spec $args {
1367        if { [info exists _settings($_first-$spec)] } {
1368            # Reset global setting with dataobj specific setting
1369            set _settings($spec) $_settings($_first-$spec)
1370        }
1371        AdjustSetting $spec
1372    }
1373}
1374
1375#
1376# AdjustSetting --
1377#
1378#       Changes/updates a specific setting in the widget.  There are
1379#       usually user-setable option.  Commands are sent to the render
1380#       server.
1381#
1382itcl::body Rappture::VtkStreamlinesViewer::AdjustSetting {what {value ""}} {
1383    if { ![isconnected] } {
1384        return
1385    }
1386    switch -- $what {
1387        "volumeOpacity" {
1388            set val $_settings(volumeOpacity)
1389            set sval [expr { 0.01 * double($val) }]
1390            foreach dataset [CurrentDatasets -visible] {
1391                SendCmd "polydata opacity $sval $dataset"
1392            }
1393        }
1394        "volumeWireframe" {
1395            set bool $_settings(volumeWireframe)
1396            foreach dataset [CurrentDatasets -visible] {
1397                SendCmd "polydata wireframe $bool $dataset"
1398            }
1399        }
1400        "volumeVisible" {
1401            set bool $_settings(volumeVisible)
1402            foreach dataset [CurrentDatasets -visible] {
1403                SendCmd "polydata visible $bool $dataset"
1404            }
1405            if { $bool } {
1406                Rappture::Tooltip::for $itk_component(volume) \
1407                    "Hide the volume"
1408            } else {
1409                Rappture::Tooltip::for $itk_component(volume) \
1410                    "Show the volume"
1411            }
1412        }
1413        "volumeLighting" {
1414            set bool $_settings(volumeLighting)
1415            foreach dataset [CurrentDatasets -visible] {
1416                SendCmd "polydata lighting $bool $dataset"
1417            }
1418        }
1419        "volumeEdges" {
1420            set bool $_settings(volumeEdges)
1421            foreach dataset [CurrentDatasets -visible] {
1422                SendCmd "polydata edges $bool $dataset"
1423            }
1424        }
1425        "axesVisible" {
1426            set bool $_settings(axesVisible)
1427            SendCmd "axis visible all $bool"
1428        }
1429        "axisLabelsVisible" {
1430            set bool $_settings(axisLabelsVisible)
1431            SendCmd "axis labels all $bool"
1432        }
1433        "axisXGrid" - "axisYGrid" - "axisZGrid" {
1434            set axis [string tolower [string range $what 4 4]]
1435            set bool $_settings($what)
1436            SendCmd "axis grid $axis $bool"
1437        }
1438        "axis-mode" {
1439            set mode [$itk_component(axismode) value]
1440            set mode [$itk_component(axismode) translate $mode]
1441            set _settings($what) $mode
1442            SendCmd "axis flymode $mode"
1443        }
1444        "cutplaneEdges" {
1445            set bool $_settings($what)
1446            foreach dataset [CurrentDatasets -visible] {
1447                SendCmd "cutplane edges $bool $dataset"
1448            }
1449        }
1450        "cutplaneVisible" {
1451            set bool $_settings($what)
1452            foreach dataset [CurrentDatasets -visible] {
1453                SendCmd "cutplane visible $bool $dataset"
1454            }
1455        }
1456        "cutplaneWireframe" {
1457            set bool $_settings($what)
1458            foreach dataset [CurrentDatasets -visible] {
1459                SendCmd "cutplane wireframe $bool $dataset"
1460            }
1461        }
1462        "cutplaneLighting" {
1463            set bool $_settings($what)
1464            foreach dataset [CurrentDatasets -visible] {
1465                SendCmd "cutplane lighting $bool $dataset"
1466            }
1467        }
1468        "cutplaneOpacity" {
1469            set val $_settings($what)
1470            set sval [expr { 0.01 * double($val) }]
1471            foreach dataset [CurrentDatasets -visible] {
1472                SendCmd "cutplane opacity $sval $dataset"
1473            }
1474        }
1475        "cutplaneXVisible" - "cutplaneYVisible" - "cutplaneZVisible" {
1476            set axis [string tolower [string range $what 8 8]]
1477            set bool $_settings($what)
1478            if { $bool } {
1479                $itk_component(${axis}CutScale) configure -state normal \
1480                    -troughcolor white
1481            } else {
1482                $itk_component(${axis}CutScale) configure -state disabled \
1483                    -troughcolor grey82
1484            }
1485            foreach dataset [CurrentDatasets -visible] {
1486                SendCmd "cutplane axis $axis $bool $dataset"
1487            }
1488        }
1489        "cutplaneXPosition" - "cutplaneYPosition" - "cutplaneZPosition" {
1490            set axis [string tolower [string range $what 8 8]]
1491            set pos [expr $_settings($what) * 0.01]
1492            foreach dataset [CurrentDatasets -visible] {
1493                SendCmd "cutplane slice ${axis} ${pos} $dataset"
1494            }
1495            set _cutplanePending 0
1496        }
1497        "streamlinesSeedsVisible" {
1498            set bool $_settings($what)
1499            foreach dataset [CurrentDatasets -visible] {
1500                SendCmd "streamlines seed visible $bool $dataset"
1501            }
1502        }
1503        "streamlinesNumSeeds" {
1504            set density $_settings($what)
1505            EventuallyReseed $density
1506        }
1507        "streamlinesVisible" {
1508            set bool $_settings($what)
1509            foreach dataset [CurrentDatasets -visible] {
1510                SendCmd "streamlines visible $bool $dataset"
1511            }
1512            if { $bool } {
1513                Rappture::Tooltip::for $itk_component(streamlines) \
1514                    "Hide the streamlines"
1515            } else {
1516                Rappture::Tooltip::for $itk_component(streamlines) \
1517                    "Show the streamlines"
1518            }
1519        }
1520        "streamlinesMode" {
1521            set mode [$itk_component(streammode) value]
1522            set _settings(streamlinesMode) $mode
1523            foreach dataset [CurrentDatasets -visible] {
1524                switch -- $mode {
1525                    "lines" {
1526                        SendCmd "streamlines lines $dataset"
1527                    }
1528                    "ribbons" {
1529                        SendCmd "streamlines ribbons 3 0 $dataset"
1530                    }
1531                    "tubes" {
1532                        SendCmd "streamlines tubes 5 3 $dataset"
1533                    }
1534                }
1535            }
1536        }
1537        "streamlines-palette" {
1538            set palette [$itk_component(palette) value]
1539            set _settings(streamlines-palette) $palette
1540            foreach dataset [CurrentDatasets -visible $_first] {
1541                foreach {dataobj comp} [split $dataset -] break
1542                ChangeColormap $dataobj $comp $palette
1543            }
1544            set _legendPending 1
1545        }
1546        "streamlinesOpacity" {
1547            set val $_settings(streamlinesOpacity)
1548            set sval [expr { 0.01 * double($val) }]
1549            foreach dataset [CurrentDatasets -visible $_first] {
1550                SendCmd "streamlines opacity $sval $dataset"
1551            }
1552        }
1553        "streamlinesScale" {
1554            set val $_settings(streamlinesScale)
1555            set sval [expr { 0.01 * double($val) }]
1556            foreach dataset [CurrentDatasets -visible $_first] {
1557                SendCmd "streamlines scale $sval $sval $sval $dataset"
1558            }
1559        }
1560        "streamlinesLighting" {
1561            set bool $_settings(streamlinesLighting)
1562            foreach dataset [CurrentDatasets -visible $_first] {
1563                SendCmd "streamlines lighting $bool $dataset"
1564            }
1565        }
1566        "streamlines-field" {
1567            set new [$itk_component(field) value]
1568            set value [$itk_component(field) translate $new]
1569            set _settings(streamlines-field) $value
1570            if { [info exists _scalarFields($new)] } {
1571                set name $_scalarFields($new)
1572                set _colorMode scalar
1573                set _currentField $new
1574            } elseif { [info exists _vectorFields($new)] } {
1575                set name $_vectorFields($new)
1576                set _colorMode vmag
1577                set _currentField $new
1578            } else {
1579                puts stderr "unknown field \"$new\""
1580                return
1581            }
1582            foreach dataset [CurrentDatasets -visible] {
1583                puts stderr "streamlines colormode $_colorMode ${name} $dataset"
1584                puts stderr "cutplane colormode $_colorMode ${name} $dataset"
1585                SendCmd "streamlines colormode $_colorMode ${name} $dataset"
1586                SendCmd "cutplane colormode $_colorMode ${name} $dataset"
1587            }
1588            set _legendPending 1
1589        }
1590        default {
1591            error "don't know how to fix $what"
1592        }
1593    }
1594}
1595
1596#
1597# RequestLegend --
1598#
1599#       Request a new legend from the server.  The size of the legend
1600#       is determined from the height of the canvas.  It will be rotated
1601#       to be vertical when drawn.
1602#
1603itcl::body Rappture::VtkStreamlinesViewer::RequestLegend {} {
1604    set font "Arial 8"
1605    set lineht [font metrics $font -linespace]
1606    set c $itk_component(legend)
1607    set w 12
1608    set h [expr {$_height - 3 * ($lineht + 2)}]
1609    if { $h < 1} {
1610        return
1611    }
1612    if { [info exists _scalarFields($_currentField)] } {
1613        set name $_scalarFields($_currentField)
1614    } elseif { [info exists _vectorFields($_currentField)] } {
1615        set name $_vectorFields($_currentField)
1616    } else {
1617        return
1618    }
1619    # Set the legend on the first streamlines dataset.
1620    foreach dataset [CurrentDatasets -visible $_first] {
1621        foreach {dataobj comp} [split $dataset -] break
1622        if { [info exists _dataset2style($dataset)] } {
1623            SendCmdNoSplash \
1624                "legend $_dataset2style($dataset) $_colorMode $name {} $w $h 0"
1625            break;
1626        }
1627    }
1628}
1629
1630#
1631# ChangeColormap --
1632#
1633itcl::body Rappture::VtkStreamlinesViewer::ChangeColormap {dataobj comp color} {
1634    set tag $dataobj-$comp
1635    if { ![info exist _style($tag)] } {
1636        error "no initial colormap"
1637    }
1638    array set style $_style($tag)
1639    set style(-color) $color
1640    set _style($tag) [array get style]
1641    SetColormap $dataobj $comp
1642}
1643
1644#
1645# SetColormap --
1646#
1647itcl::body Rappture::VtkStreamlinesViewer::SetColormap { dataobj comp } {
1648    array set style {
1649        -color BCGYR
1650        -levels 6
1651        -opacity 1.0
1652    }
1653    set tag $dataobj-$comp
1654    if { ![info exists _initialStyle($tag)] } {
1655        # Save the initial component style.
1656        set _initialStyle($tag) [$dataobj style $comp]
1657    }
1658
1659    # Override defaults with initial style defined in xml.
1660    array set style $_initialStyle($tag)
1661
1662    if { ![info exists _style($tag)] } {
1663        set _style($tag) [array get style]
1664    }
1665    # Override initial style with current style.
1666    array set style $_style($tag)
1667
1668    set name "$style(-color):$style(-levels):$style(-opacity)"
1669    if { ![info exists _colormaps($name)] } {
1670        BuildColormap $name [array get style]
1671        set _colormaps($name) 1
1672    }
1673    if { ![info exists _dataset2style($tag)] ||
1674         $_dataset2style($tag) != $name } {
1675        SendCmd "streamlines colormap $name $tag"
1676        SendCmd "cutplane colormap $name $tag"
1677        set _dataset2style($tag) $name
1678    }
1679}
1680
1681
1682#
1683# BuildColormap --
1684#
1685itcl::body Rappture::VtkStreamlinesViewer::BuildColormap { name styles } {
1686    array set style $styles
1687    set cmap [ColorsToColormap $style(-color)]
1688    if { [llength $cmap] == 0 } {
1689        set cmap "0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0"
1690    }
1691    if { ![info exists _settings(volumeOpacity)] } {
1692        set _settings(volumeOpacity) $style(-opacity)
1693    }
1694    set max $_settings(volumeOpacity)
1695
1696    set wmap "0.0 1.0 1.0 1.0"
1697    SendCmd "colormap add $name { $cmap } { $wmap }"
1698}
1699
1700# ----------------------------------------------------------------------
1701# CONFIGURATION OPTION: -plotbackground
1702# ----------------------------------------------------------------------
1703itcl::configbody Rappture::VtkStreamlinesViewer::plotbackground {
1704    if { [isconnected] } {
1705        foreach {r g b} [Color2RGB $itk_option(-plotbackground)] break
1706        SendCmd "screen bgcolor $r $g $b"
1707    }
1708}
1709
1710# ----------------------------------------------------------------------
1711# CONFIGURATION OPTION: -plotforeground
1712# ----------------------------------------------------------------------
1713itcl::configbody Rappture::VtkStreamlinesViewer::plotforeground {
1714    if { [isconnected] } {
1715        foreach {r g b} [Color2RGB $itk_option(-plotforeground)] break
1716        #fix this!
1717        #SendCmd "color background $r $g $b"
1718    }
1719}
1720
1721itcl::body Rappture::VtkStreamlinesViewer::limits { dataobj } {
1722    return
1723    array unset _limits $dataobj-*
1724    foreach comp [$dataobj components] {
1725        set tag $dataobj-$comp
1726        if { ![info exists _limits($tag)] } {
1727            set data [$dataobj blob $comp]
1728            set tmpfile file[pid].vtk
1729            set f [open "$tmpfile" "w"]
1730            fconfigure $f -translation binary -encoding binary
1731            puts $f $data
1732            close $f
1733            set reader [vtkDataSetReader $tag-xvtkDataSetReader]
1734            $reader SetFileName $tmpfile
1735            $reader ReadAllScalarsOn
1736            $reader ReadAllVectorsOn
1737            $reader ReadAllFieldsOn
1738            $reader Update
1739            set output [$reader GetOutput]
1740            set _limits($tag) [$output GetBounds]
1741            set pointData [$output GetPointData]
1742            puts stderr "\#scalars=[$reader GetNumberOfScalarsInFile]"
1743            puts stderr "\#fielddata=[$reader GetNumberOfFieldDataInFile]"
1744            puts stderr "fielddataname=[$reader GetFieldDataNameInFile 0]"
1745            set fieldData [$output GetFieldData]
1746            set pointData [$output GetPointData]
1747            puts stderr "field \#arrays=[$fieldData GetNumberOfArrays]"
1748            for { set i 0 } { $i < [$fieldData GetNumberOfArrays] } { incr i } {
1749                puts stderr [$fieldData GetArrayName $i]
1750            }
1751            puts stderr "point \#arrays=[$pointData GetNumberOfArrays]"
1752            for { set i 0 } { $i < [$pointData GetNumberOfArrays] } { incr i } {
1753                set name [$pointData GetArrayName $i]
1754                if { ![info exists _fields($name)] } {
1755                    $itk_component(field) choices insert end "$name" "$name"
1756                    set _fields($name) 1
1757                }
1758            }
1759            puts stderr "field \#components=[$fieldData GetNumberOfComponents]"
1760            puts stderr "point \#components=[$pointData GetNumberOfComponents]"
1761            puts stderr "field \#tuples=[$fieldData GetNumberOfTuples]"
1762            puts stderr "point \#tuples=[$pointData GetNumberOfTuples]"
1763            puts stderr "point \#scalars=[$pointData GetScalars]"
1764            puts stderr vectors=[$pointData GetVectors]
1765            rename $output ""
1766            rename $reader ""
1767            file delete $tmpfile
1768        }
1769        foreach { xMin xMax yMin yMax zMin zMax} $_limits($tag) break
1770        if {![info exists limits(xmin)] || $limits(xmin) > $xMin} {
1771            set limits(xmin) $xMin
1772        }
1773        if {![info exists limits(xmax)] || $limits(xmax) < $xMax} {
1774            set limits(xmax) $xMax
1775        }
1776        if {![info exists limits(ymin)] || $limits(ymin) > $yMin} {
1777            set limits(ymin) $xMin
1778        }
1779        if {![info exists limits(ymax)] || $limits(ymax) < $yMax} {
1780            set limits(ymax) $yMax
1781        }
1782        if {![info exists limits(zmin)] || $limits(zmin) > $zMin} {
1783            set limits(zmin) $zMin
1784        }
1785        if {![info exists limits(zmax)] || $limits(zmax) < $zMax} {
1786            set limits(zmax) $zMax
1787        }
1788    }
1789    return [array get limits]
1790}
1791
1792itcl::body Rappture::VtkStreamlinesViewer::BuildVolumeTab {} {
1793
1794    set fg [option get $itk_component(hull) font Font]
1795    #set bfg [option get $itk_component(hull) boldFont Font]
1796
1797    set inner [$itk_component(main) insert end \
1798        -title "Volume Settings" \
1799        -icon [Rappture::icon volume-on]]
1800    $inner configure -borderwidth 4
1801
1802    checkbutton $inner.volume \
1803        -text "Show Volume" \
1804        -variable [itcl::scope _settings(volumeVisible)] \
1805        -command [itcl::code $this AdjustSetting volumeVisible] \
1806        -font "Arial 9"
1807
1808    checkbutton $inner.wireframe \
1809        -text "Show Wireframe" \
1810        -variable [itcl::scope _settings(volumeWireframe)] \
1811        -command [itcl::code $this AdjustSetting volumeWireframe] \
1812        -font "Arial 9"
1813
1814    checkbutton $inner.lighting \
1815        -text "Enable Lighting" \
1816        -variable [itcl::scope _settings(volumeLighting)] \
1817        -command [itcl::code $this AdjustSetting volumeLighting] \
1818        -font "Arial 9"
1819
1820    checkbutton $inner.edges \
1821        -text "Show Edges" \
1822        -variable [itcl::scope _settings(volumeEdges)] \
1823        -command [itcl::code $this AdjustSetting volumeEdges] \
1824        -font "Arial 9"
1825
1826    label $inner.opacity_l -text "Opacity" -font "Arial 9"
1827    ::scale $inner.opacity -from 0 -to 100 -orient horizontal \
1828        -variable [itcl::scope _settings(volumeOpacity)] \
1829        -width 10 \
1830        -showvalue off \
1831        -command [itcl::code $this AdjustSetting volumeOpacity]
1832
1833    blt::table $inner \
1834        0,0 $inner.wireframe -anchor w -pady 2 -cspan 2 \
1835        1,0 $inner.lighting  -anchor w -pady 2 -cspan 2 \
1836        2,0 $inner.edges     -anchor w -pady 2 -cspan 3 \
1837        3,0 $inner.opacity_l -anchor w -pady 2 \
1838        3,1 $inner.opacity   -fill x   -pady 2
1839
1840    blt::table configure $inner r* c* -resize none
1841    blt::table configure $inner r4 c1 -resize expand
1842}
1843
1844
1845itcl::body Rappture::VtkStreamlinesViewer::BuildStreamsTab {} {
1846
1847    set fg [option get $itk_component(hull) font Font]
1848    #set bfg [option get $itk_component(hull) boldFont Font]
1849
1850    set inner [$itk_component(main) insert end \
1851        -title "Streams Settings" \
1852        -icon [Rappture::icon streamlines-on]]
1853    $inner configure -borderwidth 4
1854
1855    checkbutton $inner.streamlines \
1856        -text "Show Streamlines" \
1857        -variable [itcl::scope _settings(streamlinesVisible)] \
1858        -command [itcl::code $this AdjustSetting streamlinesVisible] \
1859        -font "Arial 9"
1860   
1861    checkbutton $inner.lighting \
1862        -text "Enable Lighting" \
1863        -variable [itcl::scope _settings(streamlinesLighting)] \
1864        -command [itcl::code $this AdjustSetting streamlinesLighting] \
1865        -font "Arial 9"
1866
1867    checkbutton $inner.seeds \
1868        -text "Show Seeds" \
1869        -variable [itcl::scope _settings(streamlinesSeedsVisible)] \
1870        -command [itcl::code $this AdjustSetting streamlinesSeedsVisible] \
1871        -font "Arial 9"
1872
1873    label $inner.mode_l -text "Mode" -font "Arial 9"
1874    itk_component add streammode {
1875        Rappture::Combobox $inner.mode -width 10 -editable no
1876    }
1877    $inner.mode choices insert end \
1878        "lines"    "lines" \
1879        "ribbons"   "ribbons" \
1880        "tubes"     "tubes"
1881    $itk_component(streammode) value $_settings(streamlinesMode)
1882    bind $inner.mode <<Value>> [itcl::code $this AdjustSetting streamlinesMode]
1883
1884    label $inner.opacity_l -text "Opacity" -font "Arial 9"
1885    ::scale $inner.opacity -from 0 -to 100 -orient horizontal \
1886        -variable [itcl::scope _settings(streamlinesOpacity)] \
1887        -width 10 \
1888        -showvalue off \
1889        -command [itcl::code $this AdjustSetting streamlinesOpacity]
1890
1891    label $inner.density_l -text "No. Seeds" -font "Arial 9"
1892    ::scale $inner.density -from 1 -to 1000 -orient horizontal \
1893        -variable [itcl::scope _settings(streamlinesNumSeeds)] \
1894        -width 10 \
1895        -showvalue on \
1896        -command [itcl::code $this AdjustSetting streamlinesNumSeeds]
1897
1898    label $inner.scale_l -text "Scale" -font "Arial 9"
1899    ::scale $inner.scale -from 1 -to 100 -orient horizontal \
1900        -variable [itcl::scope _settings(streamlinesScale)] \
1901        -width 10 \
1902        -showvalue off \
1903        -command [itcl::code $this AdjustSetting streamlinesScale]
1904
1905    label $inner.field_l -text "Field" -font "Arial 9"
1906    itk_component add field {
1907        Rappture::Combobox $inner.field -width 10 -editable no
1908    }
1909    bind $inner.field <<Value>> \
1910        [itcl::code $this AdjustSetting streamlines-field]
1911
1912    label $inner.palette_l -text "Palette" -font "Arial 9"
1913    itk_component add palette {
1914        Rappture::Combobox $inner.palette -width 10 -editable no
1915    }
1916    $inner.palette choices insert end \
1917        "BCGYR"              "BCGYR"            \
1918        "BGYOR"              "BGYOR"            \
1919        "blue"               "blue"             \
1920        "blue-to-brown"      "blue-to-brown"    \
1921        "blue-to-orange"     "blue-to-orange"   \
1922        "blue-to-grey"       "blue-to-grey"     \
1923        "green-to-magenta"   "green-to-magenta" \
1924        "greyscale"          "greyscale"        \
1925        "nanohub"            "nanohub"          \
1926        "rainbow"            "rainbow"          \
1927        "spectral"           "spectral"         \
1928        "ROYGB"              "ROYGB"            \
1929        "RYGCB"              "RYGCB"            \
1930        "brown-to-blue"      "brown-to-blue"    \
1931        "grey-to-blue"       "grey-to-blue"     \
1932        "orange-to-blue"     "orange-to-blue"   
1933
1934    $itk_component(palette) value "BCGYR"
1935    bind $inner.palette <<Value>> \
1936        [itcl::code $this AdjustSetting streamlines-palette]
1937
1938    blt::table $inner \
1939        0,0 $inner.palette_l   -anchor w -pady 2  \
1940        0,1 $inner.palette     -fill x   -pady 2  \
1941        1,0 $inner.field_l     -anchor w -pady 2  \
1942        1,1 $inner.field       -fill x   -pady 2  \
1943        2,0 $inner.mode_l      -anchor w -pady 2  \
1944        2,1 $inner.mode        -fill x   -pady 2  \
1945        3,0 $inner.opacity_l   -anchor w -pady 2  \
1946        3,1 $inner.opacity     -anchor w -pady 2  \
1947        5,0 $inner.lighting    -anchor w -pady 2 -cspan 2 \
1948        6,0 $inner.seeds       -anchor w -pady 2 -cspan 2 \
1949        7,0 $inner.density_l   -anchor w -pady 2  \
1950        7,1 $inner.density     -fill x   -pady 2  \
1951
1952    blt::table configure $inner r* c* -resize none
1953    blt::table configure $inner r10 c1 c2 -resize expand
1954}
1955
1956itcl::body Rappture::VtkStreamlinesViewer::BuildAxisTab {} {
1957
1958    set fg [option get $itk_component(hull) font Font]
1959    #set bfg [option get $itk_component(hull) boldFont Font]
1960
1961    set inner [$itk_component(main) insert end \
1962        -title "Axis Settings" \
1963        -icon [Rappture::icon axis1]]
1964    $inner configure -borderwidth 4
1965
1966    checkbutton $inner.visible \
1967        -text "Show Axes" \
1968        -variable [itcl::scope _settings(axesVisible)] \
1969        -command [itcl::code $this AdjustSetting axesVisible] \
1970        -font "Arial 9"
1971
1972    checkbutton $inner.labels \
1973        -text "Show Axis Labels" \
1974        -variable [itcl::scope _settings(axisLabelsVisible)] \
1975        -command [itcl::code $this AdjustSetting axisLabelsVisible] \
1976        -font "Arial 9"
1977
1978    checkbutton $inner.xgrid \
1979        -text "Show X Grid" \
1980        -variable [itcl::scope _settings(axisXGrid)] \
1981        -command [itcl::code $this AdjustSetting axisXGrid] \
1982        -font "Arial 9"
1983    checkbutton $inner.ygrid \
1984        -text "Show Y Grid" \
1985        -variable [itcl::scope _settings(axisYGrid)] \
1986        -command [itcl::code $this AdjustSetting axisYGrid] \
1987        -font "Arial 9"
1988    checkbutton $inner.zgrid \
1989        -text "Show Z Grid" \
1990        -variable [itcl::scope _settings(axisZGrid)] \
1991        -command [itcl::code $this AdjustSetting axisZGrid] \
1992        -font "Arial 9"
1993
1994    label $inner.mode_l -text "Mode" -font "Arial 9"
1995
1996    itk_component add axismode {
1997        Rappture::Combobox $inner.mode -width 10 -editable no
1998    }
1999    $inner.mode choices insert end \
2000        "static_triad"    "static" \
2001        "closest_triad"   "closest" \
2002        "furthest_triad"  "furthest" \
2003        "outer_edges"     "outer"         
2004    $itk_component(axismode) value "static"
2005    bind $inner.mode <<Value>> [itcl::code $this AdjustSetting axis-mode]
2006
2007    blt::table $inner \
2008        0,0 $inner.visible -anchor w -cspan 2 \
2009        1,0 $inner.labels  -anchor w -cspan 2 \
2010        2,0 $inner.xgrid   -anchor w -cspan 2 \
2011        3,0 $inner.ygrid   -anchor w -cspan 2 \
2012        4,0 $inner.zgrid   -anchor w -cspan 2 \
2013        5,0 $inner.mode_l  -anchor w -cspan 2 -padx { 2 0 } \
2014        6,0 $inner.mode    -fill x   -cspan 2
2015
2016    blt::table configure $inner r* c* -resize none
2017    blt::table configure $inner r7 c1 -resize expand
2018}
2019
2020
2021itcl::body Rappture::VtkStreamlinesViewer::BuildCameraTab {} {
2022    set inner [$itk_component(main) insert end \
2023        -title "Camera Settings" \
2024        -icon [Rappture::icon camera]]
2025    $inner configure -borderwidth 4
2026
2027    set labels { qx qy qz qw xpan ypan zoom }
2028    set row 0
2029    foreach tag $labels {
2030        label $inner.${tag}label -text $tag -font "Arial 9"
2031        entry $inner.${tag} -font "Arial 9"  -bg white \
2032            -textvariable [itcl::scope _view($tag)]
2033        bind $inner.${tag} <KeyPress-Return> \
2034            [itcl::code $this camera set ${tag}]
2035        blt::table $inner \
2036            $row,0 $inner.${tag}label -anchor e -pady 2 \
2037            $row,1 $inner.${tag} -anchor w -pady 2
2038        blt::table configure $inner r$row -resize none
2039        incr row
2040    }
2041    checkbutton $inner.ortho \
2042        -text "Orthographic Projection" \
2043        -variable [itcl::scope _view(ortho)] \
2044        -command [itcl::code $this camera set ortho] \
2045        -font "Arial 9"
2046    blt::table $inner \
2047            $row,0 $inner.ortho -columnspan 2 -anchor w -pady 2
2048    blt::table configure $inner r$row -resize none
2049    incr row
2050
2051    blt::table configure $inner c0 c1 -resize none
2052    blt::table configure $inner c2 -resize expand
2053    blt::table configure $inner r$row -resize expand
2054}
2055
2056itcl::body Rappture::VtkStreamlinesViewer::BuildCutplaneTab {} {
2057
2058    set fg [option get $itk_component(hull) font Font]
2059   
2060    set inner [$itk_component(main) insert end \
2061        -title "Cutplane Settings" \
2062        -icon [Rappture::icon cutbutton]]
2063
2064    $inner configure -borderwidth 4
2065
2066    checkbutton $inner.visible \
2067        -text "Show Cutplanes" \
2068        -variable [itcl::scope _settings(cutplaneVisible)] \
2069        -command [itcl::code $this AdjustSetting cutplaneVisible] \
2070        -font "Arial 9"
2071
2072    checkbutton $inner.wireframe \
2073        -text "Show Wireframe" \
2074        -variable [itcl::scope _settings(cutplaneWireframe)] \
2075        -command [itcl::code $this AdjustSetting cutplaneWireframe] \
2076        -font "Arial 9"
2077
2078    checkbutton $inner.lighting \
2079        -text "Enable Lighting" \
2080        -variable [itcl::scope _settings(cutplaneLighting)] \
2081        -command [itcl::code $this AdjustSetting cutplaneLighting] \
2082        -font "Arial 9"
2083
2084    checkbutton $inner.edges \
2085        -text "Show Edges" \
2086        -variable [itcl::scope _settings(cutplaneEdges)] \
2087        -command [itcl::code $this AdjustSetting cutplaneEdges] \
2088        -font "Arial 9"
2089
2090    label $inner.opacity_l -text "Opacity" -font "Arial 9"
2091    ::scale $inner.opacity -from 0 -to 100 -orient horizontal \
2092        -variable [itcl::scope _settings(cutplaneOpacity)] \
2093        -width 10 \
2094        -showvalue off \
2095        -command [itcl::code $this AdjustSetting cutplaneOpacity]
2096    $inner.opacity set $_settings(cutplaneOpacity)
2097
2098    # X-value slicer...
2099    itk_component add xCutButton {
2100        Rappture::PushButton $inner.xbutton \
2101            -onimage [Rappture::icon x-cutplane-red] \
2102            -offimage [Rappture::icon x-cutplane-red] \
2103            -command [itcl::code $this AdjustSetting cutplaneXVisible] \
2104            -variable [itcl::scope _settings(cutplaneXVisible)]
2105    }
2106    Rappture::Tooltip::for $itk_component(xCutButton) \
2107        "Toggle the X-axis cutplane on/off"
2108    $itk_component(xCutButton) select
2109
2110    itk_component add xCutScale {
2111        ::scale $inner.xval -from 100 -to 0 \
2112            -width 10 -orient vertical -showvalue yes \
2113            -borderwidth 1 -highlightthickness 0 \
2114            -command [itcl::code $this EventuallySetCutplane x] \
2115            -variable [itcl::scope _settings(cutplaneXPosition)] \
2116            -foreground red3 -font "Arial 9 bold"
2117    } {
2118        usual
2119        ignore -borderwidth -highlightthickness -foreground -font
2120    }
2121    # Set the default cutplane value before disabling the scale.
2122    $itk_component(xCutScale) set 50
2123    $itk_component(xCutScale) configure -state disabled
2124    Rappture::Tooltip::for $itk_component(xCutScale) \
2125        "@[itcl::code $this Slice tooltip x]"
2126
2127    # Y-value slicer...
2128    itk_component add yCutButton {
2129        Rappture::PushButton $inner.ybutton \
2130            -onimage [Rappture::icon y-cutplane-green] \
2131            -offimage [Rappture::icon y-cutplane-green] \
2132            -command [itcl::code $this AdjustSetting cutplaneYVisible] \
2133            -variable [itcl::scope _settings(cutplaneYVisible)]
2134    }
2135    Rappture::Tooltip::for $itk_component(yCutButton) \
2136        "Toggle the Y-axis cutplane on/off"
2137    $itk_component(yCutButton) select
2138
2139    itk_component add yCutScale {
2140        ::scale $inner.yval -from 100 -to 0 \
2141            -width 10 -orient vertical -showvalue yes \
2142            -borderwidth 1 -highlightthickness 0 \
2143            -command [itcl::code $this EventuallySetCutplane y] \
2144            -variable [itcl::scope _settings(cutplaneYPosition)] \
2145            -foreground green3 -font "Arial 9 bold"
2146    } {
2147        usual
2148        ignore -borderwidth -highlightthickness -foreground -font
2149    }
2150    Rappture::Tooltip::for $itk_component(yCutScale) \
2151        "@[itcl::code $this Slice tooltip y]"
2152    # Set the default cutplane value before disabling the scale.
2153    $itk_component(yCutScale) set 50
2154    $itk_component(yCutScale) configure -state disabled
2155
2156    # Z-value slicer...
2157    itk_component add zCutButton {
2158        Rappture::PushButton $inner.zbutton \
2159            -onimage [Rappture::icon z-cutplane-blue] \
2160            -offimage [Rappture::icon z-cutplane-blue] \
2161            -command [itcl::code $this AdjustSetting cutplaneZVisible] \
2162            -variable [itcl::scope _settings(cutplaneZVisible)]
2163    }
2164    Rappture::Tooltip::for $itk_component(zCutButton) \
2165        "Toggle the Z-axis cutplane on/off"
2166    $itk_component(zCutButton) select
2167
2168    itk_component add zCutScale {
2169        ::scale $inner.zval -from 100 -to 0 \
2170            -width 10 -orient vertical -showvalue yes \
2171            -borderwidth 1 -highlightthickness 0 \
2172            -command [itcl::code $this EventuallySetCutplane z] \
2173            -variable [itcl::scope _settings(cutplaneZPosition)] \
2174            -foreground blue3 -font "Arial 9 bold"
2175    } {
2176        usual
2177        ignore -borderwidth -highlightthickness -foreground -font
2178    }
2179    $itk_component(zCutScale) set 50
2180    $itk_component(zCutScale) configure -state disabled
2181    #$itk_component(zCutScale) configure -state disabled
2182    Rappture::Tooltip::for $itk_component(zCutScale) \
2183        "@[itcl::code $this Slice tooltip z]"
2184
2185    blt::table $inner \
2186        0,0 $inner.lighting             -anchor w -pady 2 -cspan 4 \
2187        1,0 $inner.wireframe            -anchor w -pady 2 -cspan 4 \
2188        2,0 $inner.edges                -anchor w -pady 2 -cspan 4 \
2189        3,0 $inner.opacity_l            -anchor w -pady 2 -cspan 1 \
2190        3,1 $inner.opacity              -fill x   -pady 2 -cspan 3 \
2191        4,0 $itk_component(xCutButton)  -anchor w -padx 2 -pady 2 \
2192        5,0 $itk_component(yCutButton)  -anchor w -padx 2 -pady 2 \
2193        6,0 $itk_component(zCutButton)  -anchor w -padx 2 -pady 2 \
2194        4,1 $itk_component(xCutScale)   -fill y -rspan 4 \
2195        4,2 $itk_component(yCutScale)   -fill y -rspan 4 \
2196        4,3 $itk_component(zCutScale)   -fill y -rspan 4 \
2197
2198    blt::table configure $inner r* c* -resize none
2199    blt::table configure $inner r7 c4 -resize expand
2200}
2201
2202
2203
2204#
2205#  camera --
2206#
2207itcl::body Rappture::VtkStreamlinesViewer::camera {option args} {
2208    switch -- $option {
2209        "show" {
2210            puts [array get _view]
2211        }
2212        "set" {
2213            set who [lindex $args 0]
2214            set x $_view($who)
2215            set code [catch { string is double $x } result]
2216            if { $code != 0 || !$result } {
2217                return
2218            }
2219            switch -- $who {
2220                "ortho" {
2221                    if {$_view(ortho)} {
2222                        SendCmd "camera mode ortho"
2223                    } else {
2224                        SendCmd "camera mode persp"
2225                    }
2226                }
2227                "xpan" - "ypan" {
2228                    PanCamera
2229                }
2230                "qx" - "qy" - "qz" - "qw" {
2231                    set q [list $_view(qw) $_view(qx) $_view(qy) $_view(qz)]
2232                    $_arcball quaternion $q
2233                    EventuallyRotate $q
2234                }
2235                "zoom" {
2236                    SendCmd "camera zoom $_view(zoom)"
2237                }
2238            }
2239        }
2240    }
2241}
2242
2243itcl::body Rappture::VtkStreamlinesViewer::ConvertToVtkData { dataobj comp } {
2244    foreach { x1 x2 xN y1 y2 yN } [$dataobj mesh $comp] break
2245    set values [$dataobj values $comp]
2246    append out "# vtk DataFile Version 2.0 \n"
2247    append out "Test data \n"
2248    append out "ASCII \n"
2249    append out "DATASET STRUCTURED_POINTS \n"
2250    append out "DIMENSIONS $xN $yN 1 \n"
2251    append out "ORIGIN 0 0 0 \n"
2252    append out "SPACING 1 1 1 \n"
2253    append out "POINT_DATA [expr $xN * $yN] \n"
2254    append out "SCALARS field float 1 \n"
2255    append out "LOOKUP_TABLE default \n"
2256    append out [join $values "\n"]
2257    append out "\n"
2258    return $out
2259}
2260
2261
2262itcl::body Rappture::VtkStreamlinesViewer::GetVtkData { args } {
2263    set bytes ""
2264    foreach dataobj [get] {
2265        foreach comp [$dataobj components] {
2266            set tag $dataobj-$comp
2267            #set contents [ConvertToVtkData $dataobj $comp]
2268            set contents [$dataobj blob $comp]
2269            append bytes "$contents\n\n"
2270        }
2271    }
2272    return [list .vtk $bytes]
2273}
2274
2275itcl::body Rappture::VtkStreamlinesViewer::GetImage { args } {
2276    if { [image width $_image(download)] > 0 &&
2277         [image height $_image(download)] > 0 } {
2278        set bytes [$_image(download) data -format "jpeg -quality 100"]
2279        set bytes [Rappture::encoding::decode -as b64 $bytes]
2280        return [list .jpg $bytes]
2281    }
2282    return ""
2283}
2284
2285itcl::body Rappture::VtkStreamlinesViewer::BuildDownloadPopup { popup command } {
2286    Rappture::Balloon $popup \
2287        -title "[Rappture::filexfer::label downloadWord] as..."
2288    set inner [$popup component inner]
2289    label $inner.summary -text "" -anchor w
2290    radiobutton $inner.vtk_button -text "VTK data file" \
2291        -variable [itcl::scope _downloadPopup(format)] \
2292        -font "Helvetica 9 " \
2293        -value vtk 
2294    Rappture::Tooltip::for $inner.vtk_button "Save as VTK data file."
2295    radiobutton $inner.image_button -text "Image File" \
2296        -variable [itcl::scope _downloadPopup(format)] \
2297        -value image
2298    Rappture::Tooltip::for $inner.image_button \
2299        "Save as digital image."
2300
2301    button $inner.ok -text "Save" \
2302        -highlightthickness 0 -pady 2 -padx 3 \
2303        -command $command \
2304        -compound left \
2305        -image [Rappture::icon download]
2306
2307    button $inner.cancel -text "Cancel" \
2308        -highlightthickness 0 -pady 2 -padx 3 \
2309        -command [list $popup deactivate] \
2310        -compound left \
2311        -image [Rappture::icon cancel]
2312
2313    blt::table $inner \
2314        0,0 $inner.summary -cspan 2  \
2315        1,0 $inner.vtk_button -anchor w -cspan 2 -padx { 4 0 } \
2316        2,0 $inner.image_button -anchor w -cspan 2 -padx { 4 0 } \
2317        4,1 $inner.cancel -width .9i -fill y \
2318        4,0 $inner.ok -padx 2 -width .9i -fill y
2319    blt::table configure $inner r3 -height 4
2320    blt::table configure $inner r4 -pady 4
2321    raise $inner.image_button
2322    $inner.vtk_button invoke
2323    return $inner
2324}
2325
2326itcl::body Rappture::VtkStreamlinesViewer::SetObjectStyle { dataobj comp } {
2327    # Parse style string.
2328    set tag $dataobj-$comp
2329    set style [$dataobj style $comp]
2330    array set settings {
2331        -color \#808080
2332        -edges 0
2333        -edgecolor black
2334        -linewidth 1.0
2335        -opacity 0.4
2336        -wireframe 0
2337        -lighting 1
2338        -seeds 1
2339        -seedcolor white
2340        -visible 1
2341    }
2342    if { $dataobj != $_first } {
2343        set settings(-opacity) 1
2344    }
2345    array set settings $style
2346    SendCmd "streamlines add $tag"
2347    SendCmd "streamlines seed visible off $tag"
2348    set seeds [$dataobj hints seeds]
2349    if { $seeds != "" && ![info exists _seeds($dataobj)] } {
2350        set length [string length $seeds]
2351        SendCmd "streamlines seed fmesh 200 data follows $length $tag"
2352        SendCmd "$seeds"
2353        set _seeds($dataobj) 1
2354    }
2355    SendCmd "cutplane add $tag"
2356    SendCmd "cutplane edges 0 $tag"
2357    SendCmd "cutplane wireframe 0 $tag"
2358    SendCmd "cutplane lighting 1 $tag"
2359    SendCmd "cutplane linewidth 1 $tag"
2360    #SendCmd "cutplane linecolor 1 1 1 $tag"
2361    #SendCmd "cutplane visible $tag"
2362    foreach axis { x y z } {
2363        SendCmd "cutplane slice $axis 0.5 $tag"
2364        SendCmd "cutplane axis $axis 0 $tag"
2365    }
2366
2367    SendCmd "polydata add $tag"
2368    SendCmd "polydata edges $settings(-edges) $tag"
2369    set _settings(volumeEdges) $settings(-edges)
2370    SendCmd "polydata color [Color2RGB $settings(-color)] $tag"
2371    SendCmd "polydata lighting $settings(-lighting) $tag"
2372    set _settings(volumeLighting) $settings(-lighting)
2373    SendCmd "polydata linecolor [Color2RGB $settings(-edgecolor)] $tag"
2374    SendCmd "polydata linewidth $settings(-linewidth) $tag"
2375    SendCmd "polydata opacity $settings(-opacity) $tag"
2376    set _settings(volumeOpacity) $settings(-opacity)
2377    SendCmd "polydata wireframe $settings(-wireframe) $tag"
2378    set _settings(volumeWireframe) $settings(-wireframe)
2379    set _settings(volumeOpacity) [expr $settings(-opacity) * 100.0]
2380    SetColormap $dataobj $comp
2381}
2382
2383itcl::body Rappture::VtkStreamlinesViewer::IsValidObject { dataobj } {
2384    if {[catch {$dataobj isa Rappture::Field} valid] != 0 || !$valid} {
2385        return 0
2386    }
2387    return 1
2388}
2389
2390# ----------------------------------------------------------------------
2391# USAGE: ReceiveLegend <colormap> <title> <vmin> <vmax> <size>
2392#
2393# Invoked automatically whenever the "legend" command comes in from
2394# the rendering server.  Indicates that binary image data with the
2395# specified <size> will follow.
2396# ----------------------------------------------------------------------
2397itcl::body Rappture::VtkStreamlinesViewer::ReceiveLegend { colormap title vmin vmax size } {
2398    set _legendPending 0
2399    puts stderr "ReceiveLegend colormap=$colormap title=$title range=$vmin,$vmax size=$size"
2400    set _limits(vmin) $vmin
2401    set _limits(vmax) $vmax
2402    set _title $title
2403    regsub {\(mag\)} $title "" _title
2404    if { [IsConnected] } {
2405        set bytes [ReceiveBytes $size]
2406        if { ![info exists _image(legend)] } {
2407            set _image(legend) [image create photo]
2408        }
2409        $_image(legend) configure -data $bytes
2410        #puts stderr "read $size bytes for [image width $_image(legend)]x[image height $_image(legend)] legend>"
2411        if { [catch {DrawLegend $_title} errs] != 0 } {
2412            puts stderr errs=$errs
2413        }
2414    }
2415}
2416
2417#
2418# DrawLegend --
2419#
2420#       Draws the legend in it's own canvas which resides to the right
2421#       of the contour plot area.
2422#
2423itcl::body Rappture::VtkStreamlinesViewer::DrawLegend { name } {
2424    set c $itk_component(view)
2425    set w [winfo width $c]
2426    set h [winfo height $c]
2427    set font "Arial 8"
2428    set lineht [font metrics $font -linespace]
2429   
2430    if { [info exists _fields($name)] } {
2431        foreach { title units } $_fields($name) break
2432        if { $units != "" } {
2433            set title [format "%s (%s)" $title $units]
2434        }
2435    } else {
2436        set title $name
2437    }
2438    if { $_settings(legendVisible) } {
2439        set x [expr $w - 2]
2440        if { [$c find withtag "legend"] == "" } {
2441            set y 2
2442            $c create text $x $y \
2443                -anchor ne \
2444                -fill $itk_option(-plotforeground) -tags "title legend" \
2445                -font $font
2446            incr y $lineht
2447            $c create text $x $y \
2448                -anchor ne \
2449                -fill $itk_option(-plotforeground) -tags "vmax legend" \
2450                -font $font
2451            incr y $lineht
2452            $c create image $x $y \
2453                -anchor ne \
2454                -image $_image(legend) -tags "colormap legend"
2455            $c create text $x [expr {$h-2}] \
2456                -anchor se \
2457                -fill $itk_option(-plotforeground) -tags "vmin legend" \
2458                -font $font
2459            #$c bind colormap <Enter> [itcl::code $this EnterLegend %x %y]
2460            $c bind colormap <Leave> [itcl::code $this LeaveLegend]
2461            $c bind colormap <Motion> [itcl::code $this MotionLegend %x %y]
2462        }
2463        $c bind title <ButtonPress> [itcl::code $this Combo post]
2464        $c bind title <Enter> [itcl::code $this Combo activate]
2465        $c bind title <Leave> [itcl::code $this Combo deactivate]
2466        # Reset the item coordinates according the current size of the plot.
2467        $c itemconfigure title -text $title
2468        if { $_limits(vmin) != "" } {
2469            $c itemconfigure vmin -text [format %g $_limits(vmin)]
2470        }
2471        if { $_limits(vmax) != "" } {
2472            $c itemconfigure vmax -text [format %g $_limits(vmax)]
2473        }
2474        set y 2
2475        $c coords title $x $y
2476        incr y $lineht
2477        $c coords vmax $x $y
2478        incr y $lineht
2479        $c coords colormap $x $y
2480        $c coords vmin $x [expr {$h - 2}]
2481    }
2482}
2483
2484#
2485# EnterLegend --
2486#
2487itcl::body Rappture::VtkStreamlinesViewer::EnterLegend { x y } {
2488    SetLegendTip $x $y
2489}
2490
2491#
2492# MotionLegend --
2493#
2494itcl::body Rappture::VtkStreamlinesViewer::MotionLegend { x y } {
2495    Rappture::Tooltip::tooltip cancel
2496    set c $itk_component(view)
2497    SetLegendTip $x $y
2498}
2499
2500#
2501# LeaveLegend --
2502#
2503itcl::body Rappture::VtkStreamlinesViewer::LeaveLegend { } {
2504    Rappture::Tooltip::tooltip cancel
2505    .rappturetooltip configure -icon ""
2506}
2507
2508#
2509# SetLegendTip --
2510#
2511itcl::body Rappture::VtkStreamlinesViewer::SetLegendTip { x y } {
2512    set c $itk_component(view)
2513    set w [winfo width $c]
2514    set h [winfo height $c]
2515    set font "Arial 8"
2516    set lineht [font metrics $font -linespace]
2517   
2518    set imgHeight [image height $_image(legend)]
2519    set coords [$c coords colormap]
2520    set imgX [expr $w - [image width $_image(legend)] - 2]
2521    set imgY [expr $y - 2 * ($lineht + 2)]
2522
2523    if { [info exists _fields($_title)] } {
2524        foreach { title units } $_fields($_title) break
2525        if { $units != "" } {
2526            set title [format "%s (%s)" $title $units]
2527        }
2528    } else {
2529        set title $_title
2530    }
2531    # Make a swatch of the selected color
2532    if { [catch { $_image(legend) get 10 $imgY } pixel] != 0 } {
2533        #puts stderr "out of range: $imgY"
2534        return
2535    }
2536    if { ![info exists _image(swatch)] } {
2537        set _image(swatch) [image create photo -width 24 -height 24]
2538    }
2539    set color [eval format "\#%02x%02x%02x" $pixel]
2540    $_image(swatch) put black  -to 0 0 23 23
2541    $_image(swatch) put $color -to 1 1 22 22
2542    .rappturetooltip configure -icon $_image(swatch)
2543
2544    # Compute the value of the point
2545    if { [info exists _limits(vmax)] && [info exists _limits(vmin)] } {
2546        set t [expr 1.0 - (double($imgY) / double($imgHeight-1))]
2547        set value [expr $t * ($_limits(vmax) - $_limits(vmin)) + $_limits(vmin)]
2548    } else {
2549        set value 0.0
2550    }
2551    set tipx [expr $x + 15]
2552    set tipy [expr $y - 5]
2553    Rappture::Tooltip::text $c "$title $value"
2554    Rappture::Tooltip::tooltip show $c +$tipx,+$tipy   
2555}
2556
2557
2558# ----------------------------------------------------------------------
2559# USAGE: Slice move x|y|z <newval>
2560#
2561# Called automatically when the user drags the slider to move the
2562# cut plane that slices 3D data.  Gets the current value from the
2563# slider and moves the cut plane to the appropriate point in the
2564# data set.
2565# ----------------------------------------------------------------------
2566itcl::body Rappture::VtkStreamlinesViewer::Slice {option args} {
2567    switch -- $option {
2568        "move" {
2569            set axis [lindex $args 0]
2570            set oldval $_settings(axis-${axis}position)
2571            set newval [lindex $args 1]
2572            if {[llength $args] != 2} {
2573                error "wrong # args: should be \"Slice move x|y|z newval\""
2574            }
2575            set newpos [expr {0.01*$newval}]
2576            SendCmd "cutplane slice $axis $newpos"
2577        }
2578        "tooltip" {
2579            set axis [lindex $args 0]
2580            set val [$itk_component(${axis}CutScale) get]
2581            return "Move the [string toupper $axis] cut plane.\nCurrently:  $axis = $val%"
2582        }
2583        default {
2584            error "bad option \"$option\": should be axis, move, or tooltip"
2585        }
2586    }
2587}
2588
2589
2590# ----------------------------------------------------------------------
2591# USAGE: _dropdown post
2592# USAGE: _dropdown unpost
2593# USAGE: _dropdown select
2594#
2595# Used internally to handle the dropdown list for this combobox.  The
2596# post/unpost options are invoked when the list is posted or unposted
2597# to manage the relief of the controlling button.  The select option
2598# is invoked whenever there is a selection from the list, to assign
2599# the value back to the gauge.
2600# ----------------------------------------------------------------------
2601itcl::body Rappture::VtkStreamlinesViewer::Combo {option} {
2602    set c $itk_component(view)
2603    switch -- $option {
2604        post {
2605            foreach { x1 y1 x2 y2 } [$c bbox title] break
2606            set x1 [expr [winfo width $itk_component(view)] - [winfo reqwidth $itk_component(fieldmenu)]]
2607            set x [expr $x1 + [winfo rootx $itk_component(view)]]
2608            set y [expr $y2 + [winfo rooty $itk_component(view)]]
2609            puts stderr "combo x=$x y=$y"
2610            tk_popup $itk_component(fieldmenu) $x $y
2611        }
2612        activate {
2613            $c itemconfigure title -fill red
2614        }
2615        deactivate {
2616            $c itemconfigure title -fill white
2617        }
2618        invoke {
2619            $itk_component(field) value $_currentField
2620            AdjustSetting streamlines-field
2621        }
2622        default {
2623            error "bad option \"$option\": should be post, unpost, select"
2624        }
2625    }
2626}
Note: See TracBrowser for help on using the repository browser.