source: branches/1.6/gui/scripts/visviewer.tcl @ 6170

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

merge r6011 from trunk (append to output buffer in visviewer)

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