source: branches/r9/gui/scripts/sequence.tcl @ 4348

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

add drawings to sequence.

File size: 9.2 KB
Line 
1# -*- mode: tcl; indent-tabs-mode: nil -*-
2
3# ----------------------------------------------------------------------
4#  COMPONENT: sequence - represents a sequence of output results
5#
6#  This object represents a sequence of other output results.  Each
7#  element in the sequence has an index and a value.  All values in
8#  the sequence must have the same type, but they can all be curves,
9#  images, or other results.
10# ======================================================================
11#  AUTHOR:  Michael McLennan, Purdue University
12#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
13#
14#  See the file "license.terms" for information on usage and
15#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
16# ======================================================================
17package require Itcl
18package require BLT
19
20namespace eval Rappture { # forward declaration }
21
22itcl::class Rappture::Sequence {
23    constructor {xmlobj path} { # defined below }
24    destructor { # defined below }
25
26    public method value {pos}
27    public method label {pos}
28    public method index {pos}
29    public method size {}
30    public method hints {{keyword ""}}
31
32    private variable _xmlobj ""  ;# ref to lib obj with sequence data
33    private variable _dataobjs   ;# maps index => data object
34    private variable _labels     ;# maps index => labels
35    private variable _indices    ;# list of sorted index values
36    private variable _hints      ;# cache of hints stored in XML
37}
38
39# ----------------------------------------------------------------------
40# CONSTRUCTOR
41# ----------------------------------------------------------------------
42itcl::body Rappture::Sequence::constructor {xmlobj path} {
43    if {![Rappture::library isvalid $xmlobj]} {
44        error "bad value \"$xmlobj\": should be LibraryObj"
45    }
46    set _xmlobj [$xmlobj element -as object $path]
47
48    #
49    # Extract data values from the element definitions.
50    #
51    foreach name [$_xmlobj children -type element] {
52        set index [$xmlobj get $path.$name.index]
53        if {"" == $index} {
54            continue
55        }
56
57        # check for an element about.label stanza
58        set elelabel [$xmlobj get $path.$name.about.label]
59
60        set ctype ""
61        set _dataobjs($index) ""
62        set _labels($index) ""
63        foreach cname [$_xmlobj children $name] {
64            set type [$xmlobj element -as type $path.$name.$cname]
65            switch -- $type {
66                index {
67                    # ignore this
68                    continue
69                }
70                about {
71                    # ignore this
72                    continue
73                }
74                curve {
75                    set obj [Rappture::Curve ::\#auto $xmlobj $path.$name.$cname]
76                }
77                drawing {
78                    set obj [Rappture::Drawing ::\#auto $xmlobj $path.$name.$cname]
79                }
80                datatable {
81                    set obj [Rappture::DataTable ::\#auto $xmlobj $path.$name.$cname]
82                }
83                histogram {
84                    set obj [Rappture::Histogram ::\#auto $xmlobj $path.$name.$cname]
85                }
86                field {
87                    set obj [Rappture::Field ::\#auto $xmlobj $path.$name.$cname]
88                }
89                image {
90                    set obj [Rappture::Image ::\#auto $xmlobj $path.$name.$cname]
91                }
92                structure {
93                    # extract unique result set prefix
94                    scan $xmlobj "::libraryObj%d" rset
95
96                    # object rooted at x.sequence(y).element(z).structure
97                    set obj [$xmlobj element -as object $path.$name.$cname]
98
99                    # scene id (sequence id)
100                    set sceneid [$xmlobj element -as id $path]-$rset
101
102                    # sequence/element/frame number starting at 1
103                    set frameid [expr [$xmlobj element -as id $path.$name] + 1]
104
105                    # only supporting one molecule per structure at the moment
106                    # otherwise should go through all children that are molecules
107                    # and insert scene/frame data.
108                    $obj put "components.molecule.state" $frameid
109                    $obj put "components.molecule.model" $sceneid
110                }
111                default {
112                    error "don't know how to handle sequences of $type"
113                }
114            }
115            if {"" == $ctype} {
116                set ctype $type
117            }
118            if {$type == $ctype} {
119                lappend _dataobjs($index) $obj
120                set _labels($index) $elelabel
121            } else {
122                itcl::delete object $obj
123            }
124        }
125    }
126    #
127    # Generate a list of sorted index values.
128    #
129    set units [$xmlobj get $path.index.units]
130    if {"" != $units} {
131        # build up a list:  {10m 10} {10cm 0.1} ...
132        set vals ""
133        foreach key [array names _dataobjs] {
134            lappend vals [list $key [Rappture::Units::convert $key \
135                -context $units -to $units -units off]]
136        }
137
138        # sort according to raw values; store both values
139        set _indices [lsort -real -index 1 $vals]
140    } else {
141        # are the indices integers, reals, or strings?
142        set how -integer
143        foreach key [array names _dataobjs] {
144            if {[regexp {^[0-9]+[eE][-+]?[0-9]+|([0-9]+)?\.[0-9]+([eE][-+]?[0-9]+)?$} $key]} {
145                set how -real
146                break
147            } elseif {![regexp {^[0-9]+$} $key]} {
148                set how -dictionary
149                break
150            }
151        }
152
153        # keep a list of indices sorted in order
154        set _indices ""
155        if {[string equal $how -dictionary]} {
156            set n 0
157            foreach val [lsort $how [array names _dataobjs]] {
158                lappend _indices [list $val $n]
159                incr n
160            }
161        } else {
162            foreach val [lsort $how [array names _dataobjs]] {
163                lappend _indices [list $val $val]
164            }
165        }
166    }
167}
168
169# ----------------------------------------------------------------------
170# DESTRUCTOR
171# ----------------------------------------------------------------------
172itcl::body Rappture::Sequence::destructor {} {
173    foreach key [array names _dataobjs] {
174        eval itcl::delete object $_dataobjs($key)
175    }
176    itcl::delete object $_xmlobj
177}
178
179# ----------------------------------------------------------------------
180# USAGE: value <pos>
181#
182# Returns the value for the element as position <pos> in the
183# list of all elements.  Here, <pos> runs from 0 to size-1.
184# ----------------------------------------------------------------------
185itcl::body Rappture::Sequence::value {pos} {
186    set i [lindex [lindex $_indices $pos] 0]
187
188    # FIXME:  This is a bandaid on what appears to be a timing problem.
189    # This "dataobjs" method is now called before any sequence frames
190    # have been added.
191    if { ![info exists _dataobjs($i)] } {
192        return ""
193    }
194
195    return $_dataobjs($i)
196}
197
198# ----------------------------------------------------------------------
199# USAGE: label <pos>
200#
201# Returns the label for the element as position <pos> in the
202# list of all elements.  Here, <pos> runs from 0 to size-1.
203# ----------------------------------------------------------------------
204itcl::body Rappture::Sequence::label {pos} {
205    set i [lindex [lindex $_indices $pos] 0]
206
207    # FIXME:  This is a bandaid on what appears to be a timing problem.
208    # This "label" method is now called before any sequence frames
209    # have been added.
210    if { ![info exists _labels($i)] } {
211        return ""
212    }
213
214    return $_labels($i)
215}
216
217# ----------------------------------------------------------------------
218# USAGE: index <pos>
219#
220# Returns information about the index value for the element at
221# position <pos> in the list of all elements.  The return value is
222# a list of two elements:  {string rawNumberValue}.  Here, <pos>
223# runs from 0 to size-1.
224# ----------------------------------------------------------------------
225itcl::body Rappture::Sequence::index {pos} {
226    return [lindex $_indices $pos]
227}
228
229# ----------------------------------------------------------------------
230# USAGE: size
231#
232# Returns the number of elements in this sequence.
233# ----------------------------------------------------------------------
234itcl::body Rappture::Sequence::size {} {
235    return [llength $_indices]
236}
237
238# ----------------------------------------------------------------------
239# USAGE: hints ?<keyword>?
240#
241# Returns a list of key/value pairs for various hints about showing
242# this image.  If a particular <keyword> is specified, then it returns
243# the hint for that <keyword>, if it exists.
244# ----------------------------------------------------------------------
245itcl::body Rappture::Sequence::hints {{keyword ""}} {
246    if {![info exists _hints]} {
247        foreach {key path} {
248            label        about.label
249            indexlabel   index.label
250            indexdesc    index.description
251        } {
252            set str [$_xmlobj get $path]
253            if {"" != $str} {
254                set _hints($key) $str
255            }
256        }
257    }
258
259    if {$keyword != ""} {
260        if {[info exists _hints($keyword)]} {
261            return $_hints($keyword)
262        }
263        return ""
264    }
265    return [array get _hints]
266}
Note: See TracBrowser for help on using the repository browser.