source: branches/1.3/gui/scripts/vtkviewer.tcl @ 3785

Last change on this file since 3785 was 3785, checked in by gah, 11 years ago

fix multiple barchart results, fix PDB reader, dynamically create tabs for vtkviewer

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