source: trunk/gui/scripts/visviewer.tcl @ 6011

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

In VisViewer::SendBytes?, append to output buffer rather than clobbering buffer.
This allows SendBytes? to be called recursively. This can happen in the call to
tkwait in SendBytes? if an event handler calls SendBytes?.

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