source: branches/1.5/gui/scripts/visviewer.tcl @ 6127

Last change on this file since 6127 was 6127, checked in by ldelgass, 8 years ago

Merge r6052:6053,r6066:6069,r6080 from trunk

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