source: branches/nanovis2/gui/scripts/heightmapviewer.tcl @ 3001

Last change on this file since 3001 was 2744, checked in by gah, 12 years ago
File size: 49.8 KB
Line 
1
2# ----------------------------------------------------------------------
3#  Component: heightmapviewer - 3D surface rendering
4#
5#  This widget performs surface rendering on 3D scalar/vector datasets.
6#  It connects to the Nanovis server running on a rendering farm,
7#  transmits data, and displays the results.
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# ======================================================================
15
16package require Itk
17package require BLT
18package require Img
19
20option add *HeightmapViewer.width 4i widgetDefault
21option add *HeightmapViewer.height 4i widgetDefault
22option add *HeightmapViewer.foreground black widgetDefault
23option add *HeightmapViewer.plotBackground black widgetDefault
24option add *HeightmapViewer.plotForeground white widgetDefault
25option add *HeightmapViewer.plotOutline white widgetDefault
26option add *HeightmapViewer.font -*-helvetica-medium-r-normal-*-12-* widgetDefault
27
28# must use this name -- plugs into Rappture::resources::load
29proc HeightmapViewer_init_resources {} {
30    Rappture::resources::register \
31        nanovis_server Rappture::HeightmapViewer::SetServerList
32}
33
34itcl::class Rappture::HeightmapViewer {
35    inherit Rappture::VisViewer
36
37    itk_option define -plotforeground plotForeground Foreground ""
38    itk_option define -plotbackground plotBackground Background ""
39    itk_option define -plotoutline plotOutline PlotOutline ""
40
41    constructor { hostlist args } {
42        Rappture::VisViewer::constructor $hostlist
43    } {
44        # defined below
45    }
46    destructor {
47        # defined below
48    }
49
50    public proc SetServerList { namelist } {
51        Rappture::VisViewer::SetServerList "nanovis" $namelist
52    }
53    public method add {dataobj {settings ""}}
54    public method get {args}
55    public method delete {args}
56    public method scale {args}
57    public method snap { w h }
58    public method download {option args}
59    public method parameters {title args} {
60        # do nothing
61    }
62    public method camera {option args}
63
64    protected method Connect {}
65    protected method Disconnect {}
66    public method isconnected {}
67
68    protected method SendCmd {string}
69    protected method ReceiveImage { args }
70    private method ReceiveLegend {tf vmin vmax size}
71    private method BuildViewTab {}
72    private method BuildCameraTab {}
73    private method PanCamera {}
74
75    private method AddImageControls { frame widget }
76    private method SetWaitVariable { value } {
77        set _getimage $value
78    }
79    private method GetWaitVariable {} {
80        return $_getimage
81    }
82    private method WaitForImage {} {
83        tkwait variable [itcl::scope _getimage]
84        return $_getimage
85    }
86
87    protected method CurrentSurfaces {{what -all}}
88    protected method Rebuild {}
89    protected method Zoom {option}
90    protected method Pan {option x y}
91    protected method Rotate {option x y}
92
93    protected method State {comp}
94    protected method FixSettings {what {value ""}}
95    protected method GetTransfuncData {dataobj comp}
96    protected method Resize {}
97    private method EventuallyResize { w h }
98
99    private variable _outbuf       ;# buffer for outgoing commands
100
101    private variable _dlist ""     ;# list of data objects
102    private variable _obj2style    ;# maps dataobj => style settings
103    private variable _obj2ovride   ;# maps dataobj => style override
104    private variable _click        ;# info used for Rotate operations
105    private variable _limits       ;# autoscale min/max for all axes
106    private variable _view         ;# view params for 3D view
107    private common _settings       ;# Array of used for global variables
108                                    # for checkbuttons and radiobuttons.
109    private variable _serverObjs   ;# contains all the dataobj-component
110                                   ;# to heightmaps in the server
111    private variable _location ""
112    private variable _first ""
113    private variable _width 0
114    private variable _height 0
115    private common _hardcopy
116    private variable _buffering 0
117    private variable _resizePending 0
118    private variable _resizeLegendPending 0
119    private variable _frame 0;          # Current frame number.
120    private variable _getimage 0;
121    private variable _downloadPopup
122}
123
124itk::usual HeightmapViewer {
125    keep -background -foreground -cursor -font
126    keep -plotbackground -plotforeground
127}
128
129# ----------------------------------------------------------------------
130# CONSTRUCTOR
131# ----------------------------------------------------------------------
132itcl::body Rappture::HeightmapViewer::constructor {hostlist args} {
133    set _serverType "nanovis"
134
135    # Draw legend event
136    $_dispatcher register !legend
137    $_dispatcher dispatch $this !legend \
138        "[itcl::code $this FixSettings legend]; list"
139
140    # Rebuild event
141    $_dispatcher register !rebuild
142    $_dispatcher dispatch $this !rebuild "[itcl::code $this Rebuild]; list"
143
144    # Resize event.
145    $_dispatcher register !resize
146    $_dispatcher dispatch $this !resize "[itcl::code $this Resize]; list"
147
148    set _outbuf ""
149
150    #
151    # Populate parser with commands handle incoming requests
152    #
153    $_parser alias image [itcl::code $this ReceiveImage]
154    $_parser alias legend [itcl::code $this ReceiveLegend]
155
156    array set _downloadPopup {
157        format image
158        image_controls ""
159    }
160    # Initialize the view to some default parameters.
161    array set _view {
162        theta   45
163        phi     45
164        psi     0
165        zoom    1.0
166        pan-x   0
167        pan-y   0
168    }
169    foreach val {xmin xmax ymin ymax zmin zmax vmin vmax} {
170        set _limits($val) ""
171    }
172    array set _settings [subst {
173        $this-pan-x             $_view(pan-x)
174        $this-pan-y             $_view(pan-y)
175        $this-phi               $_view(phi)
176        $this-psi               $_view(psi)
177        $this-theta             $_view(theta)
178        $this-surface           1
179        $this-xcutplane         0
180        $this-xcutposition      0
181        $this-ycutplane         0
182        $this-ycutposition      0
183        $this-zcutplane         0
184        $this-zcutposition      0
185        $this-zoom              $_view(zoom)
186    }]
187
188    itk_component add 3dview {
189        canvas $itk_component(plotarea).view \
190            -highlightthickness 0 -borderwidth 0
191    } {
192        usual
193        ignore -highlightthickness -borderwidth  -background
194    }
195    $_image(plot) configure -data ""
196    $itk_component(3dview) create image 0 0 -anchor nw -image $_image(plot)
197    set f [$itk_component(main) component controls]
198    itk_component add zoom {
199        frame $f.zoom
200    }
201    pack $itk_component(zoom) -side top
202
203    itk_component add reset {
204        button $f.reset -borderwidth 1 -padx 1 -pady 1 \
205            -highlightthickness 0 \
206            -image [Rappture::icon reset-view] \
207            -command [itcl::code $this Zoom reset]
208    } {
209        usual
210        ignore -highlightthickness
211    }
212    pack $itk_component(reset) -side top -padx 1 -pady { 4 0 }
213    Rappture::Tooltip::for $itk_component(reset) \
214        "Reset the view to the default zoom level"
215
216    itk_component add zoomin {
217        button $f.zin -borderwidth 1 -padx 1 -pady 1 \
218            -highlightthickness 0 \
219            -image [Rappture::icon zoom-in] \
220            -command [itcl::code $this Zoom in]
221    } {
222        usual
223        ignore -highlightthickness
224    }
225    pack $itk_component(zoomin) -side top -padx 1 -pady { 4 0 }
226    Rappture::Tooltip::for $itk_component(zoomin) "Zoom in"
227
228    itk_component add zoomout {
229        button $f.zout -borderwidth 1 -padx 1 -pady 1 \
230            -highlightthickness 0 \
231            -image [Rappture::icon zoom-out] \
232            -command [itcl::code $this Zoom out]
233    } {
234        usual
235        ignore -highlightthickness
236    }
237    pack $itk_component(zoomout) -side top -padx 1 -pady { 4 }
238    Rappture::Tooltip::for $itk_component(zoomout) "Zoom out"
239
240    itk_component add surface {
241        Rappture::PushButton $f.surface \
242            -onimage [Rappture::icon volume-on] \
243            -offimage [Rappture::icon volume-off] \
244            -command [itcl::code $this FixSettings surface] \
245            -variable [itcl::scope _settings($this-surface)]
246    }
247    $itk_component(surface) select
248    Rappture::Tooltip::for $itk_component(surface) \
249        "Toggle surfaces on/off"
250    pack $itk_component(surface) -padx 2 -pady 2
251
252    BuildViewTab
253    BuildCameraTab
254
255    set w [expr [winfo reqwidth $itk_component(hull)] - 80]
256    pack forget $itk_component(3dview)
257    pack $itk_component(3dview) -side left -fill both -expand yes
258
259
260    # Bindings for rotation via mouse
261    bind $itk_component(3dview) <ButtonPress-1> \
262        [itcl::code $this Rotate click %x %y]
263    bind $itk_component(3dview) <B1-Motion> \
264        [itcl::code $this Rotate drag %x %y]
265    bind $itk_component(3dview) <ButtonRelease-1> \
266        [itcl::code $this Rotate release %x %y]
267    bind $itk_component(3dview) <Configure> \
268        [itcl::code $this EventuallyResize %w %h]
269
270    # Bindings for panning via mouse
271    bind $itk_component(3dview) <ButtonPress-2> \
272        [itcl::code $this Pan click %x %y]
273    bind $itk_component(3dview) <B2-Motion> \
274        [itcl::code $this Pan drag %x %y]
275    bind $itk_component(3dview) <ButtonRelease-2> \
276        [itcl::code $this Pan release %x %y]
277
278    # Bindings for panning via keyboard
279    bind $itk_component(3dview) <KeyPress-Left> \
280        [itcl::code $this Pan set -10 0]
281    bind $itk_component(3dview) <KeyPress-Right> \
282        [itcl::code $this Pan set 10 0]
283    bind $itk_component(3dview) <KeyPress-Up> \
284        [itcl::code $this Pan set 0 -10]
285    bind $itk_component(3dview) <KeyPress-Down> \
286        [itcl::code $this Pan set 0 10]
287    bind $itk_component(3dview) <Shift-KeyPress-Left> \
288        [itcl::code $this Pan set -2 0]
289    bind $itk_component(3dview) <Shift-KeyPress-Right> \
290        [itcl::code $this Pan set 2 0]
291    bind $itk_component(3dview) <Shift-KeyPress-Up> \
292        [itcl::code $this Pan set 0 -2]
293    bind $itk_component(3dview) <Shift-KeyPress-Down> \
294        [itcl::code $this Pan set 0 2]
295
296    # Bindings for zoom via keyboard
297    bind $itk_component(3dview) <KeyPress-Prior> \
298        [itcl::code $this Zoom out]
299    bind $itk_component(3dview) <KeyPress-Next> \
300        [itcl::code $this Zoom in]
301
302    bind $itk_component(3dview) <Enter> "focus $itk_component(3dview)"
303
304    if {[string equal "x11" [tk windowingsystem]]} {
305        # Bindings for zoom via mouse
306        bind $itk_component(3dview) <4> [itcl::code $this Zoom out]
307        bind $itk_component(3dview) <5> [itcl::code $this Zoom in]
308    }
309
310    set _image(download) [image create photo]
311    eval itk_initialize $args
312    Connect
313}
314
315# ----------------------------------------------------------------------
316# DESTRUCTOR
317# ----------------------------------------------------------------------
318itcl::body Rappture::HeightmapViewer::destructor {} {
319    $_dispatcher cancel !rebuild
320    image delete $_image(plot)
321    image delete $_image(legend)
322    image delete $_image(download)
323}
324
325# ----------------------------------------------------------------------
326# USAGE: add <dataobj> ?<settings>?
327#
328# Clients use this to add a data object to the plot.  The optional
329# <settings> are used to configure the plot.  Allowed settings are
330# -color, -brightness, -width, -linestyle, and -raise.
331# ----------------------------------------------------------------------
332itcl::body Rappture::HeightmapViewer::add {dataobj {settings ""}} {
333    array set params {
334        -color auto
335        -width 1
336        -linestyle solid
337        -brightness 0
338        -raise 0
339        -description ""
340        -param ""
341    }
342    foreach {opt val} $settings {
343        if {![info exists params($opt)]} {
344            error "bad setting \"$opt\": should be [join [lsort [array names params]] {, }]"
345        }
346        set params($opt) $val
347    }
348    if {$params(-color) == "auto" || $params(-color) == "autoreset"} {
349        # can't handle -autocolors yet
350        set params(-color) black
351    }
352    set pos [lsearch -exact $dataobj $_dlist]
353    if {$pos < 0} {
354        lappend _dlist $dataobj
355        set _obj2ovride($dataobj-color) $params(-color)
356        set _obj2ovride($dataobj-width) $params(-width)
357        set _obj2ovride($dataobj-raise) $params(-raise)
358        set _obj2ovride($dataobj-brightness) $params(-brightness)
359        $_dispatcher event -idle !rebuild
360    }
361    scale $dataobj
362}
363
364# ----------------------------------------------------------------------
365# USAGE: get ?-objects?
366# USAGE: get ?-image 3dview|legend?
367#
368# Clients use this to query the list of objects being plotted, in
369# order from bottom to top of this result.  The optional "-image"
370# flag can also request the internal images being shown.
371# ----------------------------------------------------------------------
372itcl::body Rappture::HeightmapViewer::get { args } {
373    if {[llength $args] == 0} {
374        set args "-objects"
375    }
376
377    set op [lindex $args 0]
378    switch -- $op {
379      -objects {
380        # put the dataobj list in order according to -raise options
381        set dlist $_dlist
382        foreach obj $dlist {
383            if { [info exists _obj2ovride($obj-raise)] &&
384                 $_obj2ovride($obj-raise)} {
385                set i [lsearch -exact $dlist $obj]
386                if {$i >= 0} {
387                    set dlist [lreplace $dlist $i $i]
388                    lappend dlist $obj
389                }
390            }
391        }
392        return $dlist
393      }
394      -image {
395        if {[llength $args] != 2} {
396            error "wrong # args: should be \"get -image 3dview|legend\""
397        }
398        switch -- [lindex $args end] {
399            3dview {
400                return $_image(plot)
401            }
402            legend {
403                return $_image(legend)
404            }
405            default {
406                error "bad image name \"[lindex $args end]\": should be 3dview or legend"
407            }
408        }
409      }
410      default {
411        error "bad option \"$op\": should be -objects or -image"
412      }
413    }
414}
415
416# ----------------------------------------------------------------------
417# USAGE: delete ?<dataobj1> <dataobj2> ...?
418#
419# Clients use this to delete a dataobj from the plot.  If no dataobjs
420# are specified, then all dataobjs are deleted.
421# ----------------------------------------------------------------------
422itcl::body Rappture::HeightmapViewer::delete { args } {
423    if {[llength $args] == 0} {
424        set args $_dlist
425    }
426
427    # delete all specified dataobjs
428    set changed 0
429    foreach dataobj $args {
430        set pos [lsearch -exact $_dlist $dataobj]
431        if {$pos >= 0} {
432            set _dlist [lreplace $_dlist $pos $pos]
433            foreach key [array names _obj2ovride $dataobj-*] {
434                unset _obj2ovride($key)
435            }
436            array unset _serverObjs $dataobj-*
437            set changed 1
438        }
439    }
440
441    # if anything changed, then rebuild the plot
442    if {$changed} {
443        $_dispatcher event -idle !rebuild
444    }
445}
446
447# ----------------------------------------------------------------------
448# USAGE: scale ?<data1> <data2> ...?
449#
450# Sets the default limits for the overall plot according to the
451# limits of the data for all of the given <data> objects.  This
452# accounts for all objects--even those not showing on the screen.
453# Because of this, the limits are appropriate for all objects as
454# the user scans through data in the ResultSet viewer.
455# ----------------------------------------------------------------------
456itcl::body Rappture::HeightmapViewer::scale { args } {
457    if 0 {
458    foreach val {xmin xmax ymin ymax zmin zmax vmin vmax} {
459        set _limits($val) ""
460    }
461    }
462    foreach obj $args {
463        foreach axis {x y z v} {
464            foreach {min max} [$obj limits $axis] break
465            if {"" != $min && "" != $max} {
466                if {"" == $_limits(${axis}min)} {
467                    set _limits(${axis}min) $min
468                    set _limits(${axis}max) $max
469                } else {
470                    if {$min < $_limits(${axis}min)} {
471                        set _limits(${axis}min) $min
472                    }
473                    if {$max > $_limits(${axis}max)} {
474                        set _limits(${axis}max) $max
475                    }
476                }
477                set _limits(${axis}range) [expr {$max - $min}]
478            }
479        }
480    }
481}
482
483# ----------------------------------------------------------------------
484# USAGE: download coming
485# USAGE: download controls <downloadCommand>
486# USAGE: download now
487#
488# Clients use this method to create a downloadable representation
489# of the plot.  Returns a list of the form {ext string}, where
490# "ext" is the file extension (indicating the type of data) and
491# "string" is the data itself.
492# ----------------------------------------------------------------------
493itcl::body Rappture::HeightmapViewer::download {option args} {
494    switch $option {
495        coming {
496            if {[catch {
497                blt::winop snap $itk_component(plotarea) $_image(download)
498            }]} {
499                $_image(download) configure -width 1 -height 1
500                $_image(download) put #000000
501            }
502        }
503        controls {
504            set popup .heightmapviewerdownload
505            if {![winfo exists $popup]} {
506                # If we haven't created the popup yet, do it now
507                Rappture::Balloon $popup \
508                    -title "[Rappture::filexfer::label downloadWord] as..."
509                set inner [$popup component inner]
510                label $inner.summary -text "" -anchor w
511                pack $inner.summary -side top
512                radiobutton $inner.image -text "Image (PNG/JPEG/GIF)" \
513                    -variable \
514                    ::Rappture::HeightmapViewer::_downloadPopup(format) \
515                    -font "Arial 10 " \
516                    -value image
517                Rappture::Tooltip::for $inner.image "Save as image."
518                pack $inner.image -anchor w
519                button $inner.go -text [Rappture::filexfer::label download] \
520                    -command [lindex $args 0]
521                pack $inner.go -side bottom -pady 4
522                $inner.image select
523            } else {
524                set inner [$popup component inner]
525            }
526            set num [llength [get]]
527            set num [expr {($num == 1) ? "1 result" : "$num results"}]
528            set word [Rappture::filexfer::label downloadWord]
529            $inner.summary configure -text "$word $num in the following format:"
530            update idletasks ;          # Fix initial sizes
531            return $popup
532        }
533        now {
534            set popup .heightmapviewerdownload
535            if { [winfo exists $popup] } {
536                $popup deactivate
537            }
538            switch -- $_downloadPopup(format) {
539                "image" {
540                    set popup .heightmapviewerimage
541                    if { ![winfo exists $popup] } {
542                        # Create the balloon popup and and the print image
543                        # dialog widget to it.
544                        Rappture::Balloon $popup -title "Save as image..." \
545                            -deactivatecommand \
546                            [itcl::code $this SetWaitVariable 0]
547                        set inner [$popup component inner]
548                        AddImageControls $inner [lindex $args 0]
549                    } else {
550                        set inner [$popup component inner]
551                    }                   
552                    set _downloadPopup(image_controls) $inner
553                    update
554                    # Activate the popup and call for the output.
555                    foreach { widget toolName plotName } $args break
556                    SetWaitVariable 0
557                    $popup activate $widget left
558                    set bool [WaitForImage]
559                    $popup deactivate
560                    if { $bool } {
561                        set inner $_downloadPopup(image_controls)
562                        set fmt [$inner.format translate [$inner.format value]]
563                        # Get the image data (as base64) and decode it back to
564                        # binary.  This is better than writing to temporary
565                        # files.  When we switch to the BLT picture image it
566                        # won't be necessary to decode the image data.
567                        switch $fmt {
568                            "jpg" {
569                                set bytes [$_image(download) data \
570                                               -format "jpeg -quality 100"]
571                            }
572                            "png" {
573                                set bytes [$_image(download) data -format "png"]
574                            }
575                            "gif" {
576                                set bytes [$_image(download) data -format "gif"]
577                            }
578                            default {
579                                return ""
580                            }
581                        }
582                        set bytes [Rappture::encoding::decode -as b64 $bytes]
583                        return [list .$fmt $bytes]
584                    }
585                }
586            }
587            return ""
588        }
589        default {
590            error "bad option \"$option\": should be coming, controls, now"
591        }
592    }
593}
594
595#
596# isconnected --
597#
598#       Indicates if we are currently connected to the visualization server.
599#
600itcl::body Rappture::HeightmapViewer::isconnected {} {
601    return [VisViewer::IsConnected]
602}
603
604# ----------------------------------------------------------------------
605# USAGE: Connect ?<host:port>,<host:port>...?
606#
607# Clients use this method to establish a connection to a new
608# server, or to reestablish a connection to the previous server.
609# Any existing connection is automatically closed.
610# ----------------------------------------------------------------------
611itcl::body Rappture::HeightmapViewer::Connect {} {
612    global readyForNextFrame
613    set readyForNextFrame 1
614    Disconnect
615    set _hosts [GetServerList "nanovis"]
616    if { "" == $_hosts } {
617        return 0
618    }
619    catch {unset _serverObjs}
620    set result [VisViewer::Connect $_hosts]
621    return $result
622}
623
624# ----------------------------------------------------------------------
625# USAGE: Disconnect
626#
627# Clients use this method to disconnect from the current rendering
628# server.
629# ----------------------------------------------------------------------
630itcl::body Rappture::HeightmapViewer::Disconnect {} {
631    VisViewer::Disconnect
632
633    set _outbuf ""
634    # disconnected -- no more data sitting on server
635    global readyForNextFrame
636    set readyForNextFrame 1
637}
638
639#
640# SendCmd
641#
642#       Send commands off to the rendering server.  If we're currently
643#       sending data objects to the server, buffer the commands to be
644#       sent later.
645#
646itcl::body Rappture::HeightmapViewer::SendCmd {string} {
647    if { $_buffering } {
648        append _outbuf $string "\n"
649    } else {
650        foreach line [split $string \n] {
651            SendEcho >>line $line
652        }
653        SendBytes "$string\n"
654    }
655}
656
657# ----------------------------------------------------------------------
658# USAGE: ReceiveImage -bytes <size>
659#
660# Invoked automatically whenever the "image" command comes in from
661# the rendering server.  Indicates that binary image data with the
662# specified <size> will follow.
663# ----------------------------------------------------------------------
664itcl::body Rappture::HeightmapViewer::ReceiveImage { args } {
665    global readyForNextFrame
666    set readyForNextFrame 1
667    if {![IsConnected]} {
668        return
669    }
670    array set info {
671        -type image
672    }
673    array set info $args
674    set bytes [ReceiveBytes $info(-bytes)]
675    ReceiveEcho <<line "<read $info(-bytes) bytes"
676    if { $info(-type) == "image" } {
677        $_image(plot) configure -data $bytes
678        ReceiveEcho <<line "<read for [image width $_image(plot)]x[image height $_image(plot)] image>"
679    } elseif { $info(type) == "print" } {
680        set tag $this-print-$info(-token)
681        set _hardcopy($tag) $bytes
682    }
683}
684
685# ----------------------------------------------------------------------
686# USAGE: ReceiveLegend <tf> <vmin> <vmax> <size>
687#
688# Invoked automatically whenever the "legend" command comes in from
689# the rendering server.  Indicates that binary image data with the
690# specified <size> will follow.
691# ----------------------------------------------------------------------
692itcl::body Rappture::HeightmapViewer::ReceiveLegend {obj vmin vmax size} {
693    if { [IsConnected] } {
694        set bytes [ReceiveBytes $size]
695        if { ![info exists _image(legend)] } {
696            set _image(legend) [image create photo]
697        }
698        ReceiveEcho <<line "<read $size bytes for [image width $_image(legend)]x[image height $_image(legend)] legend>"
699        set src [image create photo -data $bytes]
700        blt::winop image rotate $src $_image(legend) 90
701        set dst $_image(legend)
702
703        set c $itk_component(3dview)
704        set w [winfo width $c]
705        set h [winfo height $c]
706        set lineht [font metrics $itk_option(-font) -linespace]
707
708        if { $_settings($this-legend) } {
709            if { [$c find withtag "legend"] == "" } {
710                $c create image [expr {$w-2}] [expr {$lineht+2}] -anchor ne \
711                    -image $_image(legend) -tags "transfunc legend"
712                $c create text [expr {$w-2}] 2 -anchor ne \
713                    -fill $itk_option(-plotforeground) -tags "vmax legend" \
714                    -font "Arial 8 bold"
715                $c create text [expr {$w-2}] [expr {$h-2}] -anchor se \
716                    -fill $itk_option(-plotforeground) -tags "vmin legend" \
717                    -font "Arial 8 bold"
718            }
719            # Reset the item coordinates according the current size of the plot.
720            $c coords transfunc [expr {$w-2}] [expr {$lineht+2}]
721            $c itemconfigure vmin -text $vmin
722            $c itemconfigure vmax -text $vmax
723            $c coords vmin [expr {$w-2}] [expr {$h-2}]
724            $c coords vmax [expr {$w-2}] 2
725        }
726    }
727}
728
729# ----------------------------------------------------------------------
730# USAGE: Rebuild
731#
732# Called automatically whenever something changes that affects the
733# data in the widget.  Clears any existing data and rebuilds the
734# widget to display new data.
735# ----------------------------------------------------------------------
736itcl::body Rappture::HeightmapViewer::Rebuild {} {
737
738    # Turn on buffering of commands to the server.  We don't want to
739    # be preempted by a server disconnect/reconnect (which automatically
740    # generates a new call to Rebuild).   
741    set _buffering 1
742
743    # Reset the overall limits
744    set _limits(vmin) ""
745    set _limits(vmax) ""
746
747    set _first ""
748    # Turn on buffering of commands to the server.  We don't want to
749    # be preempted by a server disconnect/reconnect (which automatically
750    # generates a new call to Rebuild).   
751    set _buffering 1
752
753    set w [winfo width $itk_component(3dview)]
754    set h [winfo height $itk_component(3dview)]
755    EventuallyResize $w $h
756
757    foreach dataobj [get] {
758        foreach comp [$dataobj components] {
759            # Tell the engine to expect some data
760            set tag $dataobj-$comp
761            if { ![info exists _serverObjs($tag)] } {
762                set data [$dataobj blob $comp]
763                set nbytes [string length $data]
764                append _outbuf "heightmap data follows $nbytes $dataobj-$comp\n"
765                append _outbuf $data
766               
767                set _serverObjs($tag) $tag
768               
769                # Determine the transfer function needed for this surface
770                # and make sure that it's defined on the server.
771                foreach {sname cmap wmap} [GetTransfuncData $dataobj $comp] break
772                SendCmd [list "transfunc" "define" $sname $cmap $wmap]
773                set _obj2style($tag) $sname
774            }
775        }
776    }
777
778    # Nothing to send -- activate the proper surface
779    set _first [lindex [get] 0]
780    if {"" != $_first} {
781        set axis [$_first hints updir]
782        if {"" != $axis} {
783            SendCmd "up $axis"
784        }
785        # This is where the initial camera position is set.
786        set location [$_first hints camera]
787        if { $_location == "" && $location != "" } {
788            array set _view $location
789            set _location $location
790        }
791    }
792    SendCmd "heightmap data visible 0"
793    set heightmaps [CurrentSurfaces]
794    if { $heightmaps != ""  && $_settings($this-surface) } {
795        SendCmd "heightmap data visible 1 $heightmaps"
796    }
797    set heightmaps [CurrentSurfaces -raise]
798    if { $heightmaps != "" } {
799        SendCmd "heightmap opacity 0.25"
800        SendCmd "heightmap opacity 0.95 $heightmaps"
801    } else {
802        SendCmd "heightmap opacity 0.85"
803    }
804    foreach key $heightmaps {
805        if {[info exists _obj2style($key)]} {
806            SendCmd "heightmap transfunc $_obj2style($key) $key"
807        }
808    }
809    $_dispatcher event -idle !legend
810
811    if {"" == $itk_option(-plotoutline)} {
812        SendCmd "grid linecolor [Color2RGB $itk_option(-plotoutline)]"
813    }
814    # Reset the camera and other view parameters
815    set _settings($this-theta) $_view(theta)
816    set _settings($this-phi)   $_view(phi)
817    set _settings($this-psi)   $_view(psi)
818    set _settings($this-pan-x) $_view(pan-x)
819    set _settings($this-pan-y) $_view(pan-y)
820    set _settings($this-zoom)  $_view(zoom)
821
822    set xyz [Euler2XYZ $_view(theta) $_view(phi) $_view(psi)]
823    SendCmd "camera angle $xyz"
824    PanCamera
825    SendCmd "camera zoom $_view(zoom)"
826
827    FixSettings wireframe
828    FixSettings grid
829    FixSettings axes
830    FixSettings contourlines
831
832    # Actually write the commands to the server socket.  If it fails, we don't
833    # care.  We're finished here.
834    blt::busy hold $itk_component(hull)
835    SendBytes $_outbuf;                 
836    blt::busy release $itk_component(hull)
837
838    # The "readyForNextFrame" variable throttles the sequence play rate.
839    global readyForNextFrame
840    set readyForNextFrame 0;            # Don't advance to the next frame
841                                        # until we get an image.
842    set _buffering 0;                   # Turn off buffering.
843    set _outbuf "";                     # Clear the buffer.             
844}
845
846# ----------------------------------------------------------------------
847# USAGE: Zoom in
848# USAGE: Zoom out
849# USAGE: Zoom reset
850#
851# Called automatically when the user clicks on one of the zoom
852# controls for this widget.  Changes the zoom for the current view.
853# ----------------------------------------------------------------------
854itcl::body Rappture::HeightmapViewer::Zoom {option} {
855    switch -- $option {
856        "in" {
857            set _view(zoom) [expr {$_view(zoom)*1.25}]
858            set _settings($this-zoom) $_view(zoom)
859        }
860        "out" {
861            set _view(zoom) [expr {$_view(zoom)*0.8}]
862            set _settings($this-zoom) $_view(zoom)
863        }
864        "reset" {
865            array set _view {
866                theta   45
867                phi     45
868                psi     0
869                zoom    1.0
870                pan-x   0
871                pan-y   0
872            }
873            if { $_first != "" } {
874                set location [$_first hints camera]
875                if { $location != "" } {
876                    array set _view $location
877                }
878            }
879            set xyz [Euler2XYZ $_view(theta) $_view(phi) $_view(psi)]
880            SendCmd "camera angle $xyz"
881            PanCamera
882            set _settings($this-theta) $_view(theta)
883            set _settings($this-phi) $_view(phi)
884            set _settings($this-psi) $_view(psi)
885            set _settings($this-pan-x) $_view(pan-x)
886            set _settings($this-pan-y) $_view(pan-y)
887            set _settings($this-zoom) $_view(zoom)
888        }
889    }
890    SendCmd "camera zoom $_view(zoom)"
891}
892
893# ----------------------------------------------------------------------
894# USAGE: $this Pan click x y
895#        $this Pan drag x y
896#        $this Pan release x y
897#
898# Called automatically when the user clicks on one of the zoom
899# controls for this widget.  Changes the zoom for the current view.
900# ----------------------------------------------------------------------
901itcl::body Rappture::HeightmapViewer::Pan {option x y} {
902    # Experimental stuff
903    set w [winfo width $itk_component(3dview)]
904    set h [winfo height $itk_component(3dview)]
905    if { $option == "set" } {
906        set x [expr ($x / double($w)) * $_limits(xrange)]
907        set y [expr ($y / double($h)) * $_limits(yrange)]
908        set _view(pan-x) [expr $_view(pan-x) + $x]
909        set _view(pan-y) [expr $_view(pan-y) + $y]
910        PanCamera
911        set _settings($this-pan-x) $_view(pan-x)
912        set _settings($this-pan-y) $_view(pan-y)
913        return
914    }
915    if { $option == "click" } {
916        set _click(x) $x
917        set _click(y) $y
918        $itk_component(3dview) configure -cursor hand1
919    }
920    if { $option == "drag" || $option == "release" } {
921        set dx [expr (($_click(x) - $x)/double($w)) * $_limits(xrange)]
922        set dy [expr (($_click(y) - $y)/double($h)) * $_limits(yrange)]
923        set _click(x) $x
924        set _click(y) $y
925        set _view(pan-x) [expr $_view(pan-x) - $dx]
926        set _view(pan-y) [expr $_view(pan-y) - $dy]
927        PanCamera
928        set _settings($this-pan-x) $_view(pan-x)
929        set _settings($this-pan-y) $_view(pan-y)
930    }
931    if { $option == "release" } {
932        $itk_component(3dview) configure -cursor ""
933    }
934}
935
936itcl::body Rappture::HeightmapViewer::PanCamera {} {
937    set x [expr ($_view(pan-x)) / $_limits(xrange)]
938    set y [expr ($_view(pan-y)) / $_limits(yrange)]
939    SendCmd "camera pan $x $y"
940}
941
942# ----------------------------------------------------------------------
943# USAGE: Rotate click <x> <y>
944# USAGE: Rotate drag <x> <y>
945# USAGE: Rotate release <x> <y>
946#
947# Called automatically when the user clicks/drags/releases in the
948# plot area.  Moves the plot according to the user's actions.
949# ----------------------------------------------------------------------
950itcl::body Rappture::HeightmapViewer::Rotate {option x y} {
951    switch -- $option {
952        click {
953            $itk_component(3dview) configure -cursor fleur
954            array set _click [subst {
955                x       $x
956                y       $y
957                theta   $_view(theta)
958                phi     $_view(phi)
959            }]
960        }
961        drag {
962            if {[array size _click] == 0} {
963                Rotate click $x $y
964            } else {
965                set w [winfo width $itk_component(3dview)]
966                set h [winfo height $itk_component(3dview)]
967                if {$w <= 0 || $h <= 0} {
968                    return
969                }
970
971                if {[catch {
972                    # this fails sometimes for no apparent reason
973                    set dx [expr {double($x-$_click(x))/$w}]
974                    set dy [expr {double($y-$_click(y))/$h}]
975                }] != 0 } {
976                    return
977                }
978
979                #
980                # Rotate the camera in 3D
981                #
982                if {$_view(psi) > 90 || $_view(psi) < -90} {
983                    # when psi is flipped around, theta moves backwards
984                    set dy [expr {-$dy}]
985                }
986                set theta [expr {$_view(theta) - $dy*180}]
987                while {$theta < 0} { set theta [expr {$theta+180}] }
988                while {$theta > 180} { set theta [expr {$theta-180}] }
989
990                if {abs($theta) >= 30 && abs($theta) <= 160} {
991                    set phi [expr {$_view(phi) - $dx*360}]
992                    while {$phi < 0} { set phi [expr {$phi+360}] }
993                    while {$phi > 360} { set phi [expr {$phi-360}] }
994                    set psi $_view(psi)
995                } else {
996                    set phi $_view(phi)
997                    set psi [expr {$_view(psi) - $dx*360}]
998                    while {$psi < -180} { set psi [expr {$psi+360}] }
999                    while {$psi > 180} { set psi [expr {$psi-360}] }
1000                }
1001
1002                set _view(theta)        $theta
1003                set _view(phi)          $phi
1004                set _view(psi)          $psi
1005                set xyz [Euler2XYZ $_view(theta) $_view(phi) $_view(psi)]
1006                set _settings($this-theta) $_view(theta)
1007                set _settings($this-phi) $_view(phi)
1008                set _settings($this-psi) $_view(psi)
1009                SendCmd "camera angle $xyz"
1010                set _click(x) $x
1011                set _click(y) $y
1012            }
1013        }
1014        release {
1015            Rotate drag $x $y
1016            $itk_component(3dview) configure -cursor ""
1017            catch {unset _click}
1018        }
1019        default {
1020            error "bad option \"$option\": should be click, drag, release"
1021        }
1022    }
1023}
1024
1025# ----------------------------------------------------------------------
1026# USAGE: State <component>
1027#
1028# Used internally to determine the state of a toggle button.
1029# The <component> is the itk component name of the button.
1030# Returns on/off for the state of the button.
1031# ----------------------------------------------------------------------
1032itcl::body Rappture::HeightmapViewer::State {comp} {
1033    if {[$itk_component($comp) cget -relief] == "sunken"} {
1034        return "on"
1035    }
1036    return "off"
1037}
1038
1039# ----------------------------------------------------------------------
1040# USAGE: FixSettings <what> ?<value>?
1041#
1042# Used internally to update rendering settings whenever parameters
1043# change in the popup settings panel.  Sends the new settings off
1044# to the back end.
1045# ----------------------------------------------------------------------
1046itcl::body Rappture::HeightmapViewer::FixSettings { what {value ""} } {
1047    switch -- $what {
1048        "legend" {
1049            if { !$_settings($this-legend) } {
1050                $itk_component(3dview) delete "legend"
1051            }
1052            set lineht [font metrics $itk_option(-font) -linespace]
1053            set w [winfo height $itk_component(3dview)]
1054            set h [winfo width $itk_component(3dview)]
1055            set w [expr {$w - 2*$lineht - 4}]
1056            set h 12
1057            set tag ""
1058            if {"" != $_first} {
1059                set comp [lindex [$_first components] 0]
1060                set tag $_first-$comp
1061            }
1062            if {$w > 0 && $h > 0 && "" != $tag} {
1063                SendCmd "heightmap legend $tag $w $h"
1064            } else {
1065                #$itk_component(legend) delete all
1066            }
1067        }
1068        "surface" {
1069            if { [isconnected] } {
1070                SendCmd "heightmap data visible $_settings($this-surface)"
1071            }
1072        }
1073        "grid" {
1074            if { [IsConnected] } {
1075                SendCmd "grid visible $_settings($this-grid)"
1076            }
1077        }
1078        "axes" {
1079            if { [IsConnected] } {
1080                SendCmd "axis visible $_settings($this-axes)"
1081            }
1082        }
1083        "wireframe" {
1084            if { [IsConnected] } {
1085                SendCmd "heightmap polygon $_settings($this-wireframe)"
1086            }
1087        }
1088        "contourlines" {
1089            if {[IsConnected]} {
1090                if {"" != $_first} {
1091                    set comp [lindex [$_first components] 0]
1092                    if { $comp != "" } {
1093                        set tag $_first-$comp
1094                        set bool $_settings($this-contourlines)
1095                        SendCmd "heightmap linecontour visible $bool $tag"
1096                    }
1097                }
1098            }
1099        }
1100        default {
1101            error "don't know how to fix $what: should be grid, axes, contourlines, or legend"
1102        }
1103    }
1104}
1105
1106# ----------------------------------------------------------------------
1107# USAGE: GetTransfuncData <dataobj> <comp>
1108#
1109# Used internally to compute the colormap and alpha map used to define
1110# a transfer function for the specified component in a data object.
1111# Returns: name {v r g b ...} {v w ...}
1112# ----------------------------------------------------------------------
1113itcl::body Rappture::HeightmapViewer::GetTransfuncData {dataobj comp} {
1114    array set style {
1115        -color rainbow
1116        -levels 6
1117        -opacity 0.5
1118    }
1119    array set style [lindex [$dataobj components -style $comp] 0]
1120    set sname "$style(-color):$style(-levels):$style(-opacity)"
1121
1122    if {$style(-color) == "rainbow"} {
1123        set style(-color) "white:yellow:green:cyan:blue:magenta"
1124    }
1125    if { [info exists style(-nonuniformcolors)] } {
1126        foreach { value color } $style(-nonuniformcolors) {
1127            append cmap "$value [Color2RGB $color] "
1128        }
1129    } else {
1130        set clist [split $style(-color) :]
1131        set cmap "0.0 [Color2RGB white] "
1132        for {set i 0} {$i < [llength $clist]} {incr i} {
1133            set x [expr {double($i+1)/([llength $clist]+1)}]
1134            set color [lindex $clist $i]
1135            append cmap "$x [Color2RGB $color] "
1136        }
1137        append cmap "1.0 [Color2RGB $color]"
1138    }
1139    set opacity $style(-opacity)
1140    set levels $style(-levels)
1141    set wmap {}
1142    if {[string is int $levels]} {
1143        lappend wmap 0.0 0.0
1144        set delta [expr {0.125/($levels+1)}]
1145        for {set i 1} {$i <= $levels} {incr i} {
1146            # add spikes in the middle
1147            set xval [expr {double($i)/($levels+1)}]
1148            lappend wmap [expr {$xval-$delta-0.01}] 0.0
1149            lappend wmap [expr {$xval-$delta}] $opacity
1150            lappend wmap [expr {$xval+$delta}] $opacity
1151            lappend wmap [expr {$xval+$delta+0.01}] 0.0
1152        }
1153        lappend wmap 1.0 0.0
1154    } else {
1155        lappend wmap 0.0 0.0
1156        set delta 0.05
1157        foreach xval [split $levels ,] {
1158            lappend wmap [expr {$xval-$delta}] 0.0
1159            lappend $xval $opacity
1160            lappend [expr {$xval+$delta}] 0.0
1161        }
1162        lappend wmap 1.0 0.0
1163    }
1164    return [list $sname $cmap $wmap]
1165}
1166
1167# ----------------------------------------------------------------------
1168# CONFIGURATION OPTION: -plotbackground
1169# ----------------------------------------------------------------------
1170itcl::configbody Rappture::HeightmapViewer::plotbackground {
1171    foreach {r g b} [Color2RGB $itk_option(-plotbackground)] break
1172    #fix this!
1173    #SendCmd "color background $r $g $b"
1174}
1175
1176# ----------------------------------------------------------------------
1177# CONFIGURATION OPTION: -plotforeground
1178# ----------------------------------------------------------------------
1179itcl::configbody Rappture::HeightmapViewer::plotforeground {
1180    foreach {r g b} [Color2RGB $itk_option(-plotforeground)] break
1181    #fix this!
1182    #SendCmd "color background $r $g $b"
1183}
1184
1185# ----------------------------------------------------------------------
1186# CONFIGURATION OPTION: -plotoutline
1187# ----------------------------------------------------------------------
1188itcl::configbody Rappture::HeightmapViewer::plotoutline {
1189    if {[IsConnected]} {
1190        SendCmd "grid linecolor [Color2RGB $itk_option(-plotoutline)]"
1191    }
1192}
1193
1194
1195
1196#  camera --
1197#
1198itcl::body Rappture::HeightmapViewer::camera {option args} {
1199    switch -- $option {
1200        "show" {
1201            puts [array get _view]
1202        }
1203        "set" {
1204            set who [lindex $args 0]
1205            set x $_settings($this-$who)
1206            set code [catch { string is double $x } result]
1207            if { $code != 0 || !$result } {
1208                set _settings($this-$who) $_view($who)
1209                return
1210            }
1211            switch -- $who {
1212                "pan-x" - "pan-y" {
1213                    set _view($who) $_settings($this-$who)
1214                    PanCamera
1215                }
1216                "phi" - "theta" - "psi" {
1217                    set _view($who) $_settings($this-$who)
1218                    set xyz [Euler2XYZ $_view(theta) $_view(phi) $_view(psi)]
1219                    SendCmd "camera angle $xyz"
1220                }
1221                "zoom" {
1222                    set _view($who) $_settings($this-$who)
1223                    SendCmd "camera zoom $_view(zoom)"
1224                }
1225            }
1226        }
1227    }
1228}
1229
1230itcl::body Rappture::HeightmapViewer::BuildViewTab {} {
1231    set fg [option get $itk_component(hull) font Font]
1232
1233    set inner [$itk_component(main) insert end \
1234        -title "View Settings" \
1235        -icon [Rappture::icon wrench]]
1236    $inner configure -borderwidth 4
1237
1238    foreach { key value } {
1239        grid            1
1240        axes            0
1241        contourlines    1
1242        wireframe       fill
1243        legend          1
1244    } {
1245        set _settings($this-$key) $value
1246    }
1247
1248    checkbutton $inner.surface \
1249        -text "surface" \
1250        -variable [itcl::scope _settings($this-surface)] \
1251        -command [itcl::code $this FixSettings surface] \
1252        -font "Arial 9"
1253    checkbutton $inner.grid \
1254        -text "grid" \
1255        -variable [itcl::scope _settings($this-grid)] \
1256        -command [itcl::code $this FixSettings grid] \
1257        -font "Arial 9"
1258    checkbutton $inner.axes \
1259        -text "axes" \
1260        -variable ::Rappture::HeightmapViewer::_settings($this-axes) \
1261        -command [itcl::code $this FixSettings axes] \
1262        -font "Arial 9"
1263    checkbutton $inner.contourlines \
1264        -text "contour lines" \
1265        -variable ::Rappture::HeightmapViewer::_settings($this-contourlines) \
1266        -command [itcl::code $this FixSettings contourlines]\
1267        -font "Arial 9"
1268    checkbutton $inner.wireframe \
1269        -text "wireframe" \
1270        -onvalue "wireframe" -offvalue "fill" \
1271        -variable ::Rappture::HeightmapViewer::_settings($this-wireframe) \
1272        -command [itcl::code $this FixSettings wireframe]\
1273        -font "Arial 9"
1274    checkbutton $inner.legend \
1275        -text "legend" \
1276        -variable ::Rappture::HeightmapViewer::_settings($this-legend) \
1277        -command [itcl::code $this FixSettings legend]\
1278        -font "Arial 9"
1279
1280    blt::table $inner \
1281        0,1 $inner.surface -anchor w  \
1282        1,1 $inner.grid -anchor w  \
1283        2,1 $inner.axes -anchor w \
1284        3,1 $inner.contourlines -anchor w \
1285        4,1 $inner.wireframe -anchor w \
1286        5,1 $inner.legend -anchor w
1287
1288    blt::table configure $inner c2 -resize expand
1289    blt::table configure $inner c1 -resize none
1290    blt::table configure $inner r* -resize none
1291    blt::table configure $inner r6 -resize expand
1292}
1293
1294itcl::body Rappture::HeightmapViewer::BuildCameraTab {} {
1295    set fg [option get $itk_component(hull) font Font]
1296
1297    set inner [$itk_component(main) insert end \
1298        -title "Camera Settings" \
1299        -icon [Rappture::icon camera]]
1300    $inner configure -borderwidth 4
1301
1302    set labels { phi theta psi pan-x pan-y zoom }
1303    set row 1
1304    foreach tag $labels {
1305        label $inner.${tag}label -text $tag -font "Arial 9"
1306        entry $inner.${tag} -font "Arial 9" -bg white -width 10 \
1307            -textvariable [itcl::scope _settings($this-$tag)]
1308        bind $inner.${tag} <KeyPress-Return> \
1309            [itcl::code $this camera set ${tag}]
1310        blt::table $inner \
1311            $row,1 $inner.${tag}label -anchor e \
1312            $row,2 $inner.${tag} -anchor w
1313        blt::table configure $inner r$row -resize none
1314        incr row
1315    }
1316    blt::table configure $inner c1 c2 -resize none
1317    blt::table configure $inner c3 -resize expand
1318    blt::table configure $inner r$row -resize expand
1319}
1320
1321itcl::body Rappture::HeightmapViewer::Resize {} {
1322    SendCmd "screen $_width $_height"
1323    set _resizePending 0
1324    $_dispatcher event -idle !legend
1325}
1326
1327itcl::body Rappture::HeightmapViewer::EventuallyResize { w h } {
1328    set _width $w
1329    set _height $h
1330    if { !$_resizePending } {
1331        $_dispatcher event -after 200 !resize
1332        set _resizePending 1
1333    }
1334}
1335
1336# ----------------------------------------------------------------------
1337# USAGE: CurrentVolumes ?-cutplanes?
1338#
1339# Returns a list of volume server IDs for the current volume being
1340# displayed.  This is normally a single ID, but it might be a list
1341# of IDs if the current data object has multiple components.
1342# ----------------------------------------------------------------------
1343itcl::body Rappture::HeightmapViewer::CurrentSurfaces {{what -all}} {
1344    set list {}
1345    if { $what == "-all" } {
1346        foreach key [array names _serverObjs] {
1347            foreach {dataobj comp} [split $key -] break
1348            if { [info exists _obj2ovride($dataobj-raise)] } {
1349                lappend list $dataobj-$comp
1350            }
1351        }
1352    } else {
1353        foreach key [array names _serverObjs] {
1354            foreach {dataobj comp} [split $key -] break
1355            if { [info exists _obj2ovride($dataobj$what)] &&
1356                 $_obj2ovride($dataobj$what) } {
1357                lappend list $dataobj-$comp
1358            }
1359        }
1360    }
1361    return $list
1362}
1363
1364itcl::body Rappture::HeightmapViewer::snap { w h } {
1365    if { $w <= 0 || $h <= 0 } {
1366        set w [image width $_image(plot)]
1367        set h [image height $_image(plot)]
1368    }
1369    set img [image create picture -width $w -height $h]
1370    $img resample $_image(plot)
1371    return $img
1372}
1373
1374
1375itcl::body Rappture::HeightmapViewer::AddImageControls { inner widget } {
1376    label $inner.size_l -text "Size:" -font "Arial 9"
1377    set _downloadPopup(image_controls) $inner
1378    set img $_image(plot)
1379    set res "[image width $img]x[image height $img]"
1380    Rappture::Combobox $inner.size -width 30 -editable no
1381    $inner.size choices insert end \
1382        "draft"  "Draft ($res)"         
1383
1384    label $inner.bgcolor_l -text "Background:" -font "Arial 9"
1385    Rappture::Combobox $inner.bgcolor -width 30 -editable no
1386    $inner.bgcolor choices insert end \
1387        "black"  "Black" \
1388        "white"  "White"
1389
1390    label $inner.format_l -text "Format:" -font "Arial 9"
1391    Rappture::Combobox $inner.format -width 30 -editable no
1392    $inner.format choices insert end \
1393        "png"  "PNG (Portable Network Graphics format)" \
1394        "jpg"  "JPEG (Joint Photographic Experts Group format)"
1395
1396    button $inner.go -text [Rappture::filexfer::label download] \
1397        -command [itcl::code $this SetWaitVariable 1]
1398
1399    blt::table $inner \
1400        0,0 $inner.format_l -anchor e \
1401        0,1 $inner.format -anchor w -fill x  \
1402        1,0 $inner.size_l -anchor e \
1403        1,1 $inner.size -anchor w -fill x \
1404        2,0 $inner.bgcolor_l -anchor e \
1405        2,1 $inner.bgcolor -anchor w -fill x \
1406        6,0 $inner.go -cspan 2 -pady 5
1407    $inner.bgcolor value "Black"
1408    $inner.size value "Draft ($res)"
1409    $inner.format value  "PNG (Portable Network Graphics format)"
1410}
Note: See TracBrowser for help on using the repository browser.