Animation: Difference between revisions

From Rosetta Code
Content added Content deleted
(add Ruby)
m (→‎{{header|AutoHotkey}}: Minor indentation and case changes)
Line 86: Line 86:
Gui, Show
Gui, Show
animate()
animate()
Return
return


#ifwinactive animation.ahk
#IfWinActive animation.ahk
~Lbutton::
~LButton::
WinGetPos ,,, Width, Height
WinGetPos ,,, width, height
MouseGetPos, x, y
MouseGetPos, x, y
if x and y
If x And y
if (x < Width) and (y < Height)
If (x < width) And (y < height)
reverse := !reverse
reverse := !reverse
return
return
#IfWinActive
#ifwinactive


animate()
animate()
{
{
global
Global
loop,
Loop,
{
{
sleep, 200
Sleep, 200
if reverse
If reverse
message := substr(message, 2, strlen(message)) . substr(message,1, 1)
message := SubStr(message, 2, StrLen(message)) . SubStr(message,1, 1)
else
Else
message := substr(message,strlen(message), 1) . substr(message, 1, strlen(message) - 1)
message := SubStr(message, StrLen(message), 1) . SubStr(message, 1, StrLen(message) - 1)
guicontrol,,myedit, %message%
GuiControl,,myedit, %message%
}
}
}</lang>
}</lang>

Revision as of 09:57, 19 June 2009

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.

C

Library: GTK

(NB: implicitly, through GTK, it uses also Pango library) <lang c>#include <stdlib.h>

  1. include <string.h>
  2. 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;

}</lang>

AutoHotkey

<lang AutoHotkey>message := "Hello World! " Gui, Add, Text, vmyedit , %message% Gui, +AlwaysOnTop +Disabled -SysMenu +Owner Gui, Show animate() Return

  1. IfWinActive animation.ahk

~LButton::

 WinGetPos ,,, width, height
 MouseGetPos, x, y
 If x And y
 If (x < width) And (y < height)
 reverse := !reverse
 return
  1. 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%
 }

}</lang>

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

<lang lisp>(use-package ':ltk) (use-package :ext)

(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* (string-concat (substring *message* 1 n) c))
     (setq *message* (string-concat 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)</lang>

HTML+JavaScript

<lang javascript><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.substr(1, text.length) + text[0];
               else
                   text = text[text.length - 1] + text.substr(0, text.length - 1);
               textNode.data = text;
           }, 100);
       }
   </script>
   <style type="text/css">
       #target { font-family: monospace; }
   </style>

</head> <body onload="animate('target')">

Hello World!

</body> </html></lang>

Ruby

Translation of: Tcl
Library: Ruby/Tk

<lang ruby>require 'tk' $str = TkVariable.new("Hello World! ") $dir = 0

def animate

 t = $str.value
 $str.value = if $dir == 0
                 t[1..-1] + t[0].chr
               else
                 t[-1].chr + t[0..-2]
               end
 $root.after(125) {animate}

end

$root = TkRoot.new("title" => "Basic Animation")

TkLabel.new($root) do

 textvariable $str
 font "Courier 14"
 pack {side 'top'}
 bind("ButtonPress-1") {$dir = ($dir + 1) % 2}

end

animate Tk.mainloop</lang>

Tcl

Library: Tk

<lang tcl>package require Tk set s "Hello World! " set dir 0

  1. 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

}

  1. Make the label (constant width font looks better)

pack [label .l -textvariable s -font {Courier 14}]

  1. Make a mouse click reverse the direction

bind .l <Button-1> {set dir [expr {!$dir}]}

  1. Start the animation

animate</lang>