source: trunk/gui/scripts/visviewer.tcl @ 3394

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

fix up stats reporting in servers

File size: 34.0 KB
Line 
1# -*- mode: tcl; indent-tabs-mode: nil -*-
2
3# ----------------------------------------------------------------------
4#  VisViewer -
5#
6#  This class is the base class for the various visualization viewers
7#  that use the nanoserver render farm.
8#
9# ======================================================================
10#  AUTHOR:  Michael McLennan, Purdue University
11#  Copyright (c) 2004-2012  HUBzero Foundation, LLC
12#
13#  See the file "license.terms" for information on usage and
14#  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15# ======================================================================
16
17itcl::class ::Rappture::VisViewer {
18    inherit itk::Widget
19
20    itk_option define -sendcommand sendCommand SendCommand ""
21    itk_option define -receivecommand receiveCommand ReceiveCommand ""
22
23    private common _servers         ;# array of visualization server lists
24    set _servers(nanovis) "localhost:2000"
25    set _servers(pymol)   "localhost:2020"
26    set _servers(vtkvis)  "localhost:2010"
27
28    protected variable _serverType "???";# Type of server.
29    protected variable _sid ""      ;   # socket connection to server
30    private common _done            ;   # Used to indicate status of send.
31    private variable _buffer        ;   # buffer for incoming/outgoing commands
32    private variable _initialized
33    private variable _isOpen 0
34    private variable _afterId -1
35    private variable _icon 0
36
37    # Number of milliseconds to wait before idle timeout.  If greater than 0,
38    # automatically disconnect from the visualization server when idle timeout
39    # is reached.
40    private variable _idleTimeout 43200000; # 12 hours
41    #private variable _idleTimeout 5000;    # 5 seconds
42    #private variable _idleTimeout 0;       # No timeout
43    protected variable _maxConnects 100
44
45    private variable _logging 0
46
47    protected variable _dispatcher "";  # dispatcher for !events
48    protected variable _hosts ""    ;   # list of hosts for server
49    protected variable _parser ""   ;   # interpreter for incoming commands
50    protected variable _image
51    protected variable _hostname
52    protected variable _numConnectTries 0
53    protected variable _debugConsole 0
54
55    constructor { servers args } {
56        # defined below
57    }
58    destructor {
59        # defined below
60    }
61    # Used internally only.
62    private method Shuffle { servers }
63    private method ReceiveHelper {}
64    private method ServerDown {}
65    private method SendHelper {}
66    private method SendHelper.old {}
67    private method SplashScreen { state }
68
69    protected method ToggleConsole {}
70    private method DebugConsole {}
71    private method BuildConsole {}
72    private method HideConsole {}
73    private method TraceComm { channel {data {}} }
74    private method SendDebugCommand {}
75
76    protected method CheckConnection {}
77    protected method Color2RGB { color }
78    protected method ColorsToColormap { colors }
79    protected method Connect { servers }
80    protected method Disconnect {}
81    protected method Euler2XYZ { theta phi psi }
82    protected method Flush {}
83    protected method IsConnected {}
84    protected method ReceiveBytes { nbytes }
85    protected method ReceiveEcho { channel {data ""} }
86    protected method ReceiveError { args }
87    protected method SendBytes { bytes }
88    protected method SendEcho { channel {data ""} }
89    protected method StartWaiting {}
90    protected method StopWaiting {}
91
92    private method Waiting { option widget }
93
94    private proc CheckNameList { namelist }  {
95        foreach host $namelist {
96            set pattern {^[a-zA-Z0-9\.]+:[0-9]}
97            if { ![regexp $pattern $host match] } {
98                error "bad visualization server address \"$host\": should be host:port,host:port,..."
99            }
100        }
101    }
102    public proc GetServerList { type } {
103        return $_servers($type)
104    }
105    public proc SetServerList { type namelist } {
106        # Convert the comma separated list into a Tcl list.  OGRE also adds
107        # a trailing comma that we want to ignore.
108        regsub -all "," $namelist " " namelist
109        CheckNameList $namelist
110        set _servers($type) $namelist
111    }
112    public proc RemoveServerFromList { type server } {
113        if { ![info exists _servers($type)] } {
114            error "unknown server type \"$type\""
115        }
116        set i [lsearch $_servers($type) $server]
117        if { $i < 0 } {
118            return
119        }
120        set _servers($type) [lreplace $_servers($type) $i $i]
121    }
122    public proc SetPymolServerList { namelist } {
123        SetServerList "pymol" $namelist
124    }
125    public proc SetNanovisServerList { namelist } {
126        SetServerList "nanovis" $namelist
127    }
128    public proc SetVtkServerList { namelist } {
129        SetServerList "vtk" $namelist
130    }
131}
132
133itk::usual Panedwindow {
134    keep -background -cursor
135}
136
137# ----------------------------------------------------------------------
138# CONSTRUCTOR
139# ----------------------------------------------------------------------
140itcl::body Rappture::VisViewer::constructor { servers args } {
141
142    Rappture::dispatcher _dispatcher
143    $_dispatcher register !serverDown
144    $_dispatcher dispatch $this !serverDown "[itcl::code $this ServerDown]; list"
145    $_dispatcher register !timeout
146    $_dispatcher dispatch $this !timeout "[itcl::code $this Disconnect]; list"
147
148    $_dispatcher register !waiting
149
150    CheckNameList $servers
151    set _buffer(in) ""
152    set _buffer(out) ""
153    #
154    # Create a parser to handle incoming requests
155    #
156    set _parser [interp create -safe]
157    foreach cmd [$_parser eval {info commands}] {
158        $_parser hide $cmd
159    }
160    #
161    # Set up the widgets in the main body
162    #
163    option add hull.width hull.height
164    pack propagate $itk_component(hull) no
165
166    itk_component add main {
167        Rappture::SidebarFrame $itk_interior.main -resizeframe 1
168    }
169    pack $itk_component(main) -expand yes -fill both
170    set f [$itk_component(main) component frame]
171
172    itk_component add plotarea {
173        frame $f.plotarea -highlightthickness 0 -background black
174    } {
175        ignore -background
176    }
177    pack $itk_component(plotarea) -fill both -expand yes
178    set _image(plot) [image create photo]
179
180    global env
181    if { [info exists env(VISRECORDER)] } {
182        set _logging 1
183        if { [file exists /tmp/recording.log] } {
184            file delete /tmp/recording.log
185        }
186    }
187    eval itk_initialize $args
188}
189
190#
191# destructor --
192#
193itcl::body Rappture::VisViewer::destructor {} {
194    $_dispatcher cancel !timeout
195    interp delete $_parser
196    array unset _done $this
197}
198
199#
200# Shuffle --
201#
202#   Shuffle the list of server hosts.
203#
204itcl::body Rappture::VisViewer::Shuffle { hosts } {
205    set randomHosts {}
206    set ticks [clock clicks]
207    expr {srand($ticks)}
208    for { set i [llength $hosts] } { $i > 0 } { incr i -1 } {
209        set index [expr {round(rand()*$i - 0.5)}]
210        if { $index == $i } {
211            set index [expr $i - 1]
212        }
213        lappend randomHosts [lindex $hosts $index]
214        set hosts [lreplace $hosts $index $index]
215    }
216    return $randomHosts
217}
218
219#
220# ServerDown --
221#
222#    Used internally to let the user know when the connection to the
223#    visualization server has been lost.  Puts up a tip encouraging the
224#    user to press any control to reconnect.
225#
226itcl::body Rappture::VisViewer::ServerDown {} {
227    if { [info exists itk_component(plotarea)] } {
228        set x [expr {[winfo rootx $itk_component(plotarea)]+10}]
229        set y [expr {[winfo rooty $itk_component(plotarea)]+10}]
230    } else {
231        set x 0; set y 0
232    }
233    Rappture::Tooltip::cue @$x,$y "Lost connection to visualization server.  This happens sometimes when there are too many users and the system runs out of memory.\n\nTo reconnect, reset the view or press any other control.  Your picture should come right back up."
234}
235
236#
237# Connect --
238#
239#    Connect to the visualization server (e.g. nanovis, pymolproxy).
240#    Creates an event callback that is triggered when we are idle
241#    (no I/O with the server) for some specified time.
242#
243itcl::body Rappture::VisViewer::Connect { servers } {
244    blt::busy hold $itk_component(hull) -cursor watch
245
246    if { $_numConnectTries > $_maxConnects } {
247        blt::busy release $itk_component(hull)
248        set x [expr {[winfo rootx $itk_component(hull)]+10}]
249        set y [expr {[winfo rooty $itk_component(hull)]+10}]
250        Rappture::Tooltip::cue @$x,$y "Exceeded maximum number of connection attmepts to any $_serverType visualization server. Please contact support."
251        return 0;
252    }
253    foreach server [Shuffle $servers] {
254        puts stderr "connecting to $server..."
255        foreach {hostname port} [split $server ":"] break
256        if { [catch {socket $hostname $port} _sid] != 0 } {
257            set _sid ""
258            RemoveServerFromList $_serverType $server
259            continue
260        }
261        incr _numConnectTries
262        set _hostname $server
263        fconfigure $_sid -translation binary -encoding binary
264       
265        # Read back the server identification string.
266        if { [gets $_sid data] <= 0 } {
267            set _sid ""
268            puts stderr "reading from server"
269            RemoveServerFromList $_serverType $server
270            continue
271        }
272        puts stderr "render server is $data"
273        # We're connected. Cancel any pending serverDown events and
274        # release the busy window over the hull.
275        $_dispatcher cancel !serverDown
276        if { $_idleTimeout > 0 } {
277            $_dispatcher event -after $_idleTimeout !timeout
278        }
279        blt::busy release $itk_component(hull)
280        fconfigure $_sid -buffering line
281        fileevent $_sid readable [itcl::code $this ReceiveHelper]
282        return 1
283    }
284    blt::busy release $itk_component(hull)
285    set x [expr {[winfo rootx $itk_component(hull)]+10}]
286    set y [expr {[winfo rooty $itk_component(hull)]+10}]
287    Rappture::Tooltip::cue @$x,$y "Can't connect to any $_serverType visualization server.  This may be a network problem.  Wait a few moments and try resetting the view."
288    return 0
289}
290
291#
292# Disconnect --
293#
294#    Clients use this method to disconnect from the current rendering
295#    server.  Cancel any pending idle timeout events.
296#
297itcl::body Rappture::VisViewer::Disconnect {} {
298    after cancel $_afterId
299    $_dispatcher cancel !timeout
300    catch {close $_sid}
301    set _sid ""
302    set _buffer(in) ""
303}
304
305#
306# IsConnected --
307#
308#    Indicates if we are currently connected to a server.
309#
310itcl::body Rappture::VisViewer::IsConnected {} {
311    if { $_sid == "" } {
312        return 0
313    }
314    if { [eof $_sid] } {
315        set _sid ""
316        return 0
317    }
318    return 1
319}
320
321#
322# CheckConection --
323#
324#   This routine is called whenever we're about to send/recieve data on
325#   the socket connection to the visualization server.  If we're connected,
326#   then reset the timeout event.  Otherwise try to reconnect to the
327#   visualization server.
328#
329itcl::body Rappture::VisViewer::CheckConnection {} {
330    $_dispatcher cancel !timeout
331    if { $_idleTimeout > 0 } {
332        $_dispatcher event -after $_idleTimeout !timeout
333    }
334    if { [IsConnected] } {
335        return 1
336    }
337    if { $_sid != "" } {
338        fileevent $_sid writable ""
339    }
340    # If we aren't connected, assume it's because the connection to the
341    # visualization server broke. Try to open a connection and trigger a
342    # rebuild.
343    $_dispatcher cancel !serverDown
344    set x [expr {[winfo rootx $itk_component(plotarea)]+10}]
345    set y [expr {[winfo rooty $itk_component(plotarea)]+10}]
346    Rappture::Tooltip::cue @$x,$y "Connecting..."
347    set code [catch { Connect } ok]
348    if { $code == 0 && $ok} {
349        $_dispatcher event -idle !rebuild
350        Rappture::Tooltip::cue hide
351    } else {
352        Rappture::Tooltip::cue @$x,$y "Can't connect to any $_serverType visualization server.  This may be a network problem.  Wait a few moments and try resetting the view."
353        return 0
354    }
355    return 1
356}
357
358#
359# Flush --
360#
361#    Flushes the socket.
362#
363itcl::body Rappture::VisViewer::Flush {} {
364    if { [CheckConnection] } {
365        flush $_sid
366    }
367}
368
369
370#
371# SendHelper --
372#
373#   Helper routine called from a file event to send data when the
374#   connection is writable (i.e. not blocked).  Sets a magic
375#   variable _done($this) when we're done.
376#
377itcl::body Rappture::VisViewer::SendHelper {} {
378    if { ![CheckConnection] } {
379        return 0
380    }
381    puts -nonewline $_sid $_buffer(out)
382    flush $_sid
383    set _done($this) 1;                 # Success
384}
385
386#
387# SendHelper.old --
388#
389#   Helper routine called from a file event to send data when the
390#   connection is writable (i.e. not blocked).  Sends data in chunks
391#   of 8k (or less).  Sets magic variable _done($this) to indicate
392#   that we're either finished (success) or could not send bytes to
393#   the server (failure).
394#
395itcl::body Rappture::VisViewer::SendHelper.old {} {
396    if { ![CheckConnection] } {
397        return 0
398    }
399    set bytesLeft [string length $_buffer(out)]
400    if { $bytesLeft > 0} {
401        set chunk [string range $_buffer(out) 0 8095]
402        set _buffer(out)  [string range $_buffer(out) 8096 end]
403        incr bytesLeft -8096
404        set code [catch {
405            if { $bytesLeft > 0 } {
406                puts -nonewline $_sid $chunk
407            } else {
408                puts $_sid $chunk
409            }
410        } err]
411        if { $code != 0 } {
412            puts stderr "error sending data to $_sid: $err"
413            Disconnect
414            set _done($this) 0;     # Failure
415        }
416    } else {
417        set _done($this) 1;     # Success
418    }
419}
420
421#
422# SendBytes --
423#
424#   Send a a string to the visualization server.
425#
426itcl::body Rappture::VisViewer::SendBytes { bytes } {
427    SendEcho >>line $bytes
428    if { ![CheckConnection] } {
429        return 0
430    }
431    # Even though the data is sent in only 1 "puts", we need to verify that
432    # the server is ready first.  Wait for the socket to become writable
433    # before sending anything.
434    set _done($this) 1
435    set _buffer(out) $bytes
436    fileevent $_sid writable [itcl::code $this SendHelper]
437    tkwait variable ::Rappture::VisViewer::_done($this)
438    set _buffer(out) ""
439    if { [IsConnected] } {
440        # The connection may have closed while we were writing to the server.
441        # This can happen if what we sent the server caused it to barf.
442        fileevent $_sid writable ""
443        flush $_sid
444    }
445    return $_done($this)
446}
447
448#
449# StartWaiting --
450#
451#    Read some number of bytes from the visualization server.
452#
453itcl::body Rappture::VisViewer::StartWaiting {} {
454    after cancel $_afterId
455    set _afterId [after 2000 [itcl::code $this SplashScreen on]]
456}
457
458itcl::body Rappture::VisViewer::StopWaiting {} {
459    SplashScreen off
460}
461
462#
463# ReceiveBytes --
464#
465#    Read some number of bytes from the visualization server.
466#
467itcl::body Rappture::VisViewer::ReceiveBytes { size } {
468    if { ![CheckConnection] } {
469        return 0
470    }
471    set bytes [read $_sid $size]
472    ReceiveEcho <<line "<read $size bytes"
473    return $bytes
474}
475
476#
477# ReceiveHelper --
478#
479#   Helper routine called from a file event when the connection is
480#   readable (i.e. a command response has been sent by the rendering
481#   server.  Reads the incoming command and executes it in a safe
482#   interpreter to handle the action.
483#
484#       Note: This routine currently only handles command responses from
485#         the visualization server.  It doesn't handle non-blocking
486#         reads from the visualization server.
487#
488#       nv>image -bytes 100000      yes
489#       ...following 100000 bytes...    no
490#
491#   Note: All commands from the render server are on one line.
492#         This is because the render server can send anything
493#         as an error message (restricted again to one line).
494#
495itcl::body Rappture::VisViewer::ReceiveHelper {} {
496    if { ![CheckConnection] } {
497        return 0
498    }
499    set n [gets $_sid line]
500
501    if { $n < 0 } {
502        Disconnect
503        return 0
504    }
505    set line [string trim $line]
506    if { $line == "" } {
507        return
508    }
509    if { [string compare -length 3 $line "nv>"] == 0 } {
510        ReceiveEcho <<line $line
511        append _buffer(in) [string range $line 3 end]
512        append _buffer(in) "\n"
513        if {[info complete $_buffer(in)]} {
514            set request $_buffer(in)
515            set _buffer(in) ""
516            if { [catch {$_parser eval $request} err]  != 0 } {
517                global errorInfo
518                puts stderr "err=$err errorInfo=$errorInfo"
519            }
520        }
521    } elseif { [string compare -length 21 $line "NanoVis Server Error:"] == 0 ||
522               [string compare -length 20 $line "VtkVis Server Error:"] == 0} {
523        # this shows errors coming back from the engine
524        ReceiveEcho <<error $line
525        puts stderr "Render Server Error: $line\n"
526    } else {
527        # this shows errors coming back from the engine
528        ReceiveEcho <<error $line
529        puts stderr "Garbled message: $line\n"
530    }
531}
532
533#
534# Color2RGB --
535#
536#   Converts a color name to a list of r,g,b values needed for the
537#   engine.  Each r/g/b component is scaled in the # range 0-1.
538#
539itcl::body Rappture::VisViewer::Color2RGB {color} {
540    foreach {r g b} [winfo rgb $itk_component(hull) $color] break
541    set r [expr {$r/65535.0}]
542    set g [expr {$g/65535.0}]
543    set b [expr {$b/65535.0}]
544    return [list $r $g $b]
545}
546
547#
548# Euler2XYZ --
549#
550#   Converts euler angles for the camera placement the to angles of
551#   rotation about the x/y/z axes, used by the engine.  Returns a list:
552#   {xangle, yangle, zangle}.
553#
554itcl::body Rappture::VisViewer::Euler2XYZ {theta phi psi} {
555    set xangle [expr {$theta-90.0}]
556    set yangle [expr {180.0-$phi}]
557    set zangle $psi
558    return [list $xangle $yangle $zangle]
559}
560
561#
562# SendEcho --
563#
564#     Used internally to echo sent data to clients interested in this widget.
565#     If the -sendcommand option is set, then it is invoked in the global scope
566#     with the <channel> and <data> values as arguments.  Otherwise, this does
567#     nothing.
568#
569itcl::body Rappture::VisViewer::SendEcho {channel {data ""}} {
570    if { $_logging }  {
571        set f [open "/tmp/recording.log" "a"]
572        puts $f $data
573        close $f
574    }
575    #puts stderr ">>($data)"
576    if {[string length $itk_option(-sendcommand)] > 0} {
577        uplevel #0 $itk_option(-sendcommand) [list $channel $data]
578    }
579}
580
581#
582# ReceiveEcho --
583#
584#     Echoes received data to clients interested in this widget.  If the
585#     -receivecommand option is set, then it is invoked in the global
586#     scope with the <channel> and <data> values as arguments.  Otherwise,
587#     this does nothing.
588#
589itcl::body Rappture::VisViewer::ReceiveEcho {channel {data ""}} {
590    #puts stderr "<<line $data"
591    if {[string length $itk_option(-receivecommand)] > 0} {
592        uplevel #0 $itk_option(-receivecommand) [list $channel $data]
593    }
594}
595
596itcl::body Rappture::VisViewer::SplashScreen { state } {
597    after cancel $_afterId
598    set _afterId -1
599    if { $state } {
600        if { [winfo exists $itk_component(plotarea).view.splash] } {
601            return
602        }
603        set inner [frame $itk_component(plotarea).view.splash]
604        $inner configure -relief raised -bd 2
605        label $inner.text1 -text "Rendering, please wait." \
606            -font "Arial 10"
607        label $inner.icon
608        pack $inner -expand yes -anchor c
609        blt::table $inner \
610            0,0 $inner.text1 -anchor w \
611            0,1 $inner.icon
612        Waiting start $inner.icon
613    } else {
614        if { ![winfo exists $itk_component(plotarea).view.splash] } {
615            return
616        }
617        Waiting stop $itk_component(plotarea).view.splash
618        destroy $itk_component(plotarea).view.splash
619    }
620}
621
622itcl::body Rappture::VisViewer::Waiting { option widget } {
623    switch -- $option {
624        "start" {
625            $_dispatcher dispatch $this !waiting \
626                "[itcl::code $this Waiting "next" $widget] ; list"
627            set _icon 0
628            $widget configure -image [Rappture::icon bigroller${_icon}]
629            $_dispatcher event -after 150 !waiting
630        }
631        "next" {
632            incr _icon
633            if { $_icon >= 8 } {
634                set _icon 0
635            }
636            $widget configure -image [Rappture::icon bigroller${_icon}]
637            $_dispatcher event -after 150 !waiting
638        }
639        "stop" {
640            $_dispatcher cancel !waiting
641        }
642    }
643}
644
645#
646# HideConsole --
647#
648#    Hide the debug console by withdrawing its toplevel window.
649#
650itcl::body Rappture::VisViewer::HideConsole {} {
651    set _debugConsole 0
652    DebugConsole
653}
654
655#
656# BuildConsole --
657#
658#    Create and pack the widgets that make up the debug console: a text
659#    widget to display the communication and an entry widget to type
660#    in commands to send to the render server.
661#
662itcl::body Rappture::VisViewer::BuildConsole {} {
663    toplevel .renderconsole
664    wm protocol .renderconsole WM_DELETE_WINDOW [itcl::code $this HideConsole]
665    set f .renderconsole
666    frame $f.send
667    pack $f.send -side bottom -fill x
668    label $f.send.l -text "Send:"
669    pack $f.send.l -side left
670    itk_component add command {
671        entry $f.send.e -background white
672    } {
673        ignore -background
674    }
675    pack $f.send.e -side left -expand yes -fill x
676    bind $f.send.e <KeyPress-Return> [itcl::code $this SendDebugCommand]
677   
678    scrollbar $f.sb -orient vertical -command "$f.comm yview"
679    pack $f.sb -side right -fill y
680    itk_component add trace {
681        text $f.comm -wrap char -yscrollcommand "$f.sb set" -background white
682    } {
683        ignore -background
684    }
685    pack $f.comm -expand yes -fill both
686
687    $itk_component(trace) tag configure error -foreground red \
688        -font -*-courier-medium-o-normal-*-*-120-*
689    $itk_component(trace) tag configure incoming -foreground blue
690}
691
692#
693# ToggleConsole --
694#
695#    This is used by derived classes to turn on/off debuging.  It's
696#    up the to derived class to decide how to turn on/off debugging.
697#
698itcl::body Rappture::VisViewer::ToggleConsole {} {
699    if { $_debugConsole } {
700        set _debugConsole 0
701    } else {
702        set _debugConsole 1
703    }
704    DebugConsole
705}
706
707#
708# DebugConsole --
709#
710#    Based on the value of the variable _debugConsole, turns on/off
711#    debugging. This is done by setting/unsetting a procedure that
712#    is called whenever new characters are received or sent on the
713#    socket to the render server.  Additionally, the debug console
714#    is created if necessary and hidden/shown.
715#
716itcl::body Rappture::VisViewer::DebugConsole {} {
717    if { ![winfo exists .renderconsole] } {
718        BuildConsole
719    }
720    if { $_debugConsole } {
721        $this configure -sendcommand [itcl::code $this TraceComm]
722        $this configure -receivecommand [itcl::code $this TraceComm]
723        wm deiconify .renderconsole
724    } else {
725        $this configure -sendcommand ""
726        $this configure -receivecommand ""
727        wm withdraw .renderconsole
728    }
729}
730
731# ----------------------------------------------------------------------
732# USAGE: TraceComm <channel> <data>
733#
734# Invoked automatically whenever there is communication between
735# the rendering widget and the server.  Eavesdrops on the communication
736# and posts the commands in a text viewer.
737# ----------------------------------------------------------------------
738itcl::body Rappture::VisViewer::TraceComm {channel {data ""}} {
739    $itk_component(trace) configure -state normal
740    switch -- $channel {
741        closed {
742            $itk_component(trace) insert end "--CLOSED--\n" error
743        }
744        <<line {
745            $itk_component(trace) insert end $data incoming "\n" incoming
746        }
747        >>line {
748            $itk_component(trace) insert end $data outgoing "\n" outgoing
749        }
750        error {
751            $itk_component(trace) insert end $data error "\n" error
752        }
753        default {
754            $itk_component(trace) insert end "$data\n"
755        }
756    }
757    $itk_component(trace) configure -state disabled
758    $itk_component(trace) see end
759}
760
761# ----------------------------------------------------------------------
762# USAGE: SendDebugCommand
763#
764# Invoked automatically whenever the user enters a command and
765# presses <Return>.  Sends the command along to the rendering
766# widget.
767# ----------------------------------------------------------------------
768itcl::body Rappture::VisViewer::SendDebugCommand {} {
769    set cmd [$itk_component(command) get]
770    SendBytes "$cmd\n"
771    $itk_component(command) delete 0 end
772}
773
774
775#
776# ReceiveError -bytes <size> -type <type> -token <token>
777#
778itcl::body Rappture::VisViewer::ReceiveError { args } {
779    array set info {
780        -token "???"
781        -bytes 0
782        -type "???"
783    }
784    array set info $args
785    set bytes [ReceiveBytes $info(-bytes)]
786    if { $info(-type) == "error" } {
787        set popup $itk_component(hull).error
788        if { ![winfo exists $popup] } {
789            Rappture::Balloon $popup \
790                -title "Render Server Error"
791            set inner [$popup component inner]
792            label $inner.summary -text "" -anchor w
793
794            Rappture::Scroller $inner.scrl \
795                -xscrollmode auto -yscrollmode auto
796            text $inner.scrl.text \
797                -font "Arial 9 " -background white -relief sunken -bd 1 \
798                -height 5 -wrap word -width 60
799            $inner.scrl contents $inner.scrl.text
800            button $inner.ok -text "Dismiss" -command [list $popup deactivate] \
801                -font "Arial 9"
802            blt::table $inner \
803                0,0 $inner.scrl -fill both \
804                1,0 $inner.ok
805            $inner.scrl.text tag configure normal -font "Arial 9"
806            $inner.scrl.text tag configure italic -font "Arial 9 italic"
807            $inner.scrl.text tag configure bold -font "Arial 10 bold"
808            $inner.scrl.text tag configure code -font "Courier 10 bold"
809        } else {
810            $popup deactivate
811        }
812        update
813        set inner [$popup component inner]
814        $inner.scrl.text delete 0.0 end
815       
816        $inner.scrl.text insert end "The following error was reported by the render server:\n\n" bold
817        $inner.scrl.text insert end $bytes code
818        update
819        $popup activate $itk_component(hull) below
820    } else {
821        ReceiveEcho <<error $bytes
822        puts stderr "Render server error:\n$bytes"
823    }
824}
825
826
827itcl::body Rappture::VisViewer::ColorsToColormap { colors } {
828    switch -- $colors {
829        "grey-to-blue" {
830            return {
831                0.0                      0.200 0.200 0.200
832                0.14285714285714285      0.400 0.400 0.400
833                0.2857142857142857       0.600 0.600 0.600
834                0.42857142857142855      0.900 0.900 0.900
835                0.5714285714285714       0.800 1.000 1.000
836                0.7142857142857143       0.600 1.000 1.000
837                0.8571428571428571       0.400 0.900 1.000
838                1.0                      0.000 0.600 0.800
839            }
840        }
841        "blue-to-grey" {
842            return {
843                0.0                     0.000 0.600 0.800
844                0.14285714285714285     0.400 0.900 1.000
845                0.2857142857142857      0.600 1.000 1.000
846                0.42857142857142855     0.800 1.000 1.000
847                0.5714285714285714      0.900 0.900 0.900
848                0.7142857142857143      0.600 0.600 0.600
849                0.8571428571428571      0.400 0.400 0.400
850                1.0                     0.200 0.200 0.200
851            }
852        }
853        "blue" {
854            return {
855                0.0                     0.900 1.000 1.000
856                0.1111111111111111      0.800 0.983 1.000
857                0.2222222222222222      0.700 0.950 1.000
858                0.3333333333333333      0.600 0.900 1.000
859                0.4444444444444444      0.500 0.833 1.000
860                0.5555555555555556      0.400 0.750 1.000
861                0.6666666666666666      0.300 0.650 1.000
862                0.7777777777777778      0.200 0.533 1.000
863                0.8888888888888888      0.100 0.400 1.000
864                1.0                     0.000 0.250 1.000
865            }
866        }
867        "brown-to-blue" {
868            return {
869                0.0                             0.200   0.100   0.000
870                0.09090909090909091             0.400   0.187   0.000
871                0.18181818181818182             0.600   0.379   0.210
872                0.2727272727272727              0.800   0.608   0.480
873                0.36363636363636365             0.850   0.688   0.595
874                0.45454545454545453             0.950   0.855   0.808
875                0.5454545454545454              0.800   0.993   1.000
876                0.6363636363636364              0.600   0.973   1.000
877                0.7272727272727273              0.400   0.940   1.000
878                0.8181818181818182              0.200   0.893   1.000
879                0.9090909090909091              0.000   0.667   0.800
880                1.0                             0.000   0.480   0.600
881            }
882        }
883        "blue-to-brown" {
884            return {
885                0.0                             0.000   0.480   0.600
886                0.09090909090909091             0.000   0.667   0.800
887                0.18181818181818182             0.200   0.893   1.000
888                0.2727272727272727              0.400   0.940   1.000
889                0.36363636363636365             0.600   0.973   1.000
890                0.45454545454545453             0.800   0.993   1.000
891                0.5454545454545454              0.950   0.855   0.808
892                0.6363636363636364              0.850   0.688   0.595
893                0.7272727272727273              0.800   0.608   0.480
894                0.8181818181818182              0.600   0.379   0.210
895                0.9090909090909091              0.400   0.187   0.000
896                1.0                             0.200   0.100   0.000
897            }
898        }
899        "blue-to-orange" {
900            return {
901                0.0                             0.000   0.167   1.000
902                0.09090909090909091             0.100   0.400   1.000
903                0.18181818181818182             0.200   0.600   1.000
904                0.2727272727272727              0.400   0.800   1.000
905                0.36363636363636365             0.600   0.933   1.000
906                0.45454545454545453             0.800   1.000   1.000
907                0.5454545454545454              1.000   1.000   0.800
908                0.6363636363636364              1.000   0.933   0.600
909                0.7272727272727273              1.000   0.800   0.400
910                0.8181818181818182              1.000   0.600   0.200
911                0.9090909090909091              1.000   0.400   0.100
912                1.0                             1.000   0.167   0.000
913            }
914        }
915        "orange-to-blue" {
916            return {
917                0.0                             1.000   0.167   0.000
918                0.09090909090909091             1.000   0.400   0.100
919                0.18181818181818182             1.000   0.600   0.200
920                0.2727272727272727              1.000   0.800   0.400
921                0.36363636363636365             1.000   0.933   0.600
922                0.45454545454545453             1.000   1.000   0.800
923                0.5454545454545454              0.800   1.000   1.000
924                0.6363636363636364              0.600   0.933   1.000
925                0.7272727272727273              0.400   0.800   1.000
926                0.8181818181818182              0.200   0.600   1.000
927                0.9090909090909091              0.100   0.400   1.000
928                1.0                             0.000   0.167   1.000
929            }
930        }
931        "rainbow" {
932            set clist {
933                "#EE82EE"
934                "#4B0082"
935                "blue"
936                "#008000"
937                "yellow"
938                "#FFA500"
939                "red"
940            }
941        }
942        "BGYOR" {
943            set clist {
944                "blue"
945                "#008000"
946                "yellow"
947                "#FFA500"
948                "red"
949            }
950        }
951        "ROYGB" {
952            set clist {
953                "red"
954                "#FFA500"
955                "yellow"
956                "#008000"
957                "blue"
958            }
959        }
960        "RYGCB" {
961            set clist {
962                "red"
963                "yellow"
964                "green"
965                "cyan"
966                "blue"
967            }
968        }
969        "BCGYR" {
970            set clist {
971                "blue"
972                "cyan"
973                "green"
974                "yellow"
975                "red"
976            }
977        }
978        "spectral" {
979            return {
980                0.0 0.150 0.300 1.000
981                0.1 0.250 0.630 1.000
982                0.2 0.450 0.850 1.000
983                0.3 0.670 0.970 1.000
984                0.4 0.880 1.000 1.000
985                0.5 1.000 1.000 0.750
986                0.6 1.000 0.880 0.600
987                0.7 1.000 0.680 0.450
988                0.8 0.970 0.430 0.370
989                0.9 0.850 0.150 0.196
990                1.0 0.650 0.000 0.130
991            }
992        }
993        "green-to-magenta" {
994            return {
995                0.0 0.000 0.316 0.000
996                0.06666666666666667 0.000 0.526 0.000
997                0.13333333333333333 0.000 0.737 0.000
998                0.2 0.000 0.947 0.000
999                0.26666666666666666 0.316 1.000 0.316
1000                0.3333333333333333 0.526 1.000 0.526
1001                0.4 0.737 1.000 0.737
1002                0.4666666666666667 1.000 1.000 1.000
1003                0.5333333333333333 1.000 0.947 1.000
1004                0.6 1.000 0.737 1.000
1005                0.6666666666666666 1.000 0.526 1.000
1006                0.7333333333333333 1.000 0.316 1.000
1007                0.8 0.947 0.000 0.947
1008                0.8666666666666667 0.737 0.000 0.737
1009                0.9333333333333333 0.526 0.000 0.526
1010                1.0 0.316 0.000 0.316
1011            }
1012        }
1013        "greyscale" {
1014            return {
1015                0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0
1016            }
1017        }
1018        "nanohub" {
1019            set clist "white yellow green cyan blue magenta"
1020        }
1021        default {
1022            set clist [split $colors ":"]
1023        }
1024    }
1025    set cmap {}
1026    if { [llength $clist] == 1 } {
1027        set rgb [Color2RGB $clist]
1028        append cmap "0.0 $rgb 1.0 $rgb"
1029    } else {
1030        for {set i 0} {$i < [llength $clist]} {incr i} {
1031            set x [expr {double($i)/([llength $clist]-1)}]
1032            set color [lindex $clist $i]
1033            append cmap "$x [Color2RGB $color] "
1034        }
1035    }
1036    return $cmap
1037}
Note: See TracBrowser for help on using the repository browser.