[Keith Vetter] 2019-10-01 : A spinner, also known as a https://en.wikipedia.org/wiki/Throbber%|%throbber%|%,
is an animated graphic
element used to show that a computer program is performing an action
in the background. It's related to a progress bar except it does not
convey how much of the action has been completed. A text spinner is a
spinner which just uses characters in its animation. Historically text
spinners rotated through the sequence "\" "\" "|" "/", but as this
package demonstrates, much fancier ones have been constructed.
This package provides an interface to over 50 different text spinners. It lets you
add a spinner to widget or a textvar, and it will automatically update the item at
an interval set by the spinner type.
As usual, I've provided a short demo which displays ten different spinners all
animating simultaneously.
----
[Jeff Smith] 2019-09-02 : Below is an online demo using [CloudTk]
'''Please Note''' : This demo has a run time of 2 minutes.
<<inlinehtml>>
<iframe height="1400" width="1800" src="https://cloudtk-app.tcl-lang.org/cloudtk/VNC?session=new&Tk=Text-Spinner" allowfullscreen></iframe>
<<inlinehtml>>
----
======
##+##########################################################################
#
# spinners -- Package that provides 50+ different types of text Spinners.
# by Keith Vetter 2019-10-01
#
# Usage:
# pack [label .l -textvar my_var]
# [optional] lassign [::Spinner::Info :random:] spinnerName interval frames maxWidth
# set id [::Spinner::Start spinnerName my_var]
# ::Spinner::Stop $id
#
# Can also work without Tk--it will periodically update the variable you give it
#
namespace eval Spinner {
# Inspired by https://www.npmjs.com/package/cli-spinners
# and https://stackoverflow.com/questions/2685435/cooler-ascii-spinners
variable NextID 0
variable ACTIVE
variable SPINNERS
array set SPINNERS {
dots { 80 { ⠋ ⠙ ⠹ ⠸ ⠼ ⠴ ⠦ ⠧ ⠇ ⠏ }}
dots2 { 80 { ⣾ ⣽ ⣻ ⢿ ⡿ ⣟ ⣯ ⣷ }}
dots3 { 80 { ⠋ ⠙ ⠚ ⠞ ⠖ ⠦ ⠴ ⠲ ⠳ ⠓ }}
dots4 { 80 { ⠄ ⠆ ⠇ ⠋ ⠙ ⠸ ⠰ ⠠ ⠰ ⠸ ⠙ ⠋ ⠇ ⠆ }}
dots5 { 80 { ⠋ ⠙ ⠚ ⠒ ⠂ ⠂ ⠒ ⠲ ⠴ ⠦ ⠖ ⠒ ⠐ ⠐ ⠒ ⠓ ⠋ }}
dots6 { 80 { ⠁ ⠉ ⠙ ⠚ ⠒ ⠂ ⠂ ⠒ ⠲ ⠴ ⠤ ⠄ ⠄ ⠤ ⠴ ⠲ ⠒ ⠂ ⠂ ⠒ ⠚ ⠙ ⠉ ⠁ }}
dots7 { 80 { ⠈ ⠉ ⠋ ⠓ ⠒ ⠐ ⠐ ⠒ ⠖ ⠦ ⠤ ⠠ ⠠ ⠤ ⠦ ⠖ ⠒ ⠐ ⠐ ⠒ ⠓ ⠋ ⠉ ⠈ }}
dots8 { 80 { ⠁ ⠁ ⠉ ⠙ ⠚ ⠒ ⠂ ⠂ ⠒ ⠲ ⠴ ⠤ ⠄ ⠄ ⠤ ⠠ ⠠ ⠤ ⠦ ⠖ ⠒ ⠐ ⠐ ⠒ ⠓ ⠋ ⠉ ⠈ ⠈ }}
dots9 { 80 { ⢹ ⢺ ⢼ ⣸ ⣇ ⡧ ⡗ ⡏ }}
dots10 { 80 { ⢄ ⢂ ⢁ ⡁ ⡈ ⡐ ⡠ }}
dots11 { 100 { ⠁ ⠂ ⠄ ⡀ ⢀ ⠠ ⠐ ⠈ }}
dots12 { 80 { ⢀⠀ ⡀⠀ ⠄⠀ ⢂⠀ ⡂⠀ ⠅⠀ ⢃⠀ ⡃⠀ ⠍⠀ ⢋⠀ ⡋⠀ ⠍⠁ ⢋⠁ ⡋⠁ ⠍⠉ ⠋⠉ ⠋⠉ ⠉⠙ ⠉⠙ ⠉⠩ ⠈⢙ ⠈⡙ ⢈⠩ ⡀⢙ ⠄⡙ ⢂⠩ ⡂⢘ ⠅⡘ ⢃⠨ ⡃⢐ ⠍⡐ ⢋⠠ ⡋⢀ ⠍⡁ ⢋⠁ ⡋⠁ ⠍⠉ ⠋⠉ ⠋⠉ ⠉⠙ ⠉⠙ ⠉⠩ ⠈⢙ ⠈⡙ ⠈⠩ ⠀⢙ ⠀⡙ ⠀⠩ ⠀⢘ ⠀⡘ ⠀⠨ ⠀⢐ ⠀⡐ ⠀⠠ ⠀⢀ ⠀⡀ }}
line { 130 { - \\ | / }}
line2 { 100 { ⠂ - – — – - }}
pipe { 100 { ┤ ┘ ┴ └ ├ ┌ ┬ ┐ }}
simpleDots { 400 { {. } {.. } ... { } }}
simpleDotsScrolling { 200 { {. } {.. } ... { ..} { .} { } }}
star { 70 { ✶ ✸ ✹ ✺ ✹ ✷ }}
star2 { 80 { + x * }}
flip { 70 { _ _ _ - ` ` ' ´ - _ _ _ }}
hamburger { 100 { ☱ ☲ ☴ }}
growVertical { 120 { ▁ ▃ ▄ ▅ ▆ ▇ ▆ ▅ ▄ ▃ }}
growHorizontal { 120 { ▏ ▎ ▍ ▌ ▋ ▊ ▉ ▊ ▋ ▌ ▍ ▎ }}
balloon { 140 { { } . o O @ * { } }}
balloon2 { 120 { . o O ° O o . }}
noise { 100 { ▓ ▒ ░ }}
bounce { 120 { ⠁ ⠂ ⠄ ⠂ }}
boxBounce { 120 { ▖ ▘ ▝ ▗ }}
boxBounce2 { 100 { ▌ ▀ ▐ ▄ }}
triangle { 50 { ◢ ◣ ◤ ◥ }}
arc { 100 { ◜ ◠ ◝ ◞ ◡ ◟ }}
circle { 120 { ◡ ⊙ ◠ }}
squareCorners { 180 { ◰ ◳ ◲ ◱ }}
circleQuarters { 120 { ◴ ◷ ◶ ◵ }}
circleHalves { 50 { ◐ ◓ ◑ ◒ }}
squish { 100 { ╫ ╪ }}
toggle { 250 { ⊶ ⊷ }}
toggle2 { 80 { ▫ ▪ }}
toggle3 { 120 { □ ■ }}
toggle4 { 100 { ■ □ ▪ ▫ }}
toggle5 { 100 { ▮ ▯ }}
toggle6 { 300 { ဝ ၀ }}
toggle7 { 80 { ⦾ ⦿ }}
toggle8 { 100 { ◍ ◌ }}
toggle9 { 100 { ◉ ◎ }}
toggle10 { 100 { ㊂ ㊀ ㊁ }}
toggle11 { 50 { ⧇ ⧆ }}
toggle12 { 120 { ☗ ☖ }}
toggle13 { 80 { = * - }}
arrow { 100 { ← ↖ ↑ ↗ → ↘ ↓ ↙ }}
arrow2 { 80 { {⬆️ } {↗️ } {➡️ } {↘️ } {⬇️ } {↙️ } {⬅️ } {↖️ } }}
arrow3 { 120 { ▹▹▹▹▹ ▸▹▹▹▹ ▹▸▹▹▹ ▹▹▸▹▹ ▹▹▹▸▹ ▹▹▹▹▸ }}
arrow4 {140 {{⬈ } {➞ } {⬊ } {⬋ } {⬅ } {⬉ }}} clock {140 {%F0%9F%95%9B %F0%9F%95%A7 %F0%9F%95%90 %F0%9F%95%9C %F0%9F%95%91 %F0%9F%95%9D %F0%9F%95%92 %F0%9F%95%9E %F0%9F%95%93 %F0%9F%95%9F %F0%9F%95%94 %F0%9F%95%A0 %F0%9F%95%95 %F0%9F%95%96 %F0%9F%95%97 %F0%9F%95%98 %F0%9F%95%99 %F0%9F%95%9A %F0%9F%95%A1 %F0%9F%95%A2 %F0%9F%95%A3 %F0%9F%95%A4 %F0%9F%95%A5 %F0%9F%95%A6}}
bird {140 {︷ ︵ ︹ ︺ ︶ ︸ ︶ ︺ ︹ ︵}}
bouncingBar { 80 { {[ ]} {[= ]} {[== ]} {[=== ]} {[ ===]} {[ ==]} {[ =]} {[ ]} {[ =]} {[ ==]} {[ ===]} {[====]} {[=== ]} {[== ]} {[= ]} }}
bouncingBall { 80 { {( ● )} {( ● )} {( ● )} {( ● )} {( ●)} {( ● )} {( ● )} {( ● )} {( ● )} {(● )} }}
pong { 80 { {▐⠂ ▌} {▐⠈ ▌} {▐ ⠂ ▌} {▐ ⠠ ▌} {▐ ⡀ ▌} {▐ ⠠ ▌} {▐ ⠂ ▌} {▐ ⠈ ▌} {▐ ⠂ ▌} {▐ ⠠ ▌} {▐ ⡀ ▌} {▐ ⠠ ▌} {▐ ⠂ ▌} {▐ ⠈ ▌} {▐ ⠂▌} {▐ ⠠▌} {▐ ⡀▌} {▐ ⠠ ▌} {▐ ⠂ ▌} {▐ ⠈ ▌} {▐ ⠂ ▌} {▐ ⠠ ▌} {▐ ⡀ ▌} {▐ ⠠ ▌} {▐ ⠂ ▌} {▐ ⠈ ▌} {▐ ⠂ ▌} {▐ ⠠ ▌} {▐ ⡀ ▌} {▐⠠ ▌} }}
shark { 120 { {▐|\____________▌} {▐_|\___________▌} {▐__|\__________▌} {▐___|\_________▌} {▐____|\________▌} {▐_____|\_______▌} {▐______|\______▌} {▐_______|\_____▌} {▐________|\____▌} {▐_________|\___▌} {▐__________|\__▌} {▐___________|\_▌} {▐____________|\▌} ▐____________/|▌ ▐___________/|_▌ ▐__________/|__▌ ▐_________/|___▌ ▐________/|____▌ ▐_______/|_____▌ ▐______/|______▌ ▐_____/|_______▌ ▐____/|________▌ ▐___/|_________▌ ▐__/|__________▌ ▐_/|___________▌ ▐/|____________▌ }}
dqpb { 100 { d q p b }}
grenade { 80 { {، } {′ } { ´ } { ‾ } { ⸌} { ⸊} { |} { ⁎} { ⁕} { ෴ } { ⁓} { } { } { } }}
point { 125 { ∙∙∙ ●∙∙ ∙●∙ ∙∙● ∙∙∙ }}
layer { 150 { - = ≡ }}
betaWave { 80 { ρββββββ βρβββββ ββρββββ βββρβββ ββββρββ βββββρβ ββββββρ }}
}
}
proc ::Spinner::Info {{spinnerName :random:}} {
# Returns info about a spinner, or a random one if name ":random:" is given
variable SPINNERS
if {$spinnerName eq ":random:"} {
set names [array names SPINNERS]
set n [expr {int(rand() * [llength $names])}]
set spinnerName [lindex $names $n]
}
lassign $SPINNERS($spinnerName) interval frames
set maxWidth [::tcl::mathfunc::max {*}[lmap f $frames {string length $f}]]
return [list $spinnerName $interval $frames $maxWidth]
}
proc ::Spinner::Start {name widget_or_textvar} {
variable SPINNERS
variable NextID
variable ACTIVE
set id [incr NextID]
if {[info commands winfo] ne "" && [winfo exists $widget_or_textvar]} {
set textvar [$widget_or_textvar cget -textvar]
} else {
set textvar $widget_or_textvar
}
set ACTIVE($id) go
::Spinner::_Go $id $textvar $name 0
return $id
}
proc ::Spinner::Stop {{id ""}} {
# Stop a single banner or multiple banners
variable ACTIVE
if {$id eq ""} {
array unset ACTIVE
} else {
array unset ACTIVE $id
}
}
proc ::Spinner::_Go {id textvar spinnerName idx} {
# Internal routine to update spinner $id
variable ACTIVE
variable SPINNERS
if {! [info exists ACTIVE($id)]} return
lassign $SPINNERS($spinnerName) interval frames
set $textvar [lindex $frames $idx]
set idx [expr {($idx + 1) % [llength $frames]}]
after $interval [list ::Spinner::_Go $id $textvar $spinnerName $idx]
}
################################################################
################################################################
#
# Demo code
#
package require Tk
proc DoDisplay {} {
wm title . "Spinner Demo"
set font {Helvetica 36}
set fontBold {Courier 36 bold}
set numColumns 3
set widgets {}
set row -1
set names [lsort -dictionary [array names ::Spinner::SPINNERS]]
set n [lsearch $names "shark"]
set names [concat [lreplace $names $n $n] shark]
foreach spinnerName $names {
incr row
label .title$row -text $spinnerName -font $font
label .spin$row -textvar ::spinner($row) -font $fontBold \
-width 10 -bd 2 -relief solid
::Spinner::Start $spinnerName .spin$row
lassign [::Spinner::Info $spinnerName] . . . maxWidth
lappend widths $maxWidth
lappend widgets .title$row .spin$row
if {[llength $widgets] >= 2*$numColumns} {
grid {*}$widgets
set widgets {}
}
}
if {$widgets ne {}} {
grid {*}$widgets
}
# The shark spinner needs extra space
grid config .spin$row -columnspan 2 -sticky w
.spin$row config -width 16
}
DoDisplay
return
======
----
'''[arjen] - 2019-10-02 07:20:23'''
Very nice! Two remarks though: when I ran it on my laptop, the window was larger than the screen and the font did not have all the glyphs, it seems as some spinners only showed a single question mark.
----
'''[arjen] - 2019-10-02 07:22:03'''
Hm, looking at the source code as I saved it, it might be due to the way I saved the code (copy-paste) - a lot of the characters are simply question marks.
----[GS] - '''20230203''' - Added 32 throbbers [https://en.wikipedia.org/wiki/Throbber].
arrow4 {140 {{⬈ } {➞ } {⬊ } {⬋ } {⬅ } {⬉ }}} clock {140 {%F0%9F%95%9B %F0%9F%95%A7 %F0%9F%95%90 %F0%9F%95%9C %F0%9F%95%91 %F0%9F%95%9D %F0%9F%95%92 %F0%9F%95%9E %F0%9F%95%93 %F0%9F%95%9F %F0%9F%95%94 %F0%9F%95%A0 %F0%9F%95%95 %F0%9F%95%96 %F0%9F%95%97 %F0%9F%95%98 %F0%9F%95%99 %F0%9F%95%9A %F0%9F%95%A1 %F0%9F%95%A2 %F0%9F%95%A3 %F0%9F%95%A4 %F0%9F%95%A5 %F0%9F%95%A6}}
bird {140 {︷ ︵ ︹ ︺ ︶ ︸ ︶ ︺ ︹ ︵}}