source: branches/1.3/gui/scripts/visviewer.tcl @ 4447

Last change on this file since 4447 was 4447, checked in by ldelgass, 10 years ago

whitespace

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