source: branches/1.4/gui/scripts/visviewer.tcl @ 5096

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

merge r5068:r5069 from trunk

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