source: branches/uq/gui/scripts/visviewer.tcl @ 5679

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

Full merge 1.3 branch to uq branch to sync. Fixed partial subdirectory merge
by removing mergeinfo from lang/python/Rappture directory.

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