source: trunk/gui/scripts/vtkheightmapviewer.tcl @ 2768

Last change on this file since 2768 was 2768, checked in by ldelgass, 13 years ago

Fix surface tab layout in vtk heightmap viewer

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