home *** CD-ROM | disk | FTP | other *** search
/ Freelog 65 / Freelog065.iso / BAS / Bureautique / Gnumeric / gnumeric-1.3.92-rc1.exe / pixbufs.c < prev    next >
C/C++ Source or Header  |  2004-10-15  |  6KB  |  273 lines

  1. /* Pixbufs
  2.  *
  3.  * A GdkPixbuf represents an image, normally in RGB or RGBA format.
  4.  * Pixbufs are normally used to load files from disk and perform
  5.  * image scaling.
  6.  *
  7.  * This demo is not all that educational, but looks cool. It was written
  8.  * by Extreme Pixbuf Hacker Federico Mena Quintero. It also shows
  9.  * off how to use GtkDrawingArea to do a simple animation.
  10.  *
  11.  * Look at the Image demo for additional pixbuf usage examples.
  12.  *
  13.  */
  14.  
  15. #include <config.h>
  16. #include <stdlib.h>
  17. #include <gtk/gtk.h>
  18. #include <math.h>
  19.  
  20. #include "demo-common.h"
  21.  
  22. #define FRAME_DELAY 50
  23.  
  24. #define BACKGROUND_NAME "background.jpg"
  25.  
  26. static const char *image_names[] = {
  27.   "apple-red.png",
  28.   "gnome-applets.png",
  29.   "gnome-calendar.png",
  30.   "gnome-foot.png",
  31.   "gnome-gmush.png",
  32.   "gnome-gimp.png",
  33.   "gnome-gsame.png",
  34.   "gnu-keys.png"
  35. };
  36.  
  37. #define N_IMAGES G_N_ELEMENTS (image_names)
  38.  
  39. /* demo window */
  40. static GtkWidget *window = NULL;
  41.  
  42. /* Current frame */
  43. static GdkPixbuf *frame;
  44.  
  45. /* Background image */
  46. static GdkPixbuf *background;
  47. static gint back_width, back_height;
  48.  
  49. /* Images */
  50. static GdkPixbuf *images[N_IMAGES];
  51.  
  52. /* Widgets */
  53. static GtkWidget *da;
  54.  
  55. /* Loads the images for the demo and returns whether the operation succeeded */
  56. static gboolean
  57. load_pixbufs (GError **error)
  58. {
  59.   gint i;
  60.   char *filename;
  61.  
  62.   if (background)
  63.     return TRUE; /* already loaded earlier */
  64.  
  65.   /* demo_find_file() looks in the the current directory first,
  66.    * so you can run gtk-demo without installing GTK, then looks
  67.    * in the location where the file is installed.
  68.    */
  69.   filename = demo_find_file (BACKGROUND_NAME, error);
  70.   if (!filename)
  71.     return FALSE; /* note that "error" was filled in and returned */
  72.  
  73.   background = gdk_pixbuf_new_from_file (filename, error);
  74.   g_free (filename);
  75.   
  76.   if (!background)
  77.     return FALSE; /* Note that "error" was filled with a GError */
  78.  
  79.   back_width = gdk_pixbuf_get_width (background);
  80.   back_height = gdk_pixbuf_get_height (background);
  81.  
  82.   for (i = 0; i < N_IMAGES; i++)
  83.     {
  84.       filename = demo_find_file (image_names[i], error);
  85.       if (!filename)
  86.     return FALSE; /* Note that "error" was filled with a GError */
  87.       
  88.       images[i] = gdk_pixbuf_new_from_file (filename, error);
  89.       g_free (filename);
  90.       
  91.       if (!images[i])
  92.     return FALSE; /* Note that "error" was filled with a GError */
  93.     }
  94.  
  95.   return TRUE;
  96. }
  97.  
  98. /* Expose callback for the drawing area */
  99. static gint
  100. expose_cb (GtkWidget      *widget,
  101.        GdkEventExpose *event,
  102.        gpointer       data)
  103. {
  104.   guchar *pixels;
  105.   int rowstride;
  106.  
  107.   rowstride = gdk_pixbuf_get_rowstride (frame);
  108.  
  109.   pixels = gdk_pixbuf_get_pixels (frame) + rowstride * event->area.y + event->area.x * 3;
  110.  
  111.   gdk_draw_rgb_image_dithalign (widget->window,
  112.                 widget->style->black_gc,
  113.                 event->area.x, event->area.y,
  114.                 event->area.width, event->area.height,
  115.                 GDK_RGB_DITHER_NORMAL,
  116.                 pixels, rowstride,
  117.                 event->area.x, event->area.y);
  118.  
  119.   return TRUE;
  120. }
  121.  
  122. #define CYCLE_LEN 60
  123.  
  124. static int frame_num;
  125.  
  126. /* Timeout handler to regenerate the frame */
  127. static gint
  128. timeout (gpointer data)
  129. {
  130.   double f;
  131.   int i;
  132.   double xmid, ymid;
  133.   double radius;
  134.  
  135.   gdk_pixbuf_copy_area (background, 0, 0, back_width, back_height,
  136.             frame, 0, 0);
  137.  
  138.   f = (double) (frame_num % CYCLE_LEN) / CYCLE_LEN;
  139.  
  140.   xmid = back_width / 2.0;
  141.   ymid = back_height / 2.0;
  142.  
  143.   radius = MIN (xmid, ymid) / 2.0;
  144.  
  145.   for (i = 0; i < N_IMAGES; i++)
  146.     {
  147.       double ang;
  148.       int xpos, ypos;
  149.       int iw, ih;
  150.       double r;
  151.       GdkRectangle r1, r2, dest;
  152.       double k;
  153.  
  154.       ang = 2.0 * G_PI * (double) i / N_IMAGES - f * 2.0 * G_PI;
  155.  
  156.       iw = gdk_pixbuf_get_width (images[i]);
  157.       ih = gdk_pixbuf_get_height (images[i]);
  158.  
  159.       r = radius + (radius / 3.0) * sin (f * 2.0 * G_PI);
  160.  
  161.       xpos = floor (xmid + r * cos (ang) - iw / 2.0 + 0.5);
  162.       ypos = floor (ymid + r * sin (ang) - ih / 2.0 + 0.5);
  163.  
  164.       k = (i & 1) ? sin (f * 2.0 * G_PI) : cos (f * 2.0 * G_PI);
  165.       k = 2.0 * k * k;
  166.       k = MAX (0.25, k);
  167.  
  168.       r1.x = xpos;
  169.       r1.y = ypos;
  170.       r1.width = iw * k;
  171.       r1.height = ih * k;
  172.  
  173.       r2.x = 0;
  174.       r2.y = 0;
  175.       r2.width = back_width;
  176.       r2.height = back_height;
  177.  
  178.       if (gdk_rectangle_intersect (&r1, &r2, &dest))
  179.     gdk_pixbuf_composite (images[i],
  180.                   frame,
  181.                   dest.x, dest.y,
  182.                   dest.width, dest.height,
  183.                   xpos, ypos,
  184.                   k, k,
  185.                   GDK_INTERP_NEAREST,
  186.                   ((i & 1)
  187.                    ? MAX (127, fabs (255 * sin (f * 2.0 * G_PI)))
  188.                    : MAX (127, fabs (255 * cos (f * 2.0 * G_PI)))));
  189.     }
  190.  
  191.   gtk_widget_queue_draw (da);
  192.  
  193.   frame_num++;
  194.   return TRUE;
  195. }
  196.  
  197. static guint timeout_id;
  198.  
  199. static void
  200. cleanup_callback (GtkObject *object,
  201.           gpointer   data)
  202. {
  203.   g_source_remove (timeout_id);
  204.   timeout_id = 0;
  205. }
  206.  
  207. GtkWidget *
  208. do_pixbufs (GtkWidget *do_widget)
  209. {
  210.   if (!window)
  211.     {
  212.       GError *error;
  213.  
  214.       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  215.       gtk_window_set_screen (GTK_WINDOW (window),
  216.                  gtk_widget_get_screen (do_widget));
  217.       gtk_window_set_title (GTK_WINDOW (window), "Pixbufs");
  218.       gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
  219.  
  220.       g_signal_connect (window, "destroy", G_CALLBACK (gtk_widget_destroyed), &window);
  221.       g_signal_connect (window, "destroy", G_CALLBACK (cleanup_callback), NULL);
  222.  
  223.  
  224.       error = NULL;
  225.       if (!load_pixbufs (&error))
  226.     {
  227.       GtkWidget *dialog;
  228.  
  229.       dialog = gtk_message_dialog_new (GTK_WINDOW (window),
  230.                        GTK_DIALOG_DESTROY_WITH_PARENT,
  231.                        GTK_MESSAGE_ERROR,
  232.                        GTK_BUTTONS_CLOSE,
  233.                        "Failed to load an image: %s",
  234.                        error->message);
  235.  
  236.       g_error_free (error);
  237.  
  238.       g_signal_connect (dialog, "response",
  239.                 G_CALLBACK (gtk_widget_destroy), NULL);
  240.  
  241.       gtk_widget_show (dialog);
  242.     }
  243.       else
  244.     {
  245.       gtk_widget_set_size_request (window, back_width, back_height);
  246.  
  247.       frame = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, back_width, back_height);
  248.  
  249.       da = gtk_drawing_area_new ();
  250.  
  251.       g_signal_connect (da, "expose_event",
  252.                 G_CALLBACK (expose_cb), NULL);
  253.  
  254.       gtk_container_add (GTK_CONTAINER (window), da);
  255.  
  256.       timeout_id = g_timeout_add (FRAME_DELAY, timeout, NULL);
  257.     }
  258.     }
  259.  
  260.   if (!GTK_WIDGET_VISIBLE (window))
  261.     {
  262.       gtk_widget_show_all (window);
  263.     }
  264.   else
  265.     {
  266.       gtk_widget_destroy (window);
  267.       window = NULL;
  268.       g_object_unref (frame);
  269.     }
  270.  
  271.   return window;
  272. }
  273.