Animation

From Rosetta Code

Jump to: navigation, search
Task
Animation
You are encouraged to solve this task according to the task description, using any language you may know.
Animation is the foundation of a great many parts of graphical user interfaces, including both the fancy effects when things change used in window managers, and of course games. The core of any animation system is a scheme for periodically changing the display while still remaining responsive to the user. This task demonstrates this.

Create a window containing the string "Hello World! " (the trailing space is significant). Make the text appear to be rotating right by periodically removing one letter from the end of the string and attaching it to the front. When the user clicks on the text, it should reverse its direction.

Contents

[edit] ActionScript

//create the text box
var textBox:TextField = new TextField();
addChild(textBox);
 
var text = "Hello, World! ";
var goingRight = true;
 
//modify the string and update it in the text box
function animate(e:Event)
{
if(goingRight)
text = text.slice(text.length-1,text.length) + text.slice(0, text.length - 1);
else
text = text.slice(1) + text.slice(0,1);
textBox.text = text;
}
 
//event handler to perform the animation
textBox.addEventListener(Event.ENTER_FRAME, animate);
//event handler to register clicks
textBox.addEventListener(MouseEvent.MOUSE_DOWN, function(){goingRight = !goingRight;});
 

[edit] AutoHotkey

  message := "Hello World! "
Gui, Add, Text, vmyedit , %message%
Gui, +AlwaysOnTop +Disabled -SysMenu +Owner
Gui, Show
animate()
Return ; end of auto-execute section
 
#IfWinActive animation.ahk
~LButton::
WinGetPos ,,, width, height
MouseGetPos, x, y
If x And y
If (x < width) And (y < height)
reverse := !reverse
Return
#IfWinActive
 
animate()
{
Global
Loop,
{
Sleep, 200
If reverse
message := SubStr(message, 2, StrLen(message)) . SubStr(message,1, 1)
Else
message := SubStr(message, StrLen(message), 1) . SubStr(message, 1, StrLen(message) - 1)
GuiControl,,myedit, %message%
}
}

[edit] C

Library: GTK (NB: implicitly, through GTK, it uses also Pango library)

#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>
 
const gchar *hello = "Hello World! ";
gint direction = -1;
gint cx=0;
gint slen=0;
 
GtkLabel *label;
 
void change_dir(GtkLayout *o, gpointer d)
{
direction = -direction;
}
 
gchar *rotateby(const gchar *t, gint q, gint l)
{
gint i, cl = l, j;
gchar *r = malloc(l+1);
for(i=q, j=0; cl > 0; cl--, i = (i + 1)%l, j++)
r[j] = t[i];
r[l] = 0;
return r;
}
 
gboolean scroll_it(gpointer data)
{
if ( direction > 0 )
cx = (cx + 1) % slen;
else
cx = (cx + slen - 1 ) % slen;
gchar *scrolled = rotateby(hello, cx, slen);
gtk_label_set_text(label, scrolled);
free(scrolled);
return TRUE;
}
 
 
int main(int argc, char **argv)
{
GtkWidget *win;
GtkButton *button;
PangoFontDescription *pd;
 
gtk_init(&argc, &argv);
win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(win), "Basic Animation");
g_signal_connect(G_OBJECT(win), "delete-event", gtk_main_quit, NULL);
 
label = (GtkLabel *)gtk_label_new(hello);
 
// since we shift a whole character per time, it's better to use
// a monospace font, so that the shifting seems done at the same pace
pd = pango_font_description_new();
pango_font_description_set_family(pd, "monospace");
gtk_widget_modify_font(GTK_WIDGET(label), pd);
 
button = (GtkButton *)gtk_button_new();
gtk_container_add(GTK_CONTAINER(button), GTK_WIDGET(label));
 
gtk_container_add(GTK_CONTAINER(win), GTK_WIDGET(button));
g_signal_connect(G_OBJECT(button), "clicked", G_CALLBACK(change_dir), NULL);
 
slen = strlen(hello);
 
g_timeout_add(125, scroll_it, NULL);
 
