source: branches/blt4/gui/scripts/sequenceresult.tcl @ 2287

Last change on this file since 2287 was 2201, checked in by gah, 13 years ago
File size: 25.1 KB
Line 
1
2# ----------------------------------------------------------------------
3#  COMPONENT: sequenceresult - series of results forming an animation
4#
5#  This widget displays a series of results of the same type that are
6#  grouped together and displayed as an animation.  The user can play
7#  through the results, or single step through individual values.
8# ======================================================================
9#  AUTHOR:  Michael McLennan, Purdue University
10#  Copyright (c) 2004-2005  Purdue Research Foundation
11#
12#  See the file "license.terms" for information on usage and
13#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14# ======================================================================
15package require Itk
16package require BLT
17
18option add *SequenceResult.width 3i widgetDefault
19option add *SequenceResult.height 3i widgetDefault
20option add *SequenceResult.controlBackground gray widgetDefault
21option add *SequenceResult.dialProgressColor #ccccff widgetDefault
22option add *SequenceResult.font \
23    -*-helvetica-medium-r-normal-*-12-* widgetDefault
24option add *SequenceResult.boldFont \
25    -*-helvetica-bold-r-normal-*-12-* widgetDefault
26
27itcl::class Rappture::SequenceResult {
28    inherit itk::Widget
29
30    constructor {args} {
31        # defined below
32    }
33    destructor {
34        # defined below
35    }
36    public method add {dataobj {settings ""}}
37    public method get {}
38    public method delete {args}
39    public method scale {args}
40    public method parameters {title args} {
41        # do nothing
42    }
43    public method download {option args}
44
45    public method play {}
46    public method pause {}
47    public method goto {{newval ""}}
48
49    protected method _rebuild {args}
50    protected method _playFrame {}
51    protected method _fixValue {}
52    private method Capture {w h}
53    private method Animate {w h}
54    private method VerifySequence {}
55    private method BuildViewer { viewer }
56    private method AnimationPopup { popup info }
57    private variable _dispatcher "" ;   # dispatcher for !events
58    private variable _dlist ""      ;   # list of data objects
59    private variable _topmost ""    ;   # topmost data object in _dlist
60    private variable _indices ""    ;   # list of active indices
61    private variable _pos 0         ;   # current position in the animation
62    private variable _afterId ""    ;   # current "after" event for play op
63
64    private variable _viewerclass "";   # Class of viewer.
65    private variable _animate   0 ;     # Indicates if the sequence can be
66                                        # animated (i.e. produce an animated
67                                        # gif or mpeg video).
68    private variable _popup "";         # Popup window for dialog.
69    private common _play            ;   # options for "play" operation
70
71    private variable _class "";         # Class of element in sequence.
72    private variable _dim 0;            # Dimension elements in sequence.
73    private variable _mode "";          # Mode of viewer.
74
75    set _play(speed) 60
76    set _play(loop) 0
77}
78
79itk::usual SequenceResult {
80    keep -background -foreground -cursor -font
81}
82
83# ----------------------------------------------------------------------
84# CONSTRUCTOR
85# ----------------------------------------------------------------------
86itcl::body Rappture::SequenceResult::constructor {args} {
87    Rappture::dispatcher _dispatcher
88    $_dispatcher register !rebuild
89    $_dispatcher dispatch $this !rebuild [itcl::code $this _rebuild]
90
91    option add hull.width hull.height
92    pack propagate $itk_component(hull) no
93
94    itk_component add player {
95        frame $itk_interior.player
96    }
97    pack $itk_component(player) -side bottom -fill x
98    grid columnconfigure $itk_component(player) 1 -weight 1
99
100    itk_component add play {
101        button $itk_component(player).play \
102            -bitmap [Rappture::icon play] \
103            -command [itcl::code $this play]
104    }
105    grid $itk_component(play) -row 0 -rowspan 2 -column 0 \
106        -ipadx 2 -padx {0 4} -pady 4 -sticky nsew
107
108    itk_component add dial {
109        Rappture::Radiodial $itk_component(player).dial \
110            -length 10 -valuewidth 0 -valuepadding 0 -padding 6 \
111            -linecolor "" -activelinecolor "" \
112            -knobimage [Rappture::icon knob2] -knobposition center@middle
113    } {
114        usual
115        keep -dialprogresscolor
116    }
117    grid $itk_component(dial) -row 1 -column 1 -sticky ew
118    bind $itk_component(dial) <<Value>> [itcl::code $this _fixValue]
119
120    itk_component add info {
121        frame $itk_component(player).info
122    }
123    grid $itk_component(info) -row 0 -column 1 -columnspan 2 -sticky ew
124
125    itk_component add indexLabel {
126        label $itk_component(info).ilabel
127    } {
128        usual
129        rename -font -boldfont boldFont Font
130    }
131    pack $itk_component(indexLabel) -side left
132
133    itk_component add indexValue {
134        label $itk_component(info).ivalue -padx 0
135    }
136    pack $itk_component(indexValue) -side left
137
138    # add an element.about.label stanza
139    itk_component add eleLabel {
140        label $itk_component(info).elabel -padx 10
141    }
142    pack $itk_component(eleLabel) -side left
143
144    itk_component add options {
145        button $itk_component(player).options -text "Options..." \
146            -padx 1 -pady 0 -relief flat -overrelief raised
147    }
148    grid $itk_component(options) -row 1 -column 2 -sticky sw
149
150    #
151    # Popup option panel
152    #
153    set fn [option get $itk_component(hull) font Font]
154    set bfn [option get $itk_component(hull) boldFont Font]
155
156    Rappture::Balloon $itk_component(hull).popup \
157        -title "Player Settings" -padx 4 -pady 4
158    set inner [$itk_component(hull).popup component inner]
159
160    label $inner.loopl -text "Loop:" -font $bfn
161    grid $inner.loopl -row 0 -column 0 -sticky e
162    radiobutton $inner.loopOn -text "Play once and stop" -font $fn \
163        -variable ::Rappture::SequenceResult::_play(loop) -value 0
164    grid $inner.loopOn -row 0 -column 1 -sticky w
165    radiobutton $inner.loopOff -text "Play continuously" -font $fn \
166        -variable ::Rappture::SequenceResult::_play(loop) -value 1
167    grid $inner.loopOff -row 1 -column 1 -sticky w
168    grid rowconfigure $inner 2 -minsize 8
169
170    label $inner.speedl -text "Speed:" -font $bfn
171    grid $inner.speedl -row 3 -column 0 -sticky e
172    frame $inner.speed
173    grid $inner.speed -row 3 -column 1 -sticky ew
174    label $inner.speed.slowl -text "Slower" -font $fn
175    pack $inner.speed.slowl -side left
176    ::scale $inner.speed.value -from 100 -to 1 \
177        -showvalue 0 -orient horizontal \
178        -variable ::Rappture::SequenceResult::_play(speed)
179    pack $inner.speed.value -side left
180    label $inner.speed.fastl -text "Faster" -font $fn
181    pack $inner.speed.fastl -side left
182
183    $itk_component(options) configure -command \
184        [list $itk_component(hull).popup activate $itk_component(options) above]
185
186    #
187    # Main viewer
188    #
189    itk_component add area {
190        frame $itk_interior.area
191    }
192    pack $itk_component(area) -expand yes -fill both
193
194    eval itk_initialize $args
195}
196
197# ----------------------------------------------------------------------
198# DESTRUCTOR
199# ----------------------------------------------------------------------
200itcl::body Rappture::SequenceResult::destructor {} {
201    pause  ;# stop any animation that might be playing
202}
203
204# ----------------------------------------------------------------------
205# USAGE: add <sequence> ?<settings>?
206#
207# Clients use this to add a data sequence to the viewer.  The optional
208# <settings> are used to configure the display of the data.  Allowed
209# settings are -color, -brightness, -width, -linestyle and -raise.
210# The only setting used here is -raise, which indicates the current
211# object.
212# ----------------------------------------------------------------------
213itcl::body Rappture::SequenceResult::add {dataobj {settings ""}} {
214    array set params {
215        -color auto
216        -brightness 0
217        -width 1
218        -raise 0
219        -linestyle solid
220        -description ""
221        -param ""
222    }
223    foreach {opt val} $settings {
224        if {![info exists params($opt)]} {
225            error "bad setting \"$opt\": should be [join [lsort [array names params]] {, }]"
226        }
227        set params($opt) $val
228    }
229
230    if {$params(-raise) && "" == $_topmost} {
231        set _topmost $dataobj
232    }
233    lappend _dlist $dataobj
234    $_dispatcher event -idle !rebuild
235}
236
237# ----------------------------------------------------------------------
238# USAGE: get
239#
240# Clients use this to query the list of data objects being displayed,
241# in order from bottom to top of this result.
242# ----------------------------------------------------------------------
243itcl::body Rappture::SequenceResult::get {} {
244    # put the dataobj list in order according to -raise options
245    set dlist $_dlist
246
247    set i [lsearch $_dlist $_topmost]
248    if {$i >= 0} {
249        set dlist [lreplace $dlist $i $i]
250        set dlist [linsert $dlist 0 $_topmost]
251    }
252    return $dlist
253}
254
255# ----------------------------------------------------------------------
256# USAGE: delete ?<dataobj1> <dataobj2> ...?
257#
258# Clients use this to delete a data object from the viewer.  If no
259# data objects are specified, then all data objects are deleted.
260# ----------------------------------------------------------------------
261itcl::body Rappture::SequenceResult::delete {args} {
262    if {[llength $args] == 0} {
263        set args $_dlist
264    }
265    pause
266
267    # delete all specified curves
268    set changed 0
269    foreach dataobj $args {
270        set pos [lsearch -exact $_dlist $dataobj]
271        if {$pos >= 0} {
272            set _dlist [lreplace $_dlist $pos $pos]
273            set changed 1
274
275            if {$dataobj == $_topmost} {
276                set _topmost ""
277            }
278        }
279    }
280
281    # if anything changed, then rebuild the plot
282    if {$changed} {
283        $_dispatcher event -idle !rebuild
284    }
285}
286
287# ----------------------------------------------------------------------
288# USAGE: scale ?<dataobj1> <dataobj2> ...?
289#
290# Sets the default limits for the overall plot according to the
291# limits of the data for all of the given <dataobj> objects.  This
292# accounts for all data objects--even those not showing on the screen.
293# Because of this, the limits are appropriate for all data objects as
294# the user scans through data in the ResultSet viewer.
295# ----------------------------------------------------------------------
296itcl::body Rappture::SequenceResult::scale {args} {
297    # do nothing
298}
299
300# ----------------------------------------------------------------------
301# USAGE: download coming
302# USAGE: download controls <downloadCommand>
303# USAGE: download now
304#
305# Clients use this method to create a downloadable representation
306# of the plot.  Returns a list of the form {ext string}, where
307# "ext" is the file extension (indicating the type of data) and
308# "string" is the data itself.
309# ----------------------------------------------------------------------
310itcl::body Rappture::SequenceResult::download {option args} {
311    if { ![winfo exists $itk_component(area).viewer] } {
312        return "";      # No data, no viewer, no download.
313    }
314    switch $option {
315        coming {
316            return [$itk_component(area).viewer download coming]
317        }
318        controls {
319            set _popup \
320                [eval $itk_component(area).viewer download controls $args]
321            if { $_animate } {
322                # Add the animation button to the download dialog
323                set inner [$_popup component inner]
324                if { ![winfo exists $inner.animation] } {
325                    radiobutton $inner.animation -text "Animation (GIF/MPEG)" \
326                        -variable ${_viewerclass}::_downloadPopup(format) \
327                        -value animation
328                    pack $inner.animation -anchor w
329                    update
330                }
331            }
332            return $_popup
333        }
334        now {
335            if { $_animate } {
336                # Examine the radiobutton variable to see if an animated GIF
337                # of MPEG movie was selected for download.
338                set fmt [set ${_viewerclass}::_downloadPopup(format)]
339                if { $fmt == "animation" } {
340                    if { [winfo exists $_popup] } {
341                        $_popup deactivate
342                    }
343                    set popup .sequenceanimationdownload
344                    return [AnimationPopup $popup $args]
345                }
346            }
347            # Otherwise, return download of single frame
348            return [eval $itk_component(area).viewer download now $args]
349        }
350        default {
351            error "bad option \"$option\": should be coming, controls, now"
352        }
353    }
354}
355
356# ----------------------------------------------------------------------
357# USAGE: play
358#
359# Invoked when the user hits the "play" button to play the current
360# sequence of frames as a movie.
361# ----------------------------------------------------------------------
362itcl::body Rappture::SequenceResult::play {} {
363    if { [llength $_indices] == 0 } {
364        return;                         # No frames (i.e. no data).
365    }
366    # Stop any existing animation.
367    pause
368
369    # At the end? then restart fresh
370    if {$_pos >= [llength $_indices]-1} {
371        goto 0
372    }
373
374    # Toggle the button to "pause" mode
375    $itk_component(play) configure \
376        -bitmap [Rappture::icon pause] \
377        -command [itcl::code $this pause]
378
379    global readyForNextFrame
380    set readyForNextFrame 1;            # By default, always ready
381    # Schedule the first frame
382    set delay [expr {int(ceil(pow($_play(speed)/10.0+2,2.0)*15))}]
383    set _afterId [after $delay [itcl::code $this _playFrame]]
384}
385
386# ----------------------------------------------------------------------
387# USAGE: pause
388#
389# Invoked when the user hits the "pause" button to stop playing the
390# current sequence of frames as a movie.
391# ----------------------------------------------------------------------
392itcl::body Rappture::SequenceResult::pause {} {
393    if {"" != $_afterId} {
394        catch {after cancel $_afterId}
395        set _afterId ""
396    }
397    global readyForNextFrame
398    set readyForNextFrame 1;            # By default, always ready
399
400    # toggle the button to "play" mode
401    $itk_component(play) configure \
402        -bitmap [Rappture::icon play] \
403        -command [itcl::code $this play]
404}
405
406# ----------------------------------------------------------------------
407# USAGE: goto ?<index>?
408#
409# Used internally to move the current position of the animation to
410# the frame at a particular <index>.  If the <index> is not specified,
411# then it returns the current position.
412# ----------------------------------------------------------------------
413itcl::body Rappture::SequenceResult::goto {{newval ""}} {
414    if {"" == $newval} {
415        return $_pos
416    }
417    set _pos $newval
418    set val [$itk_component(dial) get -format label @$_pos]
419    $itk_component(dial) current $val
420}
421
422# ----------------------------------------------------------------------
423# USAGE: _rebuild
424#
425# Invoked automatically whenever the data displayed in this viewer
426# changes.  Loads the data from the topmost (current) value into
427# the viewer.
428# ----------------------------------------------------------------------
429itcl::body Rappture::SequenceResult::_rebuild {args} {
430    if {"" == $_topmost && [llength $_dlist] > 0} {
431        set _topmost [lindex $_dlist 0]
432    }
433
434    VerifySequence
435
436    # If we have any data, then show the viewer.  Otherwise, hide it.
437    set viewer $itk_component(area).viewer
438    if { [winfo exists $viewer] } {
439        if { "" == $_topmost } {
440            pack forget $viewer
441            pack forget $itk_component(player)
442            return
443        }
444        pack $viewer -expand yes -fill both
445        pack $itk_component(player) -side bottom -fill x
446    } else {
447        if { "" == $_topmost } {
448            return
449        }
450        BuildViewer $viewer
451    }
452
453    # Load the current sequence info the viewer.
454    $itk_component(indexLabel) configure -text [$_topmost hints indexlabel]
455
456    $viewer delete
457    $itk_component(dial) clear
458
459    set max [$_topmost size]
460    set all ""
461    for {set i 0} {$i < $max} {incr i} {
462        eval lappend all [$_topmost value $i]
463    }
464    eval $viewer scale $all
465
466    set _indices ""
467    for {set i 0} {$i < $max} {incr i} {
468        set index [$_topmost index $i]
469        eval $itk_component(dial) add $index
470        lappend _indices [lindex $index 0]
471    }
472    _fixValue
473}
474
475# ----------------------------------------------------------------------
476# USAGE: _playFrame
477#
478# Used internally to advance each frame in the animation.  Advances
479# the frame and displays it.  When we reach the end of the animation,
480# we either loop back or stop.
481# ----------------------------------------------------------------------
482itcl::body Rappture::SequenceResult::_playFrame {} {
483    global readyForNextFrame
484    if { $readyForNextFrame } {
485        set _pos [expr {$_pos+1}]
486        set last [expr {[llength $_indices]-1}]
487       
488        if {$_pos > $last} {
489            if {$_play(loop)} {
490                set _pos 0
491            } else {
492                set _pos $last
493                pause
494                return
495            }
496        }
497        goto $_pos
498        set delay [expr {int(ceil(pow($_play(speed)/10.0+2,2.0)*15))}]
499    } else {
500        set delay 50;                   # Poll for completion
501    }
502    set _afterId [after $delay [itcl::code $this _playFrame]]
503}
504
505# ----------------------------------------------------------------------
506# USAGE: _fixValue
507#
508# Invoked automatically whenever the value on the dial changes.
509# Updates the viewer to display the value for the selected result.
510# ----------------------------------------------------------------------
511itcl::body Rappture::SequenceResult::_fixValue {} {
512    set viewer $itk_component(area).viewer
513    if {![winfo exists $viewer]} {
514        return
515    }
516    $viewer delete
517    if { $_topmost == "" } {
518        return
519    }
520    set val [$itk_component(dial) get -format label current]
521    set _pos [lsearch -glob $_indices $val*]
522    # populate the label for this element
523    if { "" != [$_topmost hints indexlabel] } {
524        $itk_component(indexValue) configure -text "= $val"
525    }
526    $itk_component(eleLabel) configure -text "[$_topmost label $_pos]"
527    foreach dataobj [$_topmost value $_pos] {
528        set settings "-color autoreset -width 2"
529        if {[catch {$dataobj hints style} style] == 0} {
530            eval lappend settings $style
531        }
532        if { [catch {$dataobj hints type} type] == 0} {
533            if {"" != $type} {
534                lappend settings -type $type
535            }
536        }
537        $viewer add $dataobj $settings
538    }
539}
540
541# ----------------------------------------------------------------------
542# USAGE: Capture
543#
544# Invoked automatically whenever the value on the dial changes.
545# Updates the viewer to display the value for the selected result.
546# ----------------------------------------------------------------------
547itcl::body Rappture::SequenceResult::Capture {w h} {
548    set viewer $itk_component(area).viewer
549    if {![winfo exists $viewer]} {
550        return
551    }
552    set label [$itk_component(indexLabel) cget -text]
553    set imageList {}
554    update idletasks
555    update
556    set old $_pos
557    for { set i 0 } { $i < [llength $_indices] } { incr i } {
558        goto $i
559        _fixValue
560        update
561        set img [$viewer snap 0 0]
562        $img export gif -file frame$i.gif
563        set value [$itk_component(indexValue) cget -text]
564        if { $value != "" } {
565            $img draw text "$label $value" 10 10 \
566                -font "Arial 10" -color white -shadow 1
567        }
568        lappend imageList $img
569    }
570    goto $old
571    _fixValue
572    update
573    set dest [image create picture]
574    eval $dest list replace 0 end $imageList
575    set delay [expr {int(ceil(pow($_play(speed)/10.0+2,2.0)*15))}]
576    set delay [expr $_play(speed)]
577    $dest export gif -animate -delay $delay -data bytes
578    eval image delete $dest $imageList
579    return [list .gif $bytes]
580}
581
582# ----------------------------------------------------------------------
583# USAGE: Animate
584#
585# Invoked automatically whenever the value on the dial changes.
586# Updates the viewer to display the value for the selected result.
587# ----------------------------------------------------------------------
588itcl::body Rappture::SequenceResult::Animate {w h} {
589    set viewer $itk_component(area).viewer
590    if {![winfo exists $viewer]} {
591        return
592    }
593    set save $_pos
594    $viewer delete                      ;# Delete all objects from the viewer
595    for { set i 0 } { $i < [llength $_indices] } { incr i } {
596        set dataobj [$_topmost value $i]
597        set val [$itk_component(dial) get -format label @$i]
598        set _pos [lsearch -glob $_indices $val*]
599        set settings "-color autoreset -width 2"
600        if {[catch {$dataobj hints style} style] == 0} {
601            eval lappend settings $style
602        }
603        if { [catch {$dataobj hints type} type] == 0} {
604            if {"" != $type} {
605                lappend settings -type $type
606            }
607        }
608        $viewer add $dataobj $settings
609        set img [$viewer snap $x $y]
610        # add caption to frame.
611        if { $val != "" } {
612            $img draw text "$label $val" 10 10 \
613                -font "Arial 10" -color white -shadow 1
614        }
615        $viewer delete
616        lappend imageList $img
617    }
618    set _pos $save
619    set dataobj [$_topmost value $_pos]
620    set settings "-color autoreset -width 2"
621    if {[catch {$dataobj hints style} style] == 0} {
622        eval lappend settings $style
623    }
624    if { [catch {$dataobj hints type} type] == 0} {
625        if {"" != $type} {
626            lappend settings -type $type
627        }
628    }
629    $viewer add $dataobj $settings
630
631    set dest [image create picture]
632    eval $dest list replace 0 end $imageList
633    set delay [expr {int(ceil(pow($_play(speed)/10.0+2,2.0)*15))}]
634    set delay [expr $_play(speed)]
635    $dest export gif -animate -delay $delay -data bytes
636    eval image delete $dest $imageList
637    return [list .gif $bytes]
638}
639
640#
641# VerifySequence --
642#
643#       Verifies the correctness of the sequence.  The sequence must
644#       contain a homogenous set of elements.  If the element is a
645#       "field", then also the dimensions of every component must be
646#       the same.
647#
648itcl::body Rappture::SequenceResult::VerifySequence {} {
649
650    # Step 1:   Use the topmost object as the standard.  Check whether it
651    #           can be sequenced.
652    set dataobj [lindex [$_topmost value 0] 0]
653    set _class [$dataobj info class]
654    set _dim 0
655    set mode ""
656    switch -- $_class {
657        ::Rappture::Curve -
658        ::Rappture::DataTable -
659        ::Rappture::Image {
660            # empty
661        }
662        ::Rappture::Field {
663            set _dim [lindex [$dataobj components -dimensions] 0]
664            switch $_dim {
665                2D {
666                    if { [$dataobj isunirect2d] } {
667                        if { [$dataobj hints type] == "contour" } {
668                            set mode "vtkcontour"
669                        } else {
670                            set mode "heightmap"
671                        }
672                    } else {
673                        set mode "vtk"
674                    }
675                    Rappture::Field2DResult $viewer -mode $mode
676                }
677                "3D" {
678                    # empty
679                }
680                default {
681                    error "Found field element $_class with $_dim dimensions"
682                }
683            }
684        }
685        ::Rappture::LibraryObj {
686            set type [$dataobj element -as type]
687            if { $type != "structure" } {
688                error "Don't know how to view sequences of $type"
689            }
690        }
691        default {
692            puts stderr "Don't know how to view sequences of type \"$_class\""
693            puts stderr "Is the sequence empty?"
694            return 0
695        }
696    }
697
698    # Step 2:   Review all the data objects.  They must be all of the same
699    #           class (e.g. can't mix curves with images).  Also check that
700    #           fields are all the same dimension.
701    foreach dataobj $_dlist {
702        set dataobj [lindex [$dataobj value 0] 0]
703        set class [$dataobj info class]
704        if { $_class != $class } {
705            puts stderr "Found element \"$class\" in sequence of \"$_class\""
706            continue
707        }
708        if { $class == "::Rappture::Field" } {
709            # check to see if the dimensions are the same for all components
710            # in the elements of the field. I dont think we can display fields
711            # of differing dimensions within the same field object.
712            foreach dim [$dataobj components -dimensions]  {
713                if { $_dim != $dim } {
714                    error "Found field element of dimension \"$dim\" in sequence of $_dim dimension elements"
715                }
716            }
717            continue
718        }
719    }
720    if { $_class == "" } {
721        puts stderr "Don't know how to view sequences of class \"$_class\""
722        puts stderr "Is the sequence empty?"
723        return 0
724    }
725}
726
727itcl::body Rappture::SequenceResult::AnimationPopup { popup info } {
728    if { ![winfo exists $popup] } {
729        # Create a popup for the print dialog
730        Rappture::Balloon $popup -title "Save as animation..."
731        set inner [$popup component inner]
732
733        # Create the print dialog widget and add it to the the balloon popup.
734        Rappture::SequenceAnimation $inner.print $this
735        $popup configure -deactivatecommand [list $inner.print reset]
736        blt::table $inner 0,0 $inner.print -fill both
737    }
738    update
739    # Activate the popup and call for the output.
740    foreach { widget toolName plotName } $info break
741    $popup activate $widget left
742    set inner [$popup component inner]
743    set output [$inner.print print "image" $toolName $plotName]
744    $popup deactivate
745    return $output
746}
747
748
749itcl::body Rappture::SequenceResult::BuildViewer { viewer } {
750    switch -- $_class {
751        ::Rappture::Curve {
752            Rappture::XyResult $viewer
753            set _viewerclass ::Rappture::XyResult
754            set _animate 1
755        }
756        ::Rappture::DataTable {
757            Rappture::DataTable $viewer
758            set _viewerclass ::Rappture::DataTable
759        }
760        ::Rappture::Image {
761            Rappture::ImageResult $viewer
762            set _viewerclass ::Rappture::ImageResult
763            set _animate 1
764        }
765        ::Rappture::Field {
766            switch -- $_dim {
767                2D {
768                    Rappture::Field2DResult $viewer -mode $mode
769                    if { $_mode == "heightmap" } {
770                        set _viewerclass ::Rappture::HeightmapViewer
771                        set _animate 1
772                    }
773                }
774                3D {
775                    Rappture::Field3DResult $viewer
776                    set _viewerclass ::Rappture::NanovisViewer
777                    set _animate 1
778                }
779            }
780        }
781        ::Rappture::LibraryObj {
782            Rappture::DeviceResult $viewer
783            set _viewerclass ::Rappture::MolvisViewer
784            set _animate 1
785        }
786    }
787    pack $viewer -expand yes -fill both
788}
Note: See TracBrowser for help on using the repository browser.