source: trunk/gui/scripts/resultviewer.tcl @ 428

Last change on this file since 428 was 428, checked in by mmc, 18 years ago
  • Added <sequence> for playing movie outputs and other sequences of related results.
  • Added <resize> option to <image> elements. This can be used to resize input items to a smaller size, so they don't take up so much real estate on the form.
  • Fixed a bug in right/below cases for popup balloons.
  • Reduced the tooltip delay time to 750ms to interact better with Rick's attention span.
  • Fixed the sash between grips to light up when you touch it, so it's easier to see.
File size: 15.1 KB
Line 
1# ----------------------------------------------------------------------
2#  COMPONENT: ResultViewer - plots a collection of related results
3#
4#  This widget plots a collection of results that all represent
5#  the same quantity, but for various ranges of input values.  It
6#  is normally used as part of an Analyzer, to plot the various
7#  results selected by a ResultSet.
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 Img
17
18itcl::class Rappture::ResultViewer {
19    inherit itk::Widget
20
21    itk_option define -width width Width 4i
22    itk_option define -height height Height 4i
23    itk_option define -colors colors Colors ""
24    itk_option define -clearcommand clearCommand ClearCommand ""
25    itk_option define -simulatecommand simulateCommand SimulateCommand ""
26
27    constructor {args} { # defined below }
28    destructor { # defined below }
29
30    public method add {index xmlobj path}
31    public method clear {{index ""}}
32    public method value {xmlobj}
33
34    public method plot {option args}
35    public method download {option}
36
37    protected method _plotAdd {xmlobj {settings ""}}
38    protected method _fixScale {args}
39    protected proc _xml2data {xmlobj path}
40
41    private variable _dispatcher ""  ;# dispatchers for !events
42    private variable _mode ""        ;# current plotting mode (xy, etc.)
43    private variable _mode2widget    ;# maps plotting mode => widget
44    private variable _dataslots ""   ;# list of all data objects in this widget
45    private variable _plotlist ""    ;# list of indices plotted in _dataslots
46}
47                                                                               
48itk::usual ResultViewer {
49    keep -background -foreground -cursor -font
50}
51
52# ----------------------------------------------------------------------
53# CONSTRUCTOR
54# ----------------------------------------------------------------------
55itcl::body Rappture::ResultViewer::constructor {args} {
56    # create a dispatcher for events
57    Rappture::dispatcher _dispatcher
58    $_dispatcher register !scale
59    $_dispatcher dispatch $this !scale \
60        [itcl::code $this _fixScale]
61
62    eval itk_initialize $args
63}
64
65# ----------------------------------------------------------------------
66# DESTRUCTOR
67# ----------------------------------------------------------------------
68itcl::body Rappture::ResultViewer::destructor {} {
69    foreach slot $_dataslots {
70        foreach obj $slot {
71            itcl::delete object $obj
72        }
73    }
74}
75
76# ----------------------------------------------------------------------
77# USAGE: add <index> <xmlobj> <path>
78#
79# Adds a new result to this result viewer at the specified <index>.
80# Data is taken from the <xmlobj> object at the <path>.
81# ----------------------------------------------------------------------
82itcl::body Rappture::ResultViewer::add {index xmlobj path} {
83    set dobj [_xml2data $xmlobj $path]
84
85    #
86    # If the index doesn't exist, then fill in empty slots and
87    # make it exist.
88    #
89    for {set i [llength $_dataslots]} {$i <= $index} {incr i} {
90        lappend _dataslots ""
91    }
92    set slot [lindex $_dataslots $index]
93    lappend slot $dobj
94    set _dataslots [lreplace $_dataslots $index $index $slot]
95
96    $_dispatcher event -idle !scale
97}
98
99# ----------------------------------------------------------------------
100# USAGE: clear ?<index>?
101#
102# Clears one or all results in this result viewer.
103# ----------------------------------------------------------------------
104itcl::body Rappture::ResultViewer::clear {{index ""}} {
105    if {"" != $index} {
106        # clear one result
107        if {$index >= 0 && $index < [llength $_dataslots]} {
108            set slot [lindex $_dataslots $index]
109            foreach dobj $slot {
110                itcl::delete object $dobj
111            }
112            set _dataslots [lreplace $_dataslots $index $index ""]
113        }
114    } else {
115        # clear all results
116        plot clear
117        foreach slot $_dataslots {
118            foreach dobj $slot {
119                itcl::delete object $dobj
120            }
121        }
122        set _dataslots ""
123    }
124}
125
126# ----------------------------------------------------------------------
127# USAGE: value <xmlobj>
128#
129# Convenience method for showing a single value.  Loads the value
130# into the widget via add/clear, then immediately plots the value.
131# This makes the widget consistent with other widgets, such as
132# the DeviceEditor, etc.
133# ----------------------------------------------------------------------
134itcl::body Rappture::ResultViewer::value {xmlobj} {
135    clear
136    if {"" != $xmlobj} {
137        add 0 $xmlobj ""
138        plot add 0 ""
139    }
140}
141
142# ----------------------------------------------------------------------
143# USAGE: plot add ?<index> <settings> <index> <settings> ...?
144# USAGE: plot clear
145#
146# Used to manipulate the contents of this viewer.  The "plot clear"
147# command clears the current viewer.  Data is still stored in the
148# widget, but the results are not shown on screen.  The "plot add"
149# command adds the data at the specified <index> to the plot.  If
150# the optional <settings> are specified, then they are applied
151# to the plot; otherwise, default settings are used.
152# ----------------------------------------------------------------------
153itcl::body Rappture::ResultViewer::plot {option args} {
154    switch -- $option {
155        add {
156            foreach {index opts} $args {
157                set reset "-color autoreset"
158                set slot [lindex $_dataslots $index]
159                foreach dobj $slot {
160                    set settings ""
161                    # start with color reset, only for first object in series
162                    if {"" != $reset} {
163                        set settings $reset
164                        set reset ""
165                    }
166                    # add default settings from data object
167                    if {[catch {$dobj hints style} style] == 0} {
168                        eval lappend settings $style
169                    }
170                    # add override settings passed in here
171                    eval lappend settings $opts
172
173                    _plotAdd $dobj $settings
174                }
175            }
176        }
177        clear {
178            # clear the contents of the current mode
179            if {"" != $_mode} {
180                $_mode2widget($_mode) delete
181            }
182            set _plotlist ""
183        }
184        default {
185            error "bad option \"$option\": should be add or clear"
186        }
187    }
188}
189
190# ----------------------------------------------------------------------
191# USAGE: _plotAdd <dataobj> <settings>
192#
193# Used internally to add a <dataobj> representing some data to
194# the plot at the top of this widget.  The data is added to the
195# current plot.  Use the "clear" function to clear before adding
196# new data.
197# ----------------------------------------------------------------------
198itcl::body Rappture::ResultViewer::_plotAdd {dataobj {settings ""}} {
199    switch -- [$dataobj info class] {
200        ::Rappture::Curve {
201            set mode "xy"
202            if {![info exists _mode2widget($mode)]} {
203                set w $itk_interior.xy
204                Rappture::XyResult $w
205                set _mode2widget($mode) $w
206            }
207        }
208        ::Rappture::Field {
209            set dims [lindex [lsort [$dataobj components -dimensions]] end]
210            switch -- $dims {
211                1D {
212                    set mode "xy"
213                    if {![info exists _mode2widget($mode)]} {
214                        set w $itk_interior.xy
215                        Rappture::XyResult $w
216                        set _mode2widget($mode) $w
217                    }
218                }
219                2D - 3D {
220                    set mode "contour"
221                    if {![info exists _mode2widget($mode)]} {
222                        set w $itk_interior.contour
223                        Rappture::ContourResult $w
224                        set _mode2widget($mode) $w
225                    }
226                }
227                default {
228                    error "can't handle [$dataobj components -dimensions] field"
229                }
230            }
231        }
232        ::Rappture::Mesh {
233            switch -- [$dataobj dimensions] {
234                2 {
235                    set mode "mesh"
236                    if {![info exists _mode2widget($mode)]} {
237                        set w $itk_interior.mesh
238                        Rappture::MeshResult $w
239                        set _mode2widget($mode) $w
240                    }
241                }
242                default {
243                    error "can't handle [$dataobj dimensions]D field"
244                }
245            }
246        }
247        ::Rappture::Table {
248            set cols [Rappture::EnergyLevels::columns $dataobj]
249            if {"" != $cols} {
250                set mode "energies"
251                if {![info exists _mode2widget($mode)]} {
252                    set w $itk_interior.energies
253                    Rappture::EnergyLevels $w
254                    set _mode2widget($mode) $w
255                }
256            }
257        }
258        ::Rappture::LibraryObj {
259            switch -- [$dataobj element -as type] {
260                string - log {
261                    set mode "log"
262                    if {![info exists _mode2widget($mode)]} {
263                        set w $itk_interior.log
264                        Rappture::TextResult $w
265                        set _mode2widget($mode) $w
266                    }
267                }
268                structure {
269                    set mode "structure"
270                    if {![info exists _mode2widget($mode)]} {
271                        set w $itk_interior.struct
272                        Rappture::DeviceResult $w
273                        set _mode2widget($mode) $w
274                    }
275                }
276                number - integer - boolean - choice {
277                    set mode "value"
278                    if {![info exists _mode2widget($mode)]} {
279                        set w $itk_interior.value
280                        Rappture::ValueResult $w
281                        set _mode2widget($mode) $w
282                    }
283                }
284            }
285        }
286        ::Rappture::Image {
287            set mode "image"
288            if {![info exists _mode2widget($mode)]} {
289                set w $itk_interior.image
290                Rappture::ImageResult $w
291                set _mode2widget($mode) $w
292            }
293        }
294        ::Rappture::Sequence {
295            set mode "sequence"
296            if {![info exists _mode2widget($mode)]} {
297                set w $itk_interior.image
298                Rappture::SequenceResult $w
299                set _mode2widget($mode) $w
300            }
301        }
302        default {
303            error "don't know how to plot <$type> data"
304        }
305    }
306
307    if {$mode != $_mode && $_mode != ""} {
308        set nactive [llength [$_mode2widget($_mode) get]]
309        if {$nactive > 0} {
310            return  ;# mixing data that doesn't mix -- ignore it!
311        }
312    }
313
314    # are we plotting in a new mode? then change widgets
315    if {$_mode2widget($mode) != [pack slaves $itk_interior]} {
316        # remove any current window
317        foreach w [pack slaves $itk_interior] {
318            pack forget $w
319        }
320        pack $_mode2widget($mode) -expand yes -fill both
321
322        set _mode $mode
323        $_dispatcher event -idle !scale
324    }
325    $_mode2widget($mode) add $dataobj $settings
326}
327
328# ----------------------------------------------------------------------
329# USAGE: _fixScale ?<eventArgs>...?
330#
331# Invoked automatically whenever a new dataset is added to fix the
332# overall scales of the viewer.  This makes the visualizer consistent
333# across all <dataobj> in this widget, so that it can plot all
334# available data.
335# ----------------------------------------------------------------------
336itcl::body Rappture::ResultViewer::_fixScale {args} {
337    if {"" != $_mode} {
338        set dlist ""
339        foreach slot $_dataslots {
340            foreach dobj $slot {
341                lappend dlist $dobj
342            }
343        }
344        eval $_mode2widget($_mode) scale $dlist
345    }
346}
347
348# ----------------------------------------------------------------------
349# USAGE: download coming
350# USAGE: download now
351#
352# Clients use this method to create a downloadable representation
353# of the plot.  Returns a list of the form {ext string}, where
354# "ext" is the file extension (indicating the type of data) and
355# "string" is the data itself.
356# ----------------------------------------------------------------------
357itcl::body Rappture::ResultViewer::download {option} {
358    if {"" == $_mode} {
359        return ""
360    }
361    return [$_mode2widget($_mode) download $option]
362}
363
364# ----------------------------------------------------------------------
365# USAGE: _xml2data <xmlobj> <path>
366#
367# Used internally to create a data object for the data at the
368# specified <path> in the <xmlobj>.
369# ----------------------------------------------------------------------
370itcl::body Rappture::ResultViewer::_xml2data {xmlobj path} {
371    set type [$xmlobj element -as type $path]
372    switch -- $type {
373        curve {
374            return [Rappture::Curve ::#auto $xmlobj $path]
375        }
376        field {
377            return [Rappture::Field ::#auto $xmlobj $path]
378        }
379        mesh {
380            return [Rappture::Mesh ::#auto $xmlobj $path]
381        }
382        table {
383            return [Rappture::Table ::#auto $xmlobj $path]
384        }
385        image {
386            return [Rappture::Image ::#auto $xmlobj $path]
387        }
388        sequence {
389            return [Rappture::Sequence ::#auto $xmlobj $path]
390        }
391        string - log {
392            return [$xmlobj element -as object $path]
393        }
394        structure {
395            return [$xmlobj element -as object $path]
396        }
397        number - integer - boolean - choice {
398            return [$xmlobj element -as object $path]
399        }
400        time - status {
401            return ""
402        }
403    }
404    error "don't know how to plot <$type> data"
405}
406
407# ----------------------------------------------------------------------
408# CONFIGURATION OPTION: -width
409# ----------------------------------------------------------------------
410itcl::configbody Rappture::ResultViewer::width {
411    set w [winfo pixels $itk_component(hull) $itk_option(-width)]
412    set h [winfo pixels $itk_component(hull) $itk_option(-height)]
413    if {$w == 0 || $h == 0} {
414        pack propagate $itk_component(hull) yes
415    } else {
416        component hull configure -width $w -height $h
417        pack propagate $itk_component(hull) no
418    }
419}
420
421# ----------------------------------------------------------------------
422# CONFIGURATION OPTION: -height
423# ----------------------------------------------------------------------
424itcl::configbody Rappture::ResultViewer::height {
425    set h [winfo pixels $itk_component(hull) $itk_option(-height)]
426    set w [winfo pixels $itk_component(hull) $itk_option(-width)]
427    if {$w == 0 || $h == 0} {
428        pack propagate $itk_component(hull) yes
429    } else {
430        component hull configure -width $w -height $h
431        pack propagate $itk_component(hull) no
432    }
433}
Note: See TracBrowser for help on using the repository browser.