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

Last change on this file since 4918 was 4761, checked in by ldelgass, 9 years ago

remove geovis server port from visviewer in release branch

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(nanovis) "localhost:2000"
25    set _servers(pymol)   "localhost:2020"
26    set _servers(vmdmds)  "localhost:2018"
27    set _servers(vtkvis)  "localhost:2010"
28
29    protected variable _serverType "???";# Type of server.
30    protected variable _sid ""      ;   # socket connection to server
31    private common _done            ;   # Used to indicate status of send.
32    private variable _buffer        ;   # buffer for incoming/outgoing commands
33    private variable _initialized
34    private variable _isOpen 0
35    private variable _afterId -1
36    private variable _icon 0
37
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
456    # There's problem when the user is interacting with the GUI at the
457    # same time we're trying to write to the server.  Don't want to
458    # block because, the GUI will look like it's dead.  We can start
459    # by putting a busy window over plot so that inadvertent things like
460    # mouse movements aren't received.
461
462    blt::busy hold $itk_component(main)
463    fileevent $_sid writable [itcl::code $this SendHelper]
464    tkwait variable ::Rappture::VisViewer::_done($this)
465    blt::busy release $itk_component(main)
466
467    set _buffer(out) ""
468    if { [IsConnected] } {
469        # The connection may have closed while we were writing to the server.
470        # This can happen if what we sent the server caused it to barf.
471        fileevent $_sid writable ""
472        flush $_sid
473    }
474    return $_done($this)
475}
476
477#
478# StartWaiting --
479#
480#    Read some number of bytes from the visualization server.
481#
482
483itcl::body Rappture::VisViewer::StartWaiting {} {
484    if { $_waitTimeout > 0 } {
485        after cancel $_afterId
486        set _afterId [after $_waitTimeout [itcl::code $this WaitDialog on]]
487    }
488}
489
490itcl::body Rappture::VisViewer::StopWaiting {} {
491    if { $_waitTimeout > 0 } {
492        WaitDialog off
493    }
494}
495
496itcl::body Rappture::VisViewer::EnableWaitDialog { value } {
497    set _waitTimeout $value
498}
499
500#
501# ReceiveBytes --
502#
503#    Read some number of bytes from the visualization server.
504#
505itcl::body Rappture::VisViewer::ReceiveBytes { size } {
506    if { ![CheckConnection] } {
507        return 0
508    }
509    set bytes [read $_sid $size]
510    ReceiveEcho <<line "<read $size bytes"
511    StopWaiting
512    return $bytes
513}
514
515#
516# ReceiveHelper --
517#
518#   Helper routine called from a file event when the connection is readable
519#   (i.e. a command response has been sent by the rendering server.  Reads
520#   the incoming command and executes it in a safe interpreter to handle the
521#   action.
522#
523#       Note: This routine currently only handles command responses from
524#         the visualization server.  It doesn't handle non-blocking
525#         reads from the visualization server.
526#
527#       nv>image -bytes 100000      yes
528#       ...following 100000 bytes...    no
529#
530#   Note: All commands from the render server are on one line.
531#         This is because the render server can send anything
532#         as an error message (restricted again to one line).
533#
534itcl::body Rappture::VisViewer::ReceiveHelper {} {
535    if { ![CheckConnection] } {
536        return 0
537    }
538    set n [gets $_sid line]
539
540    if { $n < 0 } {
541        Disconnect
542        return 0
543    }
544    set line [string trim $line]
545    if { $line == "" } {
546        return
547    }
548    if { [string compare -length 3 $line "nv>"] == 0 } {
549        ReceiveEcho <<line $line
550        append _buffer(in) [string range $line 3 end]
551        append _buffer(in) "\n"
552        if {[info complete $_buffer(in)]} {
553            set request $_buffer(in)
554            set _buffer(in) ""
555            if { [catch {$_parser eval $request} err]  != 0 } {
556                global errorInfo
557                puts stderr "err=$err errorInfo=$errorInfo"
558            }
559        }
560    } elseif { [string compare -length 21 $line "NanoVis Server Error:"] == 0 ||
561               [string compare -length 20 $line "VtkVis Server Error:"] == 0} {
562        # this shows errors coming back from the engine
563        ReceiveEcho <<error $line
564        puts stderr "Render Server Error: $line\n"
565    } else {
566        # this shows errors coming back from the engine
567        ReceiveEcho <<error $line
568        puts stderr "Garbled message: $line\n"
569    }
570}
571
572#
573# Color2RGB --
574#
575#   Converts a color name to a list of r,g,b values needed for the engine.
576#   Each r/g/b component is scaled in the # range 0-1.
577#
578itcl::body Rappture::VisViewer::Color2RGB {color} {
579    foreach {r g b} [winfo rgb $itk_component(hull) $color] break
580    set r [expr {$r/65535.0}]
581    set g [expr {$g/65535.0}]
582    set b [expr {$b/65535.0}]
583    return [list $r $g $b]
584}
585
586#
587# Euler2XYZ --
588#
589#   Converts euler angles for the camera placement the to angles of
590#   rotation about the x/y/z axes, used by the engine.  Returns a list:
591#   {xangle, yangle, zangle}.
592#
593itcl::body Rappture::VisViewer::Euler2XYZ {theta phi psi} {
594    set xangle [expr {$theta-90.0}]
595    set yangle [expr {180.0-$phi}]
596    set zangle $psi
597    return [list $xangle $yangle $zangle]
598}
599
600#
601# SendEcho --
602#
603#     Used internally to echo sent data to clients interested in this widget.
604#     If the -sendcommand option is set, then it is invoked in the global scope
605#     with the <channel> and <data> values as arguments.  Otherwise, this does
606#     nothing.
607#
608itcl::body Rappture::VisViewer::SendEcho {channel {data ""}} {
609    if { $_logging }  {
610        set f [open "/tmp/recording.log" "a"]
611        fconfigure $f -translation binary -encoding binary
612        puts -nonewline $f $data
613        close $f
614    }
615    #puts stderr ">>($data)"
616    if {[string length $itk_option(-sendcommand)] > 0} {
617        uplevel #0 $itk_option(-sendcommand) [list $channel $data]
618    }
619}
620
621#
622# ReceiveEcho --
623#
624#     Echoes received data to clients interested in this widget.  If the
625#     -receivecommand option is set, then it is invoked in the global scope
626#     with the <channel> and <data> values as arguments.  Otherwise, this
627#     does nothing.
628#
629itcl::body Rappture::VisViewer::ReceiveEcho {channel {data ""}} {
630    #puts stderr "<<line $data"
631    if {[string length $itk_option(-receivecommand)] > 0} {
632        uplevel #0 $itk_option(-receivecommand) [list $channel $data]
633    }
634}
635
636itcl::body Rappture::VisViewer::WaitDialog { state } {
637    after cancel $_afterId
638    set _afterId -1
639    if { $state } {
640        if { [winfo exists $itk_component(plotarea).view.splash] } {
641            return
642        }
643        set inner [frame $itk_component(plotarea).view.splash]
644        $inner configure -relief raised -bd 2
645        label $inner.text1 -text "Working...\nPlease wait." \
646            -font "Arial 10"
647        label $inner.icon
648        pack $inner -expand yes -anchor c
649        blt::table $inner \
650            0,0 $inner.text1 -anchor w \
651            0,1 $inner.icon
652        Waiting start $inner.icon
653    } else {
654        if { ![winfo exists $itk_component(plotarea).view.splash] } {
655            return
656        }
657        Waiting stop $itk_component(plotarea).view.splash
658        destroy $itk_component(plotarea).view.splash
659    }
660}
661
662itcl::body Rappture::VisViewer::Waiting { option widget } {
663    switch -- $option {
664        "start" {
665            $_dispatcher dispatch $this !waiting \
666                "[itcl::code $this Waiting "next" $widget] ; list"
667            set _icon 0
668            $widget configure -image [Rappture::icon bigroller${_icon}]
669            $_dispatcher event -after 150 !waiting
670        }
671        "next" {
672            incr _icon
673            if { $_icon >= 8 } {
674                set _icon 0
675            }
676            $widget configure -image [Rappture::icon bigroller${_icon}]
677            $_dispatcher event -after 150 !waiting
678        }
679        "stop" {
680            $_dispatcher cancel !waiting
681        }
682    }
683}
684
685#
686# HideConsole --
687#
688#    Hide the debug console by withdrawing its toplevel window.
689#
690itcl::body Rappture::VisViewer::HideConsole {} {
691    set _debugConsole 0
692    DebugConsole
693}
694
695#
696# BuildConsole --
697#
698#    Create and pack the widgets that make up the debug console: a text
699#    widget to display the communication and an entry widget to type
700#    in commands to send to the render server.
701#
702itcl::body Rappture::VisViewer::BuildConsole {} {
703    toplevel .renderconsole
704    wm protocol .renderconsole WM_DELETE_WINDOW [itcl::code $this HideConsole]
705    set f .renderconsole
706    frame $f.send
707    pack $f.send -side bottom -fill x
708    label $f.send.l -text "Send:"
709    pack $f.send.l -side left
710    itk_component add command {
711        entry $f.send.e -background white
712    } {
713        ignore -background
714    }
715    pack $f.send.e -side left -expand yes -fill x
716    bind $f.send.e <Return> [itcl::code $this SendDebugCommand]
717    bind $f.send.e <KP_Enter> [itcl::code $this SendDebugCommand]
718    scrollbar $f.sb -orient vertical -command "$f.comm yview"
719    pack $f.sb -side right -fill y
720    itk_component add trace {
721        text $f.comm -wrap char -yscrollcommand "$f.sb set" -background white
722    } {
723        ignore -background
724    }
725    pack $f.comm -expand yes -fill both
726    bind $f.comm <Control-F1> [itcl::code $this ToggleConsole]
727    bind $f.comm <Enter> [list focus %W]
728    bind $f.send.e <Control-F1> [itcl::code $this ToggleConsole]
729
730    $itk_component(trace) tag configure error -foreground red \
731        -font -*-courier-medium-o-normal-*-*-120-*
732    $itk_component(trace) tag configure incoming -foreground blue
733}
734
735#
736# ToggleConsole --
737#
738#    This is used by derived classes to turn on/off debuging.  It's
739#    up the to derived class to decide how to turn on/off debugging.
740#
741itcl::body Rappture::VisViewer::ToggleConsole {} {
742    if { $_debugConsole } {
743        set _debugConsole 0
744    } else {
745        set _debugConsole 1
746    }
747    DebugConsole
748}
749
750#
751# DebugConsole --
752#
753#    Based on the value of the variable _debugConsole, turns on/off
754#    debugging. This is done by setting/unsetting a procedure that
755#    is called whenever new characters are received or sent on the
756#    socket to the render server.  Additionally, the debug console
757#    is created if necessary and hidden/shown.
758#
759itcl::body Rappture::VisViewer::DebugConsole {} {
760    if { ![winfo exists .renderconsole] } {
761        BuildConsole
762    }
763    if { $_debugConsole } {
764        $this configure -sendcommand [itcl::code $this TraceComm]
765        $this configure -receivecommand [itcl::code $this TraceComm]
766        wm deiconify .renderconsole
767    } else {
768        $this configure -sendcommand ""
769        $this configure -receivecommand ""
770        wm withdraw .renderconsole
771    }
772}
773
774# ----------------------------------------------------------------------
775# USAGE: TraceComm <channel> <data>
776#
777# Invoked automatically whenever there is communication between
778# the rendering widget and the server.  Eavesdrops on the communication
779# and posts the commands in a text viewer.
780# ----------------------------------------------------------------------
781itcl::body Rappture::VisViewer::TraceComm {channel {data ""}} {
782    $itk_component(trace) configure -state normal
783    switch -- $channel {
784        closed {
785            $itk_component(trace) insert end "--CLOSED--\n" error
786        }
787        <<line {
788            $itk_component(trace) insert end $data incoming "\n" incoming
789        }
790        >>line {
791            $itk_component(trace) insert end $data outgoing "\n" outgoing
792        }
793        error {
794            $itk_component(trace) insert end $data error "\n" error
795        }
796        default {
797            $itk_component(trace) insert end "$data\n"
798        }
799    }
800    $itk_component(trace) configure -state disabled
801    $itk_component(trace) see end
802}
803
804# ----------------------------------------------------------------------
805# USAGE: SendDebugCommand
806#
807# Invoked automatically whenever the user enters a command and
808# presses <Return>.  Sends the command along to the rendering
809# widget.
810# ----------------------------------------------------------------------
811itcl::body Rappture::VisViewer::SendDebugCommand {} {
812    set cmd [$itk_component(command) get]
813    append cmd "\n"
814    SendBytes $cmd
815    $itk_component(command) delete 0 end
816}
817
818#
819# HandleOk --
820#
821#       This handles the "ok" response from the server that acknowledges
822#       the reception of a server command, but does not produce an image.
823#       It may pass an argument such as "-token 9" that could be used to
824#       determine how many commands have been processed by the server.
825#
826itcl::body Rappture::VisViewer::HandleOk { args } {
827    if { $_waitTimeout > 0 } {
828        StopWaiting
829    }
830}
831
832#
833# HandleError --
834#
835#       This handles the "viserror" response from the server that reports
836#       that a client-initiated error has occurred on the server.
837#
838itcl::body Rappture::VisViewer::HandleError { args } {
839    array set info {
840        -token "???"
841        -bytes 0
842        -type "???"
843    }
844    array set info $args
845    set bytes [ReceiveBytes $info(-bytes)]
846    if { $info(-type) == "error" } {
847        set popup $itk_component(hull).error
848        if { ![winfo exists $popup] } {
849            Rappture::Balloon $popup \
850                -title "Render Server Error"
851            set inner [$popup component inner]
852            label $inner.summary -text "" -anchor w
853
854            Rappture::Scroller $inner.scrl \
855                -xscrollmode auto -yscrollmode auto
856            text $inner.scrl.text \
857                -font "Arial 9 " -background white -relief sunken -bd 1 \
858                -height 5 -wrap word -width 60
859            $inner.scrl contents $inner.scrl.text
860            button $inner.ok -text "Dismiss" -command [list $popup deactivate] \
861                -font "Arial 9"
862            blt::table $inner \
863                0,0 $inner.scrl -fill both \
864                1,0 $inner.ok
865            $inner.scrl.text tag configure normal -font "Arial 9"
866            $inner.scrl.text tag configure italic -font "Arial 9 italic"
867            $inner.scrl.text tag configure bold -font "Arial 10 bold"
868            $inner.scrl.text tag configure code -font "Courier 10 bold"
869        } else {
870            $popup deactivate
871        }
872        update
873        set inner [$popup component inner]
874        $inner.scrl.text delete 0.0 end
875       
876        $inner.scrl.text configure -state normal
877        $inner.scrl.text insert end "The following error was reported by the render server:\n\n" bold
878        $inner.scrl.text insert end $bytes code
879        $inner.scrl.text configure -state disabled
880        update
881        $popup activate $itk_component(hull) below
882    } else {
883        ReceiveEcho <<error $bytes
884        puts stderr "Render server error:\n$bytes"
885    }
886}
887
888itcl::body Rappture::VisViewer::GetColormapList { args } {
889    array set opts {
890        -includeDefault 0
891        -includeElementDefault 0
892        -includeNone 0
893    }
894    if {[llength $args] > 0} {
895        foreach opt $args {
896            set opts($opt) 1
897        }
898    }
899    set colormaps [list]
900    if {$opts(-includeDefault)} {
901        lappend colormaps "default" "default"
902    }
903    if {$opts(-includeElementDefault)} {
904        lappend colormaps "elementDefault" "elementDefault"
905    }
906    lappend colormaps \
907        "BCGYR"              "BCGYR"            \
908        "BGYOR"              "BGYOR"            \
909        "blue-to-brown"      "blue-to-brown"    \
910        "blue-to-orange"     "blue-to-orange"   \
911        "blue-to-grey"       "blue-to-grey"     \
912        "green-to-magenta"   "green-to-magenta" \
913        "greyscale"          "greyscale"        \
914        "nanohub"            "nanohub"          \
915        "rainbow"            "rainbow"          \
916        "spectral"           "spectral"         \
917        "ROYGB"              "ROYGB"            \
918        "RYGCB"              "RYGCB"            \
919        "white-to-blue"      "white-to-blue"    \
920        "brown-to-blue"      "brown-to-blue"    \
921        "grey-to-blue"       "grey-to-blue"     \
922        "orange-to-blue"     "orange-to-blue"
923    if {$opts(-includeNone)} {
924        lappend colormaps "none" "none"
925    }
926    return $colormaps
927}
928
929itcl::body Rappture::VisViewer::ColorsToColormap { colors } {
930    switch -- $colors {
931        "grey-to-blue" {
932            return {
933                0.0                      0.200 0.200 0.200
934                0.14285714285714285      0.400 0.400 0.400
935                0.2857142857142857       0.600 0.600 0.600
936                0.42857142857142855      0.900 0.900 0.900
937                0.5714285714285714       0.800 1.000 1.000
938                0.7142857142857143       0.600 1.000 1.000
939                0.8571428571428571       0.400 0.900 1.000
940                1.0                      0.000 0.600 0.800
941            }
942        }
943        "blue-to-grey" {
944            return {
945                0.0                     0.000 0.600 0.800
946                0.14285714285714285     0.400 0.900 1.000
947                0.2857142857142857      0.600 1.000 1.000
948                0.42857142857142855     0.800 1.000 1.000
949                0.5714285714285714      0.900 0.900 0.900
950                0.7142857142857143      0.600 0.600 0.600
951                0.8571428571428571      0.400 0.400 0.400
952                1.0                     0.200 0.200 0.200
953            }
954        }
955        "white-to-blue" {
956            return {
957                0.0                     0.900 1.000 1.000
958                0.1111111111111111      0.800 0.983 1.000
959                0.2222222222222222      0.700 0.950 1.000
960                0.3333333333333333      0.600 0.900 1.000
961                0.4444444444444444      0.500 0.833 1.000
962                0.5555555555555556      0.400 0.750 1.000
963                0.6666666666666666      0.300 0.650 1.000
964                0.7777777777777778      0.200 0.533 1.000
965                0.8888888888888888      0.100 0.400 1.000
966                1.0                     0.000 0.250 1.000
967            }
968        }
969        "brown-to-blue" {
970            return {
971                0.0                             0.200   0.100   0.000
972                0.09090909090909091             0.400   0.187   0.000
973                0.18181818181818182             0.600   0.379   0.210
974                0.2727272727272727              0.800   0.608   0.480
975                0.36363636363636365             0.850   0.688   0.595
976                0.45454545454545453             0.950   0.855   0.808
977                0.5454545454545454              0.800   0.993   1.000
978                0.6363636363636364              0.600   0.973   1.000
979                0.7272727272727273              0.400   0.940   1.000
980                0.8181818181818182              0.200   0.893   1.000
981                0.9090909090909091              0.000   0.667   0.800
982                1.0                             0.000   0.480   0.600
983            }
984        }
985        "blue-to-brown" {
986            return {
987                0.0                             0.000   0.480   0.600
988                0.09090909090909091             0.000   0.667   0.800
989                0.18181818181818182             0.200   0.893   1.000
990                0.2727272727272727              0.400   0.940   1.000
991                0.36363636363636365             0.600   0.973   1.000
992                0.45454545454545453             0.800   0.993   1.000
993                0.5454545454545454              0.950   0.855   0.808
994                0.6363636363636364              0.850   0.688   0.595
995                0.7272727272727273              0.800   0.608   0.480
996                0.8181818181818182              0.600   0.379   0.210
997                0.9090909090909091              0.400   0.187   0.000
998                1.0                             0.200   0.100   0.000
999            }
1000        }
1001        "blue-to-orange" {
1002            return {
1003                0.0                             0.000   0.167   1.000
1004                0.09090909090909091             0.100   0.400   1.000
1005                0.18181818181818182             0.200   0.600   1.000
1006                0.2727272727272727              0.400   0.800   1.000
1007                0.36363636363636365             0.600   0.933   1.000
1008                0.45454545454545453             0.800   1.000   1.000
1009                0.5454545454545454              1.000   1.000   0.800
1010                0.6363636363636364              1.000   0.933   0.600
1011                0.7272727272727273              1.000   0.800   0.400
1012                0.8181818181818182              1.000   0.600   0.200
1013                0.9090909090909091              1.000   0.400   0.100
1014                1.0                             1.000   0.167   0.000
1015            }
1016        }
1017        "orange-to-blue" {
1018            return {
1019                0.0                             1.000   0.167   0.000
1020                0.09090909090909091             1.000   0.400   0.100
1021                0.18181818181818182             1.000   0.600   0.200
1022                0.2727272727272727              1.000   0.800   0.400
1023                0.36363636363636365             1.000   0.933   0.600
1024                0.45454545454545453             1.000   1.000   0.800
1025                0.5454545454545454              0.800   1.000   1.000
1026                0.6363636363636364              0.600   0.933   1.000
1027                0.7272727272727273              0.400   0.800   1.000
1028                0.8181818181818182              0.200   0.600   1.000
1029                0.9090909090909091              0.100   0.400   1.000
1030                1.0                             0.000   0.167   1.000
1031            }
1032        }
1033        "rainbow" {
1034            set clist {
1035                "#EE82EE"
1036                "#4B0082"
1037                "blue"
1038                "#008000"
1039                "yellow"
1040                "#FFA500"
1041                "red"
1042            }
1043        }
1044        "BGYOR" {
1045            set clist {
1046                "blue"
1047                "#008000"
1048                "yellow"
1049                "#FFA500"
1050                "red"
1051            }
1052        }
1053        "ROYGB" {
1054            set clist {
1055                "red"
1056                "#FFA500"
1057                "yellow"
1058                "#008000"
1059                "blue"
1060            }
1061        }
1062        "RYGCB" {
1063            set clist {
1064                "red"
1065                "yellow"
1066                "green"
1067                "cyan"
1068                "blue"
1069            }
1070        }
1071        "BCGYR" {
1072            set clist {
1073                "blue"
1074                "cyan"
1075                "green"
1076                "yellow"
1077                "red"
1078            }
1079        }
1080        "spectral" {
1081            return {
1082                0.0 0.150 0.300 1.000
1083                0.1 0.250 0.630 1.000
1084                0.2 0.450 0.850 1.000
1085                0.3 0.670 0.970 1.000
1086                0.4 0.880 1.000 1.000
1087                0.5 1.000 1.000 0.750
1088                0.6 1.000 0.880 0.600
1089                0.7 1.000 0.680 0.450
1090                0.8 0.970 0.430 0.370
1091                0.9 0.850 0.150 0.196
1092                1.0 0.650 0.000 0.130
1093            }
1094        }
1095        "green-to-magenta" {
1096            return {
1097                0.0 0.000 0.316 0.000
1098                0.06666666666666667 0.000 0.526 0.000
1099                0.13333333333333333 0.000 0.737 0.000
1100                0.2 0.000 0.947 0.000
1101                0.26666666666666666 0.316 1.000 0.316
1102                0.3333333333333333 0.526 1.000 0.526
1103                0.4 0.737 1.000 0.737
1104                0.4666666666666667 1.000 1.000 1.000
1105                0.5333333333333333 1.000 0.947 1.000
1106                0.6 1.000 0.737 1.000
1107                0.6666666666666666 1.000 0.526 1.000
1108                0.7333333333333333 1.000 0.316 1.000
1109                0.8 0.947 0.000 0.947
1110                0.8666666666666667 0.737 0.000 0.737
1111                0.9333333333333333 0.526 0.000 0.526
1112                1.0 0.316 0.000 0.316
1113            }
1114        }
1115        "greyscale" {
1116            return {
1117                0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0
1118            }
1119        }
1120        "nanohub" {
1121            set clist "white yellow green cyan blue magenta"
1122        }
1123        default {
1124            set clist [split $colors ":"]
1125        }
1126    }
1127    set cmap {}
1128    if { [llength $clist] == 1 } {
1129        set rgb [Color2RGB $clist]
1130        append cmap "0.0 $rgb 1.0 $rgb"
1131    } else {
1132        for {set i 0} {$i < [llength $clist]} {incr i} {
1133            set x [expr {double($i)/([llength $clist]-1)}]
1134            set color [lindex $clist $i]
1135            append cmap "$x [Color2RGB $color] "
1136        }
1137    }
1138    return $cmap
1139}
1140
1141
1142#
1143# StartBufferingCommands --
1144#
1145itcl::body Rappture::VisViewer::StartBufferingCommands { } {
1146    incr _buffering
1147    if { $_buffering == 1 } {
1148        set _outbuf ""
1149    }
1150}
1151
1152#
1153# StopBufferingCommands --
1154#
1155#       This gets called when we want to stop buffering the commands for
1156#       the server and actually send then to the server.  Note that there's
1157#       a reference count on buffering.  This is so that you can can
1158#       Start/Stop multiple times without worrying about the current state.
1159#
1160itcl::body Rappture::VisViewer::StopBufferingCommands { } {
1161    incr _buffering -1
1162    if { $_buffering == 0 } {
1163        SendBytes $_outbuf
1164        set _outbuf ""
1165    }
1166}
1167
1168#
1169# SendCmd
1170#
1171#       Send commands off to the rendering server.  If we're currently
1172#       sending data objects to the server, buffer the commands to be
1173#       sent later.
1174#
1175itcl::body Rappture::VisViewer::SendCmd {string} {
1176    if { $_buffering } {
1177        append _outbuf $string "\n"
1178    } else {
1179        SendBytes "$string\n"
1180    }
1181}
1182
1183#
1184# SendCmdNoWait
1185#
1186#       Send commands off to the rendering server.  If we're currently
1187#       sending data objects to the server, buffer the commands to be
1188#       sent later.
1189#
1190itcl::body Rappture::VisViewer::SendCmdNoWait {string} {
1191    if { $_buffering } {
1192        append _outbuf $string "\n"
1193    } else {
1194        SendBytes "$string\n"
1195    }
1196}
Note: See TracBrowser for help on using the repository browser.