gtk_widget_show_all(GTK_WIDGET(win));
gtk_main();
return 0;
}

[edit] C#

using System;
using System.Drawing;
using System.Windows.Forms;
 
namespace BasicAnimation
{
class BasicAnimationForm : Form
{
bool isReverseDirection;
Label textLabel;
Timer timer;
 
internal BasicAnimationForm()
{
this.Size = new Size(150, 75);
this.Text = "Basic Animation";
 
textLabel = new Label();
textLabel.Text = "Hello World! ";
textLabel.Location = new Point(3,3);
textLabel.AutoSize = true;
textLabel.Click += new EventHandler(textLabel_OnClick);
this.Controls.Add(textLabel);
 
timer = new Timer();
timer.Interval = 500;
timer.Tick += new EventHandler(timer_OnTick);
timer.Enabled = true;
 
isReverseDirection = false;
}
 
private void timer_OnTick(object sender, EventArgs e)
{
string oldText = textLabel.Text, newText;
if(isReverseDirection)
newText = oldText.Substring(1, oldText.Length - 1) + oldText.Substring(0, 1);
else
newText = oldText.Substring(oldText.Length - 1, 1) + oldText.Substring(0, oldText.Length - 1);
textLabel.Text = newText;
}
 
private void textLabel_OnClick(object sender, EventArgs e)
{
isReverseDirection = !isReverseDirection;
}
}
 
class Program
{
static void Main()
{
Application.Run(new BasicAnimationForm());
}
}
}

[edit] Clojure

Clojure is a JVM language so this example uses Swing, and illustrates Clojure's platform integration.

