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

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

start of fix for multiple fields in isosurfaces

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