1 #!/usr/bin/env dub
2 /+
3 dub.sdl:
4     name "snippet288"
5     dependency "dwt" path="../../../../../../"
6     libs \
7       "atk-1.0" \
8       "cairo" \
9       "dl" \
10       "fontconfig" \
11       "gdk-x11-2.0" \
12       "gdk_pixbuf-2.0" \
13       "glib-2.0" \
14       "gmodule-2.0" \
15       "gnomeui-2" \
16       "gnomevfs-2" \
17       "gobject-2.0" \
18       "gthread-2.0" \
19       "gtk-x11-2.0" \
20       "pango-1.0" \
21       "pangocairo-1.0" \
22       "X11" \
23       "Xcomposite" \
24       "Xcursor" \
25       "Xdamage" \
26       "Xext" \
27       "Xfixes" \
28       "Xi" \
29       "Xinerama" \
30       "Xrandr" \
31       "Xrender" \
32       "Xtst" \
33       platform="linux"
34 +/
35 
36 /*******************************************************************************
37  * Copyright (c) 2008 IBM Corporation and others.
38  * All rights reserved. This program and the accompanying materials
39  * are made available under the terms of the Eclipse Public License v1.0
40  * which accompanies this distribution, and is available at
41  * http://www.eclipse.org/legal/epl-v10.html
42  *
43  * Contributors:
44  *     IBM Corporation - initial API and implementation
45  *******************************************************************************/
46 module org.eclipse.swt.snippets.Snippet288;
47 
48 /*
49  * Create a ToolBar containing animated GIFs
50  *
51  * For a list of all SWT example snippets see
52  * http://www.eclipse.org/swt/snippets/
53  */
54 import org.eclipse.swt.SWT;
55 import org.eclipse.swt.SWTException;
56 import org.eclipse.swt.graphics.GC;
57 import org.eclipse.swt.graphics.Color;
58 import org.eclipse.swt.graphics.Image;
59 import org.eclipse.swt.graphics.ImageLoader;
60 import org.eclipse.swt.graphics.ImageData;
61 import org.eclipse.swt.widgets.Display;
62 import org.eclipse.swt.widgets.Shell;
63 import org.eclipse.swt.widgets.ToolBar;
64 import org.eclipse.swt.widgets.ToolItem;
65 import org.eclipse.swt.widgets.FileDialog;
66 
67 import java.lang.all;
68 
69 version(Tango){
70     import tango.io.FilePath;
71     import tango.io.model.IFile;
72     //import tango.core.Thread;
73     import tango.io.Stdout;
74     import tango.util.Convert;
75     import tango.core.Exception;
76 } else { // Phobos
77     import std.path;
78     import std.stdio;
79     import std.conv;
80     import core.exception;
81     import core.thread : ThreadException;
82     struct FileConst {
83         static const PathSeparatorChar = dirSeparator;
84     }
85 }
86 
87 mixin(gshared!("
88 Display display;
89 Shell shell;
90 GC shellGC;
91 Color shellBackground;
92 ImageLoader[] loader;
93 ImageData[][] imageDataArray;
94 Thread[] animateThread;
95 Image[][] image;
96 ToolItem[] item;
97 "));
98 const bool useGIFBackground = false;
99 
100 void main () {
101     display = new Display();
102     Shell shell = new Shell (display);
103     shellBackground = shell.getBackground();
104     FileDialog dialog = new FileDialog(shell, SWT.OPEN | SWT.MULTI);
105     dialog.setText("Select Multiple Animated GIFs");
106     dialog.setFilterExtensions(["*.gif"]);
107     String filename = dialog.open();
108     String[] filenames = dialog.getFileNames();
109     int numToolBarItems = cast(int)filenames.length;
110     if (numToolBarItems > 0) {
111         version(Tango){
112             try {
113                 loadAllImages((new FilePath(filename)).parent, filenames);
114             } catch (SWTException e) {
115                 Stdout.print("There was an error loading an image.").newline;
116                 e.printStackTrace();
117             }
118         } else { // Phobos
119             try {
120                 loadAllImages(filename.dirName, filenames);
121             } catch (SWTException e) {
122                 writeln("There was an error loading an image.");
123                 e.printStackTrace();
124             }
125         }
126         ToolBar toolBar = new ToolBar (shell, SWT.FLAT | SWT.BORDER | SWT.WRAP);
127         item = new ToolItem[numToolBarItems];
128         for (int i = 0; i < numToolBarItems; i++) {
129             item[i] = new ToolItem (toolBar, SWT.PUSH);
130             item[i].setImage(image[i][0]);
131         }
132         toolBar.pack ();
133         shell.open ();
134 			
135         startAnimationThreads();
136 			
137         while (!shell.isDisposed()) {
138             if (!display.readAndDispatch ()) display.sleep ();
139         }
140 			
141         for (int i = 0; i < numToolBarItems; i++) {
142             for (int j = 0; j < image[i].length; j++) {
143                 image[i][j].dispose();
144             }
145         }
146         display.dispose ();
147     }
148     Thread.joinAll();
149 }
150 
151 void loadAllImages(String directory, String[] filenames) {
152     int numItems = cast(int)filenames.length;
153     loader.length = numItems;
154     imageDataArray.length = numItems;
155     image.length = numItems;
156     for (int i = 0; i < numItems; i++) {
157         loader[i] = new ImageLoader();
158         int fullWidth = loader[i].logicalScreenWidth;
159         int fullHeight = loader[i].logicalScreenHeight;
160         imageDataArray[i] = loader[i].load(directory ~ FileConst.PathSeparatorChar ~ filenames[i]);
161         int numFramesOfAnimation = cast(int)imageDataArray[i].length;
162         image[i] = new Image[numFramesOfAnimation];
163         for (int j = 0; j < numFramesOfAnimation; j++) {
164             if (j == 0) {
165                 //for the first frame of animation, just draw the first frame
166                 image[i][j] = new Image(display, imageDataArray[i][j]);
167                 fullWidth = imageDataArray[i][j].width;
168                 fullHeight = imageDataArray[i][j].height;
169             }
170             else {
171                 //after the first frame of animation, draw the background or previous frame first, then the new image data 
172                 image[i][j] = new Image(display, fullWidth, fullHeight);
173                 GC gc = new GC(image[i][j]);
174                 gc.setBackground(shellBackground);
175                 gc.fillRectangle(0, 0, fullWidth, fullHeight);
176                 ImageData imageData = imageDataArray[i][j];
177                 switch (imageData.disposalMethod) {
178                 case SWT.DM_FILL_BACKGROUND:
179                     /* Fill with the background color before drawing. */
180                     Color bgColor = null;
181                     if (useGIFBackground && loader[i].backgroundPixel != -1) {
182                         bgColor = new Color(display, imageData.palette.getRGB(loader[i].backgroundPixel));
183                     }
184                     gc.setBackground(bgColor !is null ? bgColor : shellBackground);
185                     gc.fillRectangle(imageData.x, imageData.y, imageData.width, imageData.height);
186                     if (bgColor !is null) bgColor.dispose();
187                     break;
188                 default:
189                     /* Restore the previous image before drawing. */
190                     gc.drawImage(
191                         image[i][j-1],
192                         0,
193                         0,
194                         fullWidth,
195                         fullHeight,
196                         0,
197                         0,
198                         fullWidth,
199                         fullHeight);
200                     break;
201                 }
202                 Image newFrame = new Image(display, imageData);
203                 gc.drawImage(newFrame,
204                              0,
205                              0,
206                              imageData.width,
207                              imageData.height,
208                              imageData.x,
209                              imageData.y,
210                              imageData.width,
211                              imageData.height);
212                 newFrame.dispose();
213                 gc.dispose();
214             }
215         }
216     }
217 }
218 
219 void startAnimationThreads() {
220     animateThread = new Thread[image.length];
221     for (int ii = 0; ii < image.length; ii++) {
222         animateThread[ii] = new class(ii) Thread {
223             int imageDataIndex = 0;
224             int id = 0;
225             this(int _id) { 
226                 id = _id;
227                 //name = "Animation "~to!(char[])(ii);
228                 //isDaemon = true;
229                 super(&run);
230             }
231             override
232             void run() {
233                 try {
234                     int repeatCount = loader[id].repeatCount;
235                     while (loader[id].repeatCount == 0 || repeatCount > 0) {
236                         imageDataIndex = (imageDataIndex + 1) % cast(int)imageDataArray[id].length;
237                         if (!display.isDisposed()) {
238                             display.asyncExec(new class Runnable {
239 									public void run() {
240 										if (!item[id].isDisposed())
241 											item[id].setImage(image[id][imageDataIndex]);
242 									}
243 								});
244                         }
245 							
246                         /* Sleep for the specified delay time (adding commonly-used slow-down fudge factors). */
247                         try {
248                             int ms = imageDataArray[id][imageDataIndex].delayTime * 10;
249                             if (ms < 20) ms += 30;
250                             if (ms < 30) ms += 10;
251                             Thread.sleep(1 * ms);
252                         } catch (ThreadException e) {
253                         }
254 
255                         /* If we have just drawn the last image, decrement the repeat count and start again. */
256                         if (imageDataIndex == imageDataArray[id].length - 1) repeatCount--;
257                     }
258                 } catch (SWTException ex) {
259                     version(Tango){
260                         Stdout.print("There was an error animating the GIF").newline;
261                     } else { // Phobos
262                         writeln("There was an error animating the GIF");
263                     }
264                     ex.printStackTrace();
265                 }
266             }
267         };
268         animateThread[ii].start();
269     }
270 }
271