(import '[javax.swing JFrame JLabel])
(import '[java.awt.event MouseAdapter])
 
(def text "Hello World! ")
(def text-ct (count text))
(def rotations
(vec
(take text-ct
(map #(apply str %)
(partition text-ct 1 (cycle text))))))
 
(def pos (atom 0)) ;position in rotations vector being displayed
(def dir (atom 1)) ;direction of next position (-1 or 1)
 
(def label (JLabel. text))
 
(.addMouseListener label
(proxy [MouseAdapter] []
(mouseClicked [evt] (swap! dir -))))
 
(defn animator []
(while true
(Thread/sleep 100)
(swap! pos #(-> % (+ @dir) (mod text-ct)))
(.setText label (rotations @pos))))
 
(doto (JFrame.)
(.add label)
(.pack)
(.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)
(.setVisible true))
 
(future-call animator) ;simple way to run animator on a separate thread

[edit] Common Lisp

The ltk package provides a lisp interface to Tk for creating graphical interfaces. Assuming ltk has been installed somewhere the following will work as per the Tcl example. Library: Tk

(use-package :ltk)
 
(defparameter *message* "Hello World! ")
(defparameter *direction* :left)
(defun animate (label)
(let* ((n (length *message*))
(i (if (eq *direction* :left) 0 (1- n)))
(c (string (char *message* i))))
(if (eq *direction* :left)
(setq *message* (concatenate 'string (substring *message* 1 n) (list c)))
(setq *message* (concatenate 'string (list c) (substring *message* 0 (1- n)))))
(setf (ltk:text label) *message*)
(ltk:after 125 (lambda () (animate label)))))
 
(defun basic-animation ()
(ltk:with-ltk ()
(let* ((label (make-instance 'label
:font "Courier 14")))
(setf (text label) *message*)
(ltk:bind label "<Button-1>"
(lambda (event)
(declare (ignore event))
(cond
((eq *direction* :left) (setq *direction* :right))
((eq *direction* :right) (setq *direction* :left)))))
(ltk:pack label)
(animate label)
(ltk:mainloop))))
 
(basic-animation)

[edit] D

Library: QD uses Library: SDL Library: SDL_ttf Library: tools

module test26;
 
import qd, SDL_ttf, tools.time;
 
void main() {
screen(320, 200);
auto last = sec();
string text = "Hello World! ";
auto speed = 0.2;
int dir = true;
while (true) {
cls;
print(10, 10, Bottom|Right, text);
if (sec() - last > speed) {
last = sec();
if (dir == 0) text = text[$-1] ~ text[0 .. $-1];
else text = text[1 .. $] ~ text[0];
}
flip; events;
if (mouse.clicked
&& mouse.pos in display.select(10, 10, 100, 20)
) dir = !dir;
}
}

[edit] E

Works with: E-on-Java (Java Swing; tested on Mac OS X 10.5.7)

# State
var text := "Hello World! "
var leftward := false
 
# Window
def w := <swing:makeJFrame>("RC: Basic Animation")
 
# Text in window
w.setContentPane(def l := <swing:makeJLabel>(text))
l.setOpaque(true) # repaints badly if not set!
l.addMouseListener(def mouseListener {
to mouseClicked(_) {
leftward := !leftward
}
match _ {}
})
 
# Animation
def anim := timer.every(100, fn _ { # milliseconds
def s := text.size()
l.setText(text := if (leftward) {
text(1, s) + text(0, 1)
} else {
text(s - 1, s) + text(0, s - 1)
})
})
 
# Set up window shape and close behavior
w.pack()
w.setLocationRelativeTo(null)
w.addWindowListener(def windowListener {
to windowClosing(_) { anim.stop() }
match _ {}
})
 
# Start everything
w.show()
anim.start()

Text-only version (no Java dependency; no clicking, use reverse() and stop() to control):

def [reverse, stop] := {
var text := "Hello World! "
var leftward := false
 
def anim := timer.every(100, fn _ { # milliseconds
def s := text.size()
text := if (leftward) {
text(1, s) + text(0, 1)
} else {
text(s - 1, s) + text(0, s - 1)
}
print("\b" * s, text)
})
print("\n", text)
anim.start()
[def _() { leftward := !leftward; null }, anim.stop]
}

[edit] F#

Library: Windows Presentation Foundation

open System.Windows
 
let str = "Hello world! "
let mutable i = 0
let mutable d = 1
 
[<System.STAThread>]
do
let button = Controls.Button()
button.Click.Add(fun _ -> d <- str.Length - d)
let update _ =
i <- (i + d) % str.Length
button.Content <- str.[i..] + str.[..i-1]
Media.CompositionTarget.Rendering.Add update
(Application()).Run(Window(Content=button)) |> ignore

[edit] Factor

USING: accessors alarms calendar kernel models sequences ui
ui.gadgets ui.gadgets.labels ui.gestures ;
FROM: models => change-model ;
IN: rosetta.animation
 
CONSTANT: sentence "Hello World! "
 
TUPLE: animated-label < label-control reversed alarm ;
: <animated-label> ( model -- <animated-model> )
sentence animated-label new-label swap >>model
monospace-font >>font ;
: update-string ( str reverse -- str )
[ unclip-last prefix ] [ unclip suffix ] if ;
: update-model ( model reversed? -- )
[ update-string ] curry change-model ;
 
animated-label
H{
{ T{ button-down } [ [ not ] change-reversed drop ] }
} set-gestures
 
M: animated-label graft*
[ [ [ model>> ] [ reversed>> ] bi update-model ] curry 400 milliseconds every ] keep
(>>alarm) ;
M: animated-label ungraft*
alarm>> cancel-alarm ;
: main ( -- )
[ sentence <model> <animated-label> "Rosetta" open-window ] with-ui ;
 
MAIN: main

[edit] Haskell

Using simple graphics Library: HGL from HackageDB

import Graphics.HGL.Units (Time, Point, Size, )
import Graphics.HGL.Draw.Monad (Graphic, )
import Graphics.HGL.Draw.Text
import Graphics.HGL.Draw.Font
import Graphics.HGL.Window
import Graphics.HGL.Run
import Graphics.HGL.Utils
 
import Control.Exception (bracket, )
 
runAnim = runGraphics $
bracket
(openWindowEx "Basic animation task" Nothing (250,50) DoubleBuffered (Just 110))
closeWindow
(\w -> do
f <- createFont (64,28) 0 False False "courier"
let loop t dir = do
e <- maybeGetWindowEvent w
let d = case e of
Just (Button _ True False) -> -dir
_ -> dir
t' = if d == 1 then last t : init t else tail t ++ [head t]
setGraphic w (withFont f $ text (5,10) t') >> getWindowTick w
loop t' d
 
loop "Hello world ! " 1 )

Run within interpreter GHCi:

*Main> runAnim

[edit] HicEst

CHARACTER string="Hello World! "
 
WINDOW(WINdowhandle=wh, Height=1, X=1, TItle="left/right click to rotate left/right, Y-click-position sets milliseconds period")
AXIS(WINdowhandle=wh, PoinT=20, X=2048, Y, Title='ms', MiN=0, MaX=400, MouSeY=msec, MouSeCall=Mouse_callback, MouSeButton=button_type)
direction = 4
msec = 100 ! initial milliseconds
DO tic = 1, 1E20
WRITE(WIN=wh, Align='Center Vertical') string
IF(direction == 4) string = string(LEN(string)) // string ! rotate left
IF(direction == 8) string = string(2:) // string(1) ! rotate right
WRITE(StatusBar, Name) tic, direction, msec
SYSTEM(WAIT=msec)
ENDDO
END
 
SUBROUTINE Mouse_callback()
direction = button_type ! 4 == left button up, 8 == right button up
END

[edit] J

coinsert'jgl2' [ require'gl2'   
 
MESSAGE =: 'Hello World! '
TIMER_INTERVAL =: 0.5 * 1000 NB. Milliseconds
DIRECTION =: 1 NB. Initial direction is right -->
 
ANIM =: noun define
pc anim nomax nosize;pn "Basic Animation in J";
xywh 1 1 174 24;cc isi isigraph rightmove bottommove;
pas 0 0;pcenter;pshow;
)
 
anim_run =: verb def ' wd ANIM,''; timer '',":TIMER_INTERVAL '
sys_timer_z_ =: verb def ' isiMsg MESSAGE=: DIRECTION |. MESSAGE ' NB. Rotate MESSAGE according to DIRECTION
anim_isi_mbldown =: verb def ' DIRECTION=: - DIRECTION ' NB. Reverse direction when user clicks
anim_close =: verb def ' wd ''timer 0; pclose; reset;'' ' NB. Shut down timer
 
isiMsg =: verb define
wd'psel anim'
glclear '' NB. Clear out old drawing
glfont '"courier new" 36'
gltext y
glpaint '' NB. Copy to screen
)
 
anim_run ''

[edit] Java

Library: Swing

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;
import javax.swing.JLabel;
 
public class Rotate extends JFrame {
String text = "Hello World! ";
JLabel label = new JLabel(text);
boolean rotRight = true;
int startIdx = 0;
 
public Rotate() {
label.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent evt) {
rotRight = !rotRight;
}
});
add(label);
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
 
public static void main(String[] args) {
final Rotate rot = new Rotate();
TimerTask task = new TimerTask() {
public void run() {
if (rot.rotRight) {
rot.startIdx++;
if (rot.startIdx >= rot.text.length()) {
rot.startIdx -= rot.text.length();
}
} else {
rot.startIdx--;
if (rot.startIdx < 0) {
rot.startIdx += rot.text.length();
}
}
rot.label.setText(getRotatedText(rot.text, rot.startIdx));
}
};
Timer timer = new Timer(false);
timer.schedule(task, 0, 500);
}
 
public static String getRotatedText(String text, int startIdx) {
String ret = "";
int i = startIdx;
do {
ret += text.charAt(i) + "";
i++;
i = i % text.length();
} while (i != startIdx);
return ret;
}
}

[edit] JavaScript + HTML

<html> <head>
<title>RC: Basic Animation</title>
<script type="text/javascript">
function animate(id) {
var element = document.getElementById(id);
var textNode = element.childNodes[0]; // assuming no other children
 
var text = textNode.data;
var reverse = false;
 
element.onclick = function () { reverse = !reverse; };
 
setInterval(function () {
if (reverse)
text = text.substring(1) + text[0];
else
text = text[text.length - 1] + text.substring(0, text.length - 1);
textNode.data = text;
}, 100);
}
</script>
</head> <body onload="animate('target')">
<pre id="target">Hello World! </pre>
</body> </html>

[edit] JavaScript + SVG

<svg xmlns="http://www.w3.org/2000/svg"
width="100" height="40">
<script type="text/javascript">
function animate(element) {
var textNode = element.childNodes[0]; // assuming no other children
var text = textNode.data;
var reverse = false;
 
element.onclick = function () { reverse = !reverse; };
 
setInterval(function () {
if (reverse)
text = text.substring(1) + text[0];
else
text = text[text.length - 1] + text.substring(0, text.length - 1);
textNode.data = text;
}, 100);
}
</script>
 
<rect width="100" height="40" fill="yellow"/>
<text x="2" y="20" onload="animate(this);">Hello World! </text>
</svg>

[edit] Liberty BASIC

    txt$ = "Hello World! "
txtLength = len(txt$)
direction=1
 
NoMainWin
 
open "Rosetta Task: Animation" for graphics_nsb as #demo
#demo "Trapclose [quit]"
#demo "down"
#demo "Font Verdana 20 Bold"
#demo "When leftButtonUp [changedirection]"
 
timer 150 , [draw]
wait
 
[draw]
if direction then
txt$ = right$(txt$, 1);left$(txt$, txtLength - 1)
else
txt$ = right$(txt$, txtLength - 1);left$(txt$, 1)
end if
#demo "discard"
#demo "place 50 100"
#demo "\";txt$
wait
 
[changedirection]
direction = not(direction)
wait
 
[quit]
timer 0
close #demo
end

[edit] Logo

Works with: UCB Logo

to rotate.left :thing
output lput first :thing butfirst :thing
end
to rotate.right :thing
output fput last :thing butlast :thing
end
 
make "text "|Hello World! |
make "right? "true
 
to step.animation
label :text ; graphical
 ; type char 13 type :text ; textual
wait 6 ; 1/10 second
if button <> 0 [make "right? not :right?]
make "text ifelse :right? [rotate.right :text] [rotate.left :text]
end
 
hideturtle
until [key?] [step.animation]

[edit] Mathematica

mystring = "Hello World! ";
Scroll[str_, dir_] := StringJoin @@ RotateLeft[str // Characters, dir];
GiveString[dir_] := (mystring = Scroll[mystring, dir]);
CreateDialog[{
DynamicModule[{direction = -1},
EventHandler[
Dynamic[TextCell[
Refresh[GiveString[direction], UpdateInterval -> 1/8]],
TrackedSymbols -> {}], {"MouseClicked" :> (direction *= -1)}]]
}];

[edit] Oz

functor
import
Application
QTk at 'x-oz://system/wp/QTk.ozf'
define
proc {Start}
Label
Window = {CreateWindow ?Label}
Animation = {New LabelAnimation init(Label delay:125)}
in
{Window show}
{Animation go}
end
 
fun {CreateWindow ?Label}
Courier = {QTk.newFont font(family:courier size:14)}
GUI = td(
title:"Basic Animation"
label(text:"Hello World! " handle:Label font:Courier)
action:proc {$} {Application.exit 0} end
)
in
{QTk.build GUI}
end
 
class LabelAnimation from Time.repeat
attr
activeShifter:ShiftRight
otherShifter:ShiftLeft
feat
label
 
meth init(Label delay:Delay<=100)
self.label = Label
{self setRepAll(action:Animate delay:Delay)}
{Label bind(event:"<Button-1>" action:self#Revert)}
end
 
meth Animate
OldText = {self.label get(text:$)}
NewText = {@activeShifter OldText}
in
{self.label set(text:NewText)}
end
 
meth Revert
otherShifter := (activeShifter := @otherShifter)
end
end
 
fun {ShiftRight Xs}
{List.last Xs}|{List.take Xs {Length Xs}-1}
end
 
fun {ShiftLeft Xs}
{Append Xs.2 [Xs.1]}
end
 
{Start}
end

[edit] Perl

Library: XUL::GuiGui

use XUL::Gui;
 
my $dir = '(.+)(.)';
interval {
ID(lbl)->value =~ s/$dir/$2$1/;
} 75;
 
display Label
id => 'lbl',
value => "Hello World! ",
onclick => sub {toggle $dir => '(.+)(.)', '(.)(.+)'};

[edit] PureBasic

OpenWindow(0,0,0,500,100,"Hello World!",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
 
text$ = "Hello World! "
direction = 1
 
LoadFont(0,"",60)
ButtonGadget(0,2,2,496,96,text$) : SetGadgetFont(0,FontID(0))
 
Repeat
event = WaitWindowEvent(50)
Select event
Case #PB_Event_Gadget
If EventGadget() = 0
direction*-1
EndIf
Case #PB_Event_CloseWindow
End
EndSelect
 
If ElapsedMilliseconds()-tick > 400
offset+direction
If offset > Len(text$)-1
offset = 0
ElseIf offset < 0
offset = Len(text$)-1
EndIf
SetGadgetText(0,Mid(text$,offset+1)+Left(text$,offset))
tick = ElapsedMilliseconds()
EndIf
ForEver

[edit] Python

Library: pygame

import pygame, sys
from pygame.locals import *
pygame.init()
 
YSIZE = 40
XSIZE = 150
 
TEXT = "Hello World! "
FONTSIZE = 32
 
LEFT = False
RIGHT = True
 
DIR = RIGHT
 
TIMETICK = 180
TICK = USEREVENT + 2
 
TEXTBOX = pygame.Rect(10,10,XSIZE,YSIZE)
 
pygame.time.set_timer(TICK, TIMETICK)
 
window = pygame.display.set_mode((XSIZE, YSIZE))
pygame.display.set_caption("Animation")
 
font = pygame.font.SysFont(None, FONTSIZE)
screen = pygame.display.get_surface()
 
def rotate():
index = DIR and -1 or 1
global TEXT
TEXT = TEXT[index:]+TEXT[:index]
 
def click(position):
if TEXTBOX.collidepoint(position):
global DIR
DIR = not DIR
 
def draw():
surface = font.render(TEXT, True, (255,255,255), (0,0,0))
global TEXTBOX
TEXTBOX = screen.blit(surface, TEXTBOX)
 
def input(event):
if event.type == QUIT:
sys.exit(0)
elif event.type == MOUSEBUTTONDOWN:
click(event.pos)
elif event.type == TICK:
draw()
rotate()
 
while True:
input(pygame.event.wait())
pygame.display.flip()

[edit] R

Library: gWidgets

The basic principle is:create a window with a label in it, then add a handler to the label for rotating the string, and another for changing direction on a click. Use of the tag function allows you to store the text flow direction as an attribute of the label.

 
rotate_string <- function(x, forwards)
{
   nchx <- nchar(x)
   if(forwards)
   {                                  
      paste(substr(x, nchx, nchx), substr(x, 1, nchx - 1), sep = "")
   } else
   {                                                          
      paste(substr(x, 2, nchx), substr(x, 1, 1), sep = "")
   }
}
 
handle_rotate_label <- function(obj, interval = 100)
{
  addHandlerIdle(obj,
    handler = function(h, ...)
    {
       svalue(obj) <- rotate_string(svalue(obj), tag(obj, "forwards"))
    },
    interval = interval
  )
}
 
handle_change_direction_on_click <- function(obj)
{
  addHandlerClicked(obj,
    handler = function(h, ...)
    {
      tag(h$obj, "forwards") <- !tag(h$obj, "forwards")
    }
  )
}
 
library(gWidgets)
library(gWidgetstcltk) #or library(gWidgetsRGtk2) or library(gWidgetsrJava)             
lab <- glabel("Hello World! ", container = gwindow())  
tag(lab, "forwards") <- TRUE
handle_rotate_label(lab)
handle_change_direction_on_click(lab)
 

[edit] REBOL

rebol [
Title: "Basic Animation"
Author: oofoe
Date: 2009-12-06
URL: http://rosettacode.org/wiki/Basic_Animation
]

 
message: "Hello World! " how: 1
 
roll: func [
"Shifts a text string right or left by one character."
text [string!] "Text to shift."
direction [integer!] "Direction to shift -- right: 1, left: -1."
/local h t
][
either direction > 0 [
h: last text t: copy/part text ((length? text) - 1)
][
h: copy skip text 1 t: text/1
]
rejoin [h t]
]
 
; This next bit specifies the GUI panel. The window will have a
; gradient backdrop, over which will be composited the text, in a
; monospaced font with a drop-shadow. A timer (the 'rate' bit) is set
; to update 24 times per second. The 'engage' function in the 'feel'
; block listens for events on the text face. Time events update the
; animation and mouse-down change the animation's direction.
 
view layout [
backdrop effect [gradient 0x1 coal black]
 
vh1 as-is message ; 'as-is' prevents text trimming.
font [name: font-fixed]
rate 24
feel [
engage: func [f a e] [
case [
'time = a [set-face f message: roll message how] ; Animate.
'down = a [how: how * -1] ; Change direction.
]
]
]
]

[edit] Ruby

Translation of: Tcl Library: Ruby/Tk

require 'tk'
$str = TkVariable.new("Hello World! ")
$dir = :right
 
def animate
$str.value = shift_char($str.value, $dir)
$root.after(125) {animate}
end
 
def shift_char(str, dir)
case dir
when :right then str[-1,1] + str[0..-2]
when :left then str[1..-1] + str[0,1]
end
end
 
$root = TkRoot.new("title" => "Basic Animation")
 
TkLabel.new($root) do
textvariable $str
font "Courier 14"
pack {side 'top'}
bind("ButtonPress-1") {$dir = {:right=>:left,:left=>:right}[$dir]}
end
 
animate
Tk.mainloop

[edit] Scala

Works with: Scala version 2.8

import scala.actors.Actor.{actor, loop, reactWithin, exit}
import scala.actors.TIMEOUT
import scala.swing.{SimpleSwingApplication, MainFrame, Label}
import scala.swing.event.MouseClicked
 
case object Revert
 
object BasicAnimation extends SimpleSwingApplication {
val label = new Label("Hello World! ")
val rotator = actor {
var goingRight = true
loop {
reactWithin(250 /*ms*/) {
case Revert => goingRight = !goingRight
case TIMEOUT =>
if (goingRight)
label.text = label.text.last + label.text.init
else
label.text = label.text.tail + label.text.head
case unknown => println("Unknown message "+unknown); exit()
}
}
}
def top = new MainFrame {
title = "Basic Animation"
contents = label
}
listenTo(label.mouse.clicks) // use "Mouse" instead of "mouse" on Scala 2.7
reactions += {
case _ : MouseClicked => rotator ! Revert
}
}

[edit] Suneido

Window(Controller
{
Xmin: 50
Ymin: 50
New()
{
super(.layout())
.txt = .FindControl('text')
.moveTimer = SetTimer(NULL, 0, 600, .moveTimerFunc)
}
direction: -1
moveTimer: false
layout()
{
return #(Vert (Static 'Hello World! ', size: 12, weight: 600,
notify:, name: 'text'))
}
moveTimerFunc(@unused)
{
str = .txt.Get()
.txt.Set(str.Substr(1 * .direction) $ str.Substr(0, (1 * .direction)))
}
Static_Click()
{
.direction = .direction * -1
}
Destroy()
{
if .moveTimer isnt false
{
KillTimer(NULL, .moveTimer)
ClearCallback(.moveTimerFunc)
}
super.Destroy()
}
})

[edit] SVG (no scripts)

Works with: Batik version 1.7

This animation is defined as a smooth movement rather than by moving whole characters, because that is more natural in SVG (without scripting); by characters would require 13 different text elements displayed in sequence.

<svg xmlns="http://www.w3.org/2000/svg" width="100" height="30">
<g id="all">
<rect width="100%" height="100%" fill="yellow"/>
<g style="font: 18 'Times New Roman', serif;
fill: black;
stroke: white; stroke-width: 0.001; /* workaround for Batik oddity */ ">

<text x="0" y="20" textLength="95">Hello World!</text>
<text x="-100" y="20" textLength="95">Hello World!</text>
<animateMotion restart="whenNotActive" repeatCount="indefinite" dur="2s"
begin="0s;all.click" end="all.click"
from="0,0" by="100,0"/>
<animateMotion restart="whenNotActive" repeatCount="indefinite" dur="2s"
begin="all.click" end="all.click"
from="100,0" by="-100,0"/>
</g>
</g>
</svg>

(Does not work in Safari 4.0.2 because it apparently does not implement toggled animations correctly (see spec). Dreadful workaround: set the two animations to id="a" begin="0s;all.click" end="all.mousedown" and begin="a.end" end="all.click", respectively.)

[edit] Tcl

Library: Tk

package require Tk
set s "Hello World! "
set dir 0
# Periodic animation callback
proc animate {} {
global dir s
if {$dir} {
set s [string range $s 1 end][string index $s 0]
} else {
set s [string index $s end][string range $s 0 end-1]
}
# We will run this code ~8 times a second (== 125ms delay)
after 125 animate
}
# Make the label (constant width font looks better)
pack [label .l -textvariable s -font {Courier 14}]
# Make a mouse click reverse the direction
bind .l <Button-1> {set dir [expr {!$dir}]}
# Start the animation
animate

[edit] TI-89 BASIC

The requirements contain "When the user clicks on the text…". The TI-89 does not have a graphical cursor, so just for the sake of overdoing it, and to have a little more complex animation (overlapping objects), this program implements one. Use the arrow keys and ENTER to control the cursor.

rcanimat()
Prgm
  Local leftward,s,i,k,x,y

  false → leftward
  "Hello World! " → s
  0 → k      © last keypress found
  6*3 → x    © cursor position
  5 → y

  ClrIO
  While k ≠ 4360 and k ≠ 277 and k ≠ 264  © QUIT,HOME,ESC keys

    © Handle Enter key
    If k = 13 Then
      If x ≥ 40 and x < 40+6*dim(s) and y ≥ 25 and y < 35 Then © On text?
        not leftward → leftward
      ElseIf x ≥ 5 and x < 5+6*dim("[Quit]") and y ≥ 55 and y < 65 Then © On quit?
        Exit
      EndIf
    EndIf

    © Cursor movement keys
    If k=338 or k=340 or k=344 or k=337 or k=339 or k=342 or k=345 or k=348 Then
      Output y, x, " " © Blank old cursor pos
      If     k = 338 or k = 339 or k = 342 Then: y-6→y
      ElseIf k = 344 or k = 345 or k = 348 Then: y+6→y :EndIf
      If     k = 337 or k = 339 or k = 345 Then: x-6→x
      ElseIf k = 340 or k = 342 or k = 348 Then: x+6→x :EndIf
      min(max(y, 0), 64)→y
      min(max(x, 0), 152)→x
    EndIf

    © Drawing
    Output 0, 0, "Use arrows, ENTER key"
    Output 60, 5, "[Quit]"
    Output 30, 40, s
    Output y, x, "Ŵ"              © should be diamond symbol

    © Animation
    If leftward Then
      right(s, dim(s)-1) & left(s, 1) → s
    Else
      right(s, 1) & left(s, dim(s)-1) → s
    EndIf

    0 → i
    getKey() → k                  © reads most recent keypress or 0
    While i < 2 and k = 0         © Delay loop. Better solution?
      getKey() → k
      i + 1 → i
    EndWhile

  EndWhile
  DispHome
EndPrgm
Personal tools
Support