1 /* Pixbufs
2  *
3  * A Pixbuf 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 DrawingArea to do a simple animation.
10  *
11  * Look at the Image demo for additional pixbuf usage examples.
12  *
13  */
14 
15 using Gdk;
16 using Gtk;
17 
18 using System;
19 using System.Runtime.InteropServices; // for Marshal.Copy
20 
21 namespace GtkDemo
22 {
23 	[Demo ("Pixbuf", "DemoPixbuf.cs")]
24 	public class DemoPixbuf : Gtk.Window
25 	{
26 		const int FrameDelay = 50;
27 		const int CycleLen = 60;
28 		const string BackgroundName = "background.jpg";
29 
30 		static string[] ImageNames = {
31 			"apple-red.png",
32 			"gnome-applets.png",
33 			"gnome-calendar.png",
34 			"gnome-foot.png",
35 			"gnome-gmush.png",
36 			"gnome-gimp.png",
37 			"gnome-gsame.png",
38 			"gnu-keys.png"
39 		};
40 
41 		// background image
42 		static Pixbuf background;
43 		static int backWidth, backHeight;
44 
45 		// images
46 		static Pixbuf[] images;
47 
48 		// current frame
49 		Pixbuf frame;
50 		int frameNum;
51 
52 		// drawing area
53 		DrawingArea drawingArea;
54 
55 		uint timeoutId;
56 
DemoPixbuf()57 		static DemoPixbuf ()
58 		{
59 			// Load the images for the demo
60 
61 			background = Gdk.Pixbuf.LoadFromResource (BackgroundName);
62 
63 			backWidth = background.Width;
64 			backHeight = background.Height;
65 
66 			images = new Pixbuf[ImageNames.Length];
67 
68 			int i = 0;
69 			foreach (string im in ImageNames)
70 				images[i++] = Gdk.Pixbuf.LoadFromResource (im);
71 		}
72 
73 		// Expose callback for the drawing area
Expose(object o, ExposeEventArgs args)74 		void Expose (object o, ExposeEventArgs args)
75 		{
76 			Widget widget = (Widget) o;
77 			Gdk.Rectangle area = args.Event.Area;
78 			byte[] pixels;
79 			int rowstride;
80 
81 			rowstride = frame.Rowstride;
82 			pixels = new byte[(frame.Height - area.Y) * rowstride];
83 			IntPtr src = (IntPtr)(frame.Pixels.ToInt64 () + rowstride * area.Y + area.X * 3);
84 			Marshal.Copy (src, pixels, 0, pixels.Length);
85 
86 			widget.GdkWindow.DrawRgbImageDithalign (widget.Style.BlackGC,
87 								area.X, area.Y, area.Width, area.Height,
88 								Gdk.RgbDither.Normal,
89 								pixels, rowstride,
90 								area.X, area.Y);
91 			args.RetVal = true;
92 		}
93 
94 		// timeout handler to regenerate the frame
timeout()95 		bool timeout ()
96 		{
97 			background.CopyArea (0, 0, backWidth, backHeight, frame, 0, 0);
98 
99 			double f = (double) (frameNum % CycleLen) / CycleLen;
100 
101 			int xmid = backWidth / 2;
102 			int ymid = backHeight / 2;
103 
104 			double radius = Math.Min (xmid, ymid) / 2;
105 
106 			for (int i = 0; i < images.Length; i++) {
107 				double ang = 2 * Math.PI * (double) i / images.Length - f * 2 * Math.PI;
108 
109 				int iw = images[i].Width;
110 				int ih = images[i].Height;
111 
112 				double r = radius + (radius / 3) * Math.Sin (f * 2 * Math.PI);
113 
114 				int xpos = (int) Math.Floor (xmid + r * Math.Cos (ang) -
115 							     iw / 2.0 + 0.5);
116 				int ypos = (int) Math.Floor (ymid + r * Math.Sin (ang) -
117 							     ih / 2.0 + 0.5);
118 
119 				double k = (i % 2 == 1) ? Math.Sin (f * 2 * Math.PI) :
120 					Math.Cos (f * 2 * Math.PI);
121 				k = 2 * k * k;
122 				k = Math.Max (0.25, k);
123 
124 				Rectangle r1, r2, dest;
125 
126 				r1 = new Rectangle (xpos, ypos, (int) (iw * k), (int) (ih * k));
127 				r2 = new Rectangle (0, 0, backWidth, backHeight);
128 
129 				dest = Rectangle.Intersect (r1, r2);
130 				if (!dest.IsEmpty) {
131 					images[i].Composite (frame, dest.X, dest.Y,
132 							     dest.Width, dest.Height,
133 							     xpos, ypos, k, k,
134 							     InterpType.Nearest,
135 							     (int) ((i % 2 == 1) ?
136 								    Math.Max (127, Math.Abs (255 * Math.Sin (f * 2 * Math.PI))) :
137 								    Math.Max (127, Math.Abs (255 * Math.Cos (f * 2 * Math.PI)))));
138 				}
139 			}
140 
141 			drawingArea.QueueDraw ();
142 			frameNum++;
143 
144 			return true;
145 		}
146 
DemoPixbuf()147 		public DemoPixbuf () : base ("Pixbufs")
148 		{
149 			Resizable = false;
150 			SetSizeRequest (backWidth, backHeight);
151 
152 			frame = new Pixbuf (Colorspace.Rgb, false, 8, backWidth, backHeight);
153 
154 			drawingArea = new DrawingArea ();
155 			drawingArea.ExposeEvent += new ExposeEventHandler (Expose);
156 
157 			Add (drawingArea);
158 			timeoutId = GLib.Timeout.Add (FrameDelay, new GLib.TimeoutHandler(timeout));
159 
160 			ShowAll ();
161 		}
162 
OnDestroyed()163 		protected override void OnDestroyed ()
164 		{
165 			if (timeoutId != 0) {
166 				GLib.Source.Remove (timeoutId);
167 				timeoutId = 0;
168 			}
169 		}
170 
OnDeleteEvent(Gdk.Event evt)171 		protected override bool OnDeleteEvent (Gdk.Event evt)
172 		{
173 			Destroy ();
174 			return true;
175 		}
176 	}
177 }
178