source: branches/r9/gui/scripts/visviewer.tcl @ 4919

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