ASCII animation

Richard Suchenwirth 2005-08-05 - When a longer-running process runs in a terminal window, it may be helpful for the user to indicate that it is still active. Here's a simple way of producing some animation on stdout: You store the "phases" you want to display in a variable, and in certain intervals call ascii_animate which will display the first of the phases on stdout, followed by CR but no LF, so the next operation will occur in the same place. Also, the phases list is cycled, with the first element being moved to the end of the list. The example shows a short bar that seems to rotate :)


 set phases {- / | \\}

 proc ascii_animate _var {
    upvar 1 $_var var
    puts -nonewline [lindex $var 0]\r
    flush stdout
    set var [concat [lrange $var 1 end] [lindex $var 0]]
 }
#-- Test:
 while 1 {
    ascii_animate phases
    after 500
 }

RS 2013-12-09: The above test uses a blocking while loop. For practical application, you'd better use an every timer:

 every 500 ascii_animate phases

Lectus: And here is a Progress Bar command ready to be used.

It displays like this: (Your message) |###| 30%

#|---------------------------|
#| ASCII_ProgressBar command |
#|---------------------------|

namespace eval ASCII_ProgressBar {
        variable count 0
        variable p "#"
        variable msg ""
        proc new {message} {
                set ASCII_ProgressBar::count 0
                set ASCII_ProgressBar::p "#"
                puts -nonewline "${message} \|| 0%\r"
                flush stdout
                set ASCII_ProgressBar::msg $message
        }
        
        proc increase {n {timer 0}} {
                for {set i 0} {$i < $n} {incr i} {incr ASCII_ProgressBar::count}
                for {set i 0} {$i < $n} {incr i 10} {append ASCII_ProgressBar::p "\010#\|"}
                if {[string length $ASCII_ProgressBar::p] == 10} { append ASCII_ProgressBar::p "\010\|"}
                
                puts -nonewline "${ASCII_ProgressBar::msg} \|${ASCII_ProgressBar::p} ${ASCII_ProgressBar::count}%\r"; flush stdout;
                after $timer
        }
        
        namespace export new increase
        namespace ensemble create
}

#|----------|
#| Examples |
#|----------|

# First
ASCII_ProgressBar new "Computing operation 1..."
ASCII_ProgressBar increase 10 500
ASCII_ProgressBar increase 10 500
# simple operation
set x 8
ASCII_ProgressBar increase 20 1000
set y 4
#another one
ASCII_ProgressBar increase 20 1000
set z [expr $x * $y]
ASCII_ProgressBar increase 30 1000
set z [expr $z + 10]
ASCII_ProgressBar increase 10 1000
puts "\n\nWe're done and the operation resulted: $z"

puts "\n"

# Second
ASCII_ProgressBar new "Computing operation 2..."
ASCII_ProgressBar increase 10 500
ASCII_ProgressBar increase 10 500
# simple operation
set x $z
ASCII_ProgressBar increase 20 1000
set y 2
#another one
ASCII_ProgressBar increase 20 1000
set z [expr $z * $y]
ASCII_ProgressBar increase 30 1000
set z [expr $z + 10]
ASCII_ProgressBar increase 10 1000
puts "\n\nWe're done and the operation resulted: $z"