⚠️ Warning: This is a draft ⚠️
This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.
If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.
{{task|Temporal media}} [[Category:GUI]] {{requires|Graphics}}
'''Animation''' is integral to many parts of [[GUI]]s, 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.
;Task:
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 (windowed) text, it should reverse its direction.
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;});
Ada
{{works with|GNAT}} {{libheader|GtkAda}}
animation.adb:
with Gtk.Main;
with Gtk.Handlers;
with Gtk.Label;
with Gtk.Button;
with Gtk.Window;
with Glib.Main;
procedure Animation is
Scroll_Forwards : Boolean := True;
package Button_Callbacks is new Gtk.Handlers.Callback
(Gtk.Button.Gtk_Button_Record);
package Label_Timeout is new Glib.Main.Generic_Sources
(Gtk.Label.Gtk_Label);
package Window_Callbacks is new Gtk.Handlers.Return_Callback
(Gtk.Window.Gtk_Window_Record, Boolean);
-- Callback for click event
procedure On_Button_Click
(Object : access Gtk.Button.Gtk_Button_Record'Class);
-- Callback for delete event
function On_Main_Window_Delete
(Object : access Gtk.Window.Gtk_Window_Record'Class)
return Boolean;
function Scroll_Text (Data : Gtk.Label.Gtk_Label) return Boolean;
procedure On_Button_Click
(Object : access Gtk.Button.Gtk_Button_Record'Class)
is
pragma Unreferenced (Object);
begin
Scroll_Forwards := not Scroll_Forwards;
end On_Button_Click;
function On_Main_Window_Delete
(Object : access Gtk.Window.Gtk_Window_Record'Class)
return Boolean
is
pragma Unreferenced (Object);
begin
Gtk.Main.Main_Quit;
return True;
end On_Main_Window_Delete;
function Scroll_Text (Data : Gtk.Label.Gtk_Label) return Boolean is
Text : constant String := Gtk.Label.Get_Text (Data);
begin
if Scroll_Forwards then
Gtk.Label.Set_Text
(Label => Data,
Str => Text (Text'First + 1 .. Text'Last) & Text (Text'First));
else
Gtk.Label.Set_Text
(Label => Data,
Str => Text (Text'Last) & Text (Text'First .. Text'Last - 1));
end if;
return True;
end Scroll_Text;
Main_Window : Gtk.Window.Gtk_Window;
Text_Button : Gtk.Button.Gtk_Button;
Scrolling_Text : Gtk.Label.Gtk_Label;
Timeout_ID : Glib.Main.G_Source_Id;
pragma Unreferenced (Timeout_ID);
begin
Gtk.Main.Init;
Gtk.Window.Gtk_New (Window => Main_Window);
Gtk.Label.Gtk_New (Label => Scrolling_Text, Str => "Hello World! ");
Gtk.Button.Gtk_New (Button => Text_Button);
Gtk.Button.Add (Container => Text_Button, Widget => Scrolling_Text);
Button_Callbacks.Connect
(Widget => Text_Button,
Name => "clicked",
Marsh => Button_Callbacks.To_Marshaller (On_Button_Click'Access));
Timeout_ID :=
Label_Timeout.Timeout_Add
(Interval => 125,
Func => Scroll_Text'Access,
Data => Scrolling_Text);
Gtk.Window.Add (Container => Main_Window, Widget => Text_Button);
Window_Callbacks.Connect
(Widget => Main_Window,
Name => "delete_event",
Marsh => Window_Callbacks.To_Marshaller (On_Main_Window_Delete'Access));
Gtk.Window.Show_All (Widget => Main_Window);
Gtk.Main.Main;
end Animation;
AutoHotkey
SetTimer, Animate ; Timer runs every 250 ms.
String := "Hello World "
Gui, Add, Text, vS gRev, %String%
Gui, +AlwaysOnTop -SysMenu
Gui, Show
Return
Animate:
String := (!Reverse) ? (SubStr(String, 0) . Substr(String, 1, StrLen(String)-1)) : (SubStr(String, 2) . SubStr(String, 1, 1))
GuiControl,,S, %String%
return
Rev: ; Runs whenever user clicks on the text control
Reverse := !Reverse
return
BASIC256
str$="Hello, World! "
direction=0 #value of 0: to the right, 1: to the left.
tlx=10 #Top left x
tly=10 #Top left y
fastgraphics
font "Arial",20,100 #The Font configuration (Font face, size, weight)
main:
while clickb=0
if direction=0 then
str$=RIGHT(str$,1) + LEFT(str$,length(str$)-1)
else
str$=MID(str$,2,length(str$)-1)+LEFT(str$,1)
end if
refresh
clg
color red
text tlx,tly,str$
pause .1
end while
#Note: textheight() and textwidth() depends on the latest configuration of the FONT command.
if clickb=1 and clickx>=tlx and clickx<=tlx+textwidth(str$) and clicky>=tly and clicky<=tly+textheight() then
direction=NOT direction
end if
clickclear
goto main
BBC BASIC
{{works with|BBC BASIC for Windows}}
VDU 23,22,212;40;16,32,16,128
txt$ = "Hello World! "
direction% = TRUE
ON MOUSE direction% = NOT direction% : RETURN
OFF
REPEAT
CLS
PRINT txt$;
IF direction% THEN
txt$ = RIGHT$(txt$) + LEFT$(txt$)
ELSE
txt$ = MID$(txt$,2) + LEFT$(txt$,1)
ENDIF
WAIT 20
UNTIL FALSE
C
{{libheader|GTK}} (NB: implicitly, through GTK, it uses also Pango library)
#include <iostream>
#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;
}
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());
}
}
}
Ceylon
module.ceylon
native("jvm")
module animation "1.0.0" {
import java.desktop "8";
}
run.ceylon
import javax.swing {
JFrame,
JLabel,
Timer
}
import java.awt.event {
MouseAdapter,
MouseEvent,
ActionListener,
ActionEvent
}
shared void run() {
value initialText = "Hello World! ";
value label = JLabel(initialText);
variable value forward = true;
label.addMouseListener(object extends MouseAdapter() {
mouseClicked(MouseEvent? mouseEvent) =>
forward = !forward;
});
Timer(1k, object satisfies ActionListener {
shared actual void actionPerformed(ActionEvent? actionEvent) {
String left;
String right;
if(forward) {
left = label.text.last?.string else "?";
right = "".join(label.text.exceptLast);
} else {
left = label.text.rest;
right = label.text.first?.string else "?";
}
label.text = left + right;
}
}).start();
value frame = JFrame();
frame.defaultCloseOperation = JFrame.\iEXIT_ON_CLOSE;
frame.title = "Rosetta Code Animation Example";
frame.add(label);
frame.pack();
frame.visible = true;
}
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
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. {{libheader|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 (char *message* i)))
(if (eq *direction* :left)
(setq *message* (concatenate 'string
(subseq *message* 1 n)
(list c)))
(setq *message* (concatenate 'string (list c)
(subseq *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)
D
{{libheader|QD}} uses {{libheader|SDL}} {{libheader|SDL_ttf}} {{libheader|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;
}
}
Dart
import 'dart:html';
import 'dart:async';
const frameTime = const Duration(milliseconds: 100);
void main() {
String text = "Hello World! ";
bool rotateRight = true;
Element writeHere =
querySelector('#output'); // assumes you have a pre with that ID
writeHere.onClick.listen((event) => rotateRight = !rotateRight);
new Timer.periodic(frameTime, (_) {
text = changeText(text, rotateRight);
writeHere.text = text;
});
}
String changeText(extt, rotateRight) {
if (rotateRight) {
return extt.substring(extt.length - 1) + extt.substring(0, extt.length - 1);
} else {
return extt.substring(1) + extt.substring(0, 1);
}
}
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]
}
=={{header|F Sharp|F#}}== {{libheader|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
Factor
USING: accessors timers 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>> stop-timer ;
: main ( -- )
[ sentence <model> <animated-label> "Rosetta" open-window ] with-ui ;
MAIN: main
Fantom
using concurrent
using fwt
using gfx
const class RotateString : Actor
{
new make (Label label) : super (ActorPool ())
{
Actor.locals["rotate-label"] = label
Actor.locals["rotate-string"] = label.text
Actor.locals["direction"] = "forward"
sendLater (1sec, "update")
}
// responsible for calling appropriate methods to process each message
override Obj? receive (Obj? msg)
{
switch (msg)
{
case "update":
Desktop.callAsync |->| { update } // make sure we update GUI in event thread
sendLater (1sec, "update")
case "reverse":
Desktop.callAsync |->| { reverse }
}
return null
}
// change the stored string indicating the direction to rotate
Void reverse ()
{
Actor.locals["direction"] =
(Actor.locals["direction"] == "forward" ? "backward" : "forward")
}
// update the text on the label according to the stored direction
Void update ()
{
label := Actor.locals["rotate-label"] as Label
str := Actor.locals["rotate-string"] as Str
if (label != null)
{
newStr := ""
if (Actor.locals["direction"] == "forward")
newStr = str[1..-1] + str[0].toChar
else
newStr = str[-1].toChar + str[0..<-1]
label.text = newStr
Actor.locals["rotate-string"] = newStr
}
}
}
class Animate
{
public static Void main ()
{
label := Label
{
text = "Hello world! "
halign = Halign.center
}
ticker := RotateString (label)
label.onMouseDown.add |Event e|
{
ticker.send ("reverse")
}
Window
{
title = "Animate"
label,
}.open
}
}
FBSL
FBSLSETTEXT(ME, "Hello world! ")
RESIZE(ME, 0, 0, 220, 0)
CENTER(ME)
SHOW(ME)
SetTimer(ME, 1000, 100, NULL)
BEGIN EVENTS
STATIC bForward AS BOOLEAN = TRUE
IF CBMSG = WM_TIMER THEN
Marquee(bForward)
RETURN 0
ELSEIF CBMSG = WM_NCLBUTTONDOWN THEN
IF CBWPARAM = HTCAPTION THEN bForward = NOT bForward
ELSEIF CBMSG = WM_CLOSE THEN
KillTimer(ME, 1000)
END IF
END EVENTS
SUB Marquee(BYVAL forward AS BOOLEAN)
STATIC caption AS STRING = FBSLGETTEXT(ME)
STATIC length AS INTEGER = STRLEN(caption)
IF forward THEN
caption = RIGHT(caption, 1) & LEFT(caption, length - 1)
ELSE
caption = MID(caption, 2) & LEFT(caption, 1)
END IF
FBSLSETTEXT(ME, caption)
END SUB
FreeBASIC
Any mouse button on the text will change the direction.
To exit, push the window's closing cross. (255 + 107 is the combination that is passed to INKEY$ by that button.)
DIM C AS STRING = "Hello World! ", SIZE AS USHORT = LEN(C)
DIM DIRECTION AS BYTE = 0
DIM AS INTEGER X, Y, BTNS
DIM HELD AS BYTE = 0
SCREEN 19
DO
LOCATE 1, 1
PRINT C
GETMOUSE X, Y, , BTNS
IF BTNS <> 0 AND HELD = 0 THEN
'remember if it was pressed, to not react every frame
HELD = 1
IF X >= 0 AND X < SIZE * 8 AND Y >= 0 AND Y < 16 THEN
DIRECTION = 1 - DIRECTION
END IF
ELSE
HELD = 0
END IF
IF INKEY = CHR(255) + CHR(107) THEN EXIT DO
IF DIRECTION = 0 THEN
C = RIGHT(C, 1) + LEFT(C, SIZE - 1)
ELSE
C = RIGHT(C, SIZE - 1) + LEFT(C, 1)
END IF
SLEEP 100, 1
LOOP
Gambas
'This code will create the necessary controls on a GUI Form
hLabel As Label 'Label needed to display the 'Hello World! " message
hTimer As Timer 'Timer to rotate the display
bDirection As Boolean 'Used to control the direction of the text
'__________________________________________________
Public Sub Form_Open()
Dim hPanel As Panel '2 Panels used to centre the Label vertically on the Form
Dim hHBox As HBox 'Box to hold the Label
With Me 'Set the Form Properties
.Arrangement = Arrange.Vertical 'Arrange controls vertically
.Title = "Animation" 'Give the Form a Title
.Height = 75 'Set the Height of the Form
.Width = 225 'Set the Width of the Form
End With
hPanel = New Panel(Me) 'Add a Panel to the Form
HPanel.Expand = True 'Expand the Panel
hHBox = New HBox(Me) 'Add a HBox to the Form
hHBox.Height = 28 'Set the HBox Height
hLabel = New Label(hHBox) As "LabelAnimation" 'Add new Lable with Event name
With hLabel 'Change the hLabel properties
.Height = 35 'Set the Height of the Label
.Expand = True 'Expand the hLabel
.Font.Bold = True 'Set the Font to Bold
.Font.size = 20 'Set the Font Size
.Alignment = Align.Center 'Centre align the text
.Tooltip = "Click me to reverse direction" 'Add a Tooltip
.Border = Border.Plain 'Add a Border
.Text = "Hello World! " 'Add the Text
End With
hPanel = New Panel(Me) 'Add another Panel
HPanel.Expand = True 'Expand the Panel
hTimer = New Timer As "Timer1" 'Add a Timer
hTimer.delay = 500 'Set the Timer Delay
hTimer.Start 'Start the Timer
End
'__________________________________________________
Public Sub LabelAnimation_MouseDown() 'If the hLabel is clicked..
bDirection = Not bDirection 'Change the value of bDirection
End
'__________________________________________________
Public Sub Timer1_Timer() 'Timer
Dim sString As String = hLabel.Text 'To hold the text in the Label
Dim sTemp As String 'Temp string
If bDirection Then 'If the text is to rotate left then..
sTemp = Left(sString, 1) 'Get the first charater of the Label Text e.g 'H'
sString = Right(sString, -1) & sTemp 'Recreate sString with all the text less the 1st character e.g. 'ello World! ' and add the 1st character to the end e.g. 'ello World! H'
Else 'Else if text is to rotate right then..
sTemp = Right(sString, 1) 'Get the last charater of the Label Text e.g '!'
sString = sTemp & Left(sString, -1) 'Recreate sString with all the text less the last character e.g. ' Hello World' and add the last character to the begining e.g. '! Hello World'
End If
hLabel.text = sString 'Display the result
End
'''[http://www.cogier.com/gambas/Animation.png Click here for image of running code]'''
Go
package main
import (
"log"
"time"
"github.com/gdamore/tcell"
)
const (
msg = "Hello World! "
x0, y0 = 8, 3
shiftsPerSecond = 4
clicksToExit = 5
)
func main() {
s, err := tcell.NewScreen()
if err != nil {
log.Fatal(err)
}
if err = s.Init(); err != nil {
log.Fatal(err)
}
s.Clear()
s.EnableMouse()
tick := time.Tick(time.Second / shiftsPerSecond)
click := make(chan bool)
go func() {
for {
em, ok := s.PollEvent().(*tcell.EventMouse)
if !ok || em.Buttons()&0xFF == tcell.ButtonNone {
continue
}
mx, my := em.Position()
if my == y0 && mx >= x0 && mx < x0+len(msg) {
click <- true
}
}
}()
for inc, shift, clicks := 1, 0, 0; ; {
select {
case <-tick:
shift = (shift + inc) % len(msg)
for i, r := range msg {
s.SetContent(x0+((shift+i)%len(msg)), y0, r, nil, 0)
}
s.Show()
case <-click:
clicks++
if clicks == clicksToExit {
s.Fini()
return
}
inc = len(msg) - inc
}
}
}
Haskell
Using simple graphics {{libheader|HGL}} from [http://hackage.haskell.org/packages/hackage.html 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
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
=={{header|Icon}} and {{header|Unicon}}== The following code uses features exclusive to Unicon.
import gui
$include "guih.icn"
class WindowApp : Dialog (label, direction)
method rotate_left (msg)
return msg[2:0] || msg[1]
end
method rotate_right (msg)
return msg[-1:0] || msg[1:-1]
end
method reverse_direction ()
direction := 1-direction
end
# this method gets called by the ticker, and updates the label
method tick ()
static msg := "Hello World! "
if direction = 0
then msg := rotate_left (msg)
else msg := rotate_right (msg)
label.set_label(msg)
end
method component_setup ()
direction := 1 # start off rotating to the right
label := Label("label=Hello World! ", "pos=0,0")
# respond to a mouse click on the label
label.connect (self, "reverse_direction", MOUSE_RELEASE_EVENT)
add (label)
connect (self, "dispose", CLOSE_BUTTON_EVENT)
# tick every 100ms
self.set_ticker (100)
end
end
# create and show the window
procedure main ()
w := WindowApp ()
w.show_modal ()
end
The following code uses features exclusive to Icon.
link graphics
procedure main()
s := "Hello World! "
WOpen("size=640,400", "label=Animation")
Font("typewriter,60,bold")
direction := 1
w := TextWidth(s)
h := WAttrib("fheight")
x := (WAttrib("width") - w) / 2
y := (WAttrib("height") - 20 + h) / 2
repeat
{ if *Pending() > 0 then if (Event() = &lrelease) & (x < &x < x + w) & (y > &y > y-h) then direction := ixor(direction, 1)
s := s[2 - 3 * direction:0] || s[1:2 - 3 * direction]
EraseArea(x, y, w, -h)
DrawString(x,y - WAttrib("descent")-1,s)
WFlush()
delay(250)
}
end
J
{{works with|J8}}
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 closeok;pn "Basic Animation in J";
minwh 350 5;
cc isi isigraph flush;
pcenter;pshow;
)
anim_run =: verb def 'wd ANIM,''; ptimer '',":TIMER_INTERVAL' NB. Set form timer
anim_timer =: verb def 'glpaint 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
anim_isi_paint =: verb define
glclear '' NB. Clear out old drawing
glrgb 255 0 0
gltextcolor''
glfont '"courier new" 36'
gltext MESSAGE
)
anim_run ''
{{works with|J6}}
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 ''
Java
{{libheader|Swing}}
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.WindowConstants;
public class Rotate {
private static class State {
private final String text = "Hello World! ";
private int startIndex = 0;
private boolean rotateRight = true;
}
public static void main(String[] args) {
State state = new State();
JLabel label = new JLabel(state.text);
label.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent event) {
state.rotateRight = !state.rotateRight;
}
});
TimerTask task = new TimerTask() {
public void run() {
int delta = state.rotateRight ? 1 : -1;
state.startIndex = (state.startIndex + state.text.length() + delta) % state.text.length();
label.setText(rotate(state.text, state.startIndex));
}
};
Timer timer = new Timer(false);
timer.schedule(task, 0, 500);
JFrame rot = new JFrame();
rot.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
rot.add(label);
rot.pack();
rot.setLocationRelativeTo(null);
rot.addWindowListener(new WindowAdapter() {
@Override
public void windowClosed(WindowEvent e) {
timer.cancel();
}
});
rot.setVisible(true);
}
private static String rotate(String text, int startIdx) {
char[] rotated = new char[text.length()];
for (int i = 0; i < text.length(); i++) {
rotated[i] = text.charAt((i + startIdx) % text.length());
}
return String.valueOf(rotated);
}
}
=={{header|JavaScript}} + {{header|HTML}}==
<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!