1 /*
2  *
3  * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  *   - Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  *
12  *   - Redistributions in binary form must reproduce the above copyright
13  *     notice, this list of conditions and the following disclaimer in the
14  *     documentation and/or other materials provided with the distribution.
15  *
16  *   - Neither the name of Oracle nor the names of its
17  *     contributors may be used to endorse or promote products derived
18  *     from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 package java2d.demos.Mix;
33 
34 
35 import static java.awt.Color.LIGHT_GRAY;
36 import static java.awt.Color.WHITE;
37 import static java.lang.Math.random;
38 import java.awt.AlphaComposite;
39 import java.awt.BasicStroke;
40 import java.awt.Color;
41 import java.awt.Component;
42 import java.awt.Dimension;
43 import java.awt.Font;
44 import java.awt.FontMetrics;
45 import java.awt.Graphics2D;
46 import java.awt.Image;
47 import java.awt.RenderingHints;
48 import java.awt.event.ActionEvent;
49 import java.awt.event.ActionListener;
50 import java.awt.geom.GeneralPath;
51 import java.awt.geom.Path2D;
52 import java.awt.geom.PathIterator;
53 import java.awt.image.BufferedImage;
54 import java.io.BufferedReader;
55 import java.io.FileReader;
56 import java.util.ArrayList;
57 import java.util.List;
58 import java.util.logging.Level;
59 import java.util.logging.Logger;
60 import java2d.AnimatingControlsSurface;
61 import java2d.CustomControls;
62 import javax.swing.AbstractButton;
63 import javax.swing.JComboBox;
64 import javax.swing.JToggleButton;
65 import javax.swing.JToolBar;
66 
67 
68 /**
69  * Animated Bezier Curve shape with images at the control points.
70  * README.txt file scrolling up. Composited Image fading in and out.
71  */
72 @SuppressWarnings("serial")
73 public class BezierScroller extends AnimatingControlsSurface {
74 
75     private static String[] appletStrs = { " ", "J2Ddemo",
76         "BezierScroller - Animated Bezier Curve shape with images",
77         "For README.txt file scrolling run in application mode", " " };
78     private static final int NUMPTS = 6;
79     private static Color greenBlend = new Color(0, 255, 0, 100);
80     private static Color blueBlend = new Color(0, 0, 255, 100);
81     private static Font font = new Font(Font.SERIF, Font.PLAIN, 12);
82     private static BasicStroke bs = new BasicStroke(3.0f);
83     private static Image hotj_img;
84     private static BufferedImage img;
85     private static final int UP = 0;
86     private static final int DOWN = 1;
87     private float[] animpts = new float[NUMPTS * 2];
88     private float[] deltas = new float[NUMPTS * 2];
89     private BufferedReader reader;
90     private int nStrs;
91     private int strH;
92     private int yy, ix, iy, imgX;
93     private List<String> vector, appletVector;
94     private float alpha = 0.2f;
95     private int alphaDirection;
96     protected boolean doImage, doShape, doText;
97     protected boolean buttonToggle;
98 
99     /*
100      * Using this to scale down globe.png since we want a smaller version,
101      * I know it is 100 x 160 and has a transparent pixel.
102      */
scaled(Image src)103     private Image scaled(Image src) {
104         int sw = src.getWidth(null);
105         int sh = src.getHeight(null);
106         int dw = sw/5;
107         int dh = sh/5;
108         BufferedImage bi =
109             new BufferedImage(dw, dh, BufferedImage.TYPE_INT_ARGB);
110         Graphics2D g2d = bi.createGraphics();
111         g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
112                              RenderingHints.VALUE_INTERPOLATION_BICUBIC);
113         g2d.drawImage(src, 0, 0, dw, dh, 0, 0, sw, sh, null);
114         g2d.dispose();
115         return bi;
116     }
117 
118     @SuppressWarnings("LeakingThisInConstructor")
BezierScroller()119     public BezierScroller() {
120         setBackground(WHITE);
121         doShape = doText = true;
122         hotj_img = scaled(getImage("globe.png"));
123         Image image = getImage("jumptojavastrip.png");
124         int iw = image.getWidth(this);
125         int ih = image.getHeight(this);
126         img = new BufferedImage(iw, ih, BufferedImage.TYPE_INT_RGB);
127         img.createGraphics().drawImage(image, 0, 0, this);
128         setControls(new Component[] { new DemoControls(this) });
129     }
130 
animate(float[] pts, float[] deltas, int index, int limit)131     public void animate(float[] pts, float[] deltas, int index, int limit) {
132         float newpt = pts[index] + deltas[index];
133         if (newpt <= 0) {
134             newpt = -newpt;
135             deltas[index] = (float) (random() * 4.0 + 2.0);
136         } else if (newpt >= limit) {
137             newpt = 2.0f * limit - newpt;
138             deltas[index] = -(float) (random() * 4.0 + 2.0);
139         }
140         pts[index] = newpt;
141     }
142 
getFile()143     public void getFile() {
144         try {
145             String fName = "README.txt";
146             if ((reader = new BufferedReader(new FileReader(fName))) != null) {
147                 getLine();
148             }
149         } catch (Exception e) {
150             reader = null;
151         }
152         if (reader == null) {
153             appletVector = new ArrayList<String>(100);
154             for (int i = 0; i < 100; i++) {
155                 appletVector.add(appletStrs[i % appletStrs.length]);
156             }
157             getLine();
158         }
159         buttonToggle = true;
160     }
161 
getLine()162     public String getLine() {
163         String str = null;
164         if (reader != null) {
165             try {
166                 if ((str = reader.readLine()) != null) {
167                     if (str.length() == 0) {
168                         str = " ";
169                     }
170                     vector.add(str);
171                 }
172             } catch (Exception e) {
173                 Logger.getLogger(BezierScroller.class.getName()).log(
174                         Level.SEVERE,
175                         null, e);
176                 reader = null;
177             }
178         } else {
179             if (!appletVector.isEmpty()) {
180                 vector.add(str = appletVector.remove(0));
181             }
182         }
183         return str;
184     }
185 
186     @Override
reset(int w, int h)187     public void reset(int w, int h) {
188         for (int i = 0; i < animpts.length; i += 2) {
189             animpts[i + 0] = (float) (random() * w);
190             animpts[i + 1] = (float) (random() * h);
191             deltas[i + 0] = (float) (random() * 6.0 + 4.0);
192             deltas[i + 1] = (float) (random() * 6.0 + 4.0);
193             if (animpts[i + 0] > w / 2.0f) {
194                 deltas[i + 0] = -deltas[i + 0];
195             }
196             if (animpts[i + 1] > h / 2.0f) {
197                 deltas[i + 1] = -deltas[i + 1];
198             }
199         }
200         FontMetrics fm = getFontMetrics(font);
201         strH = fm.getAscent() + fm.getDescent();
202         nStrs = h / strH + 2;
203         vector = new ArrayList<String>(nStrs);
204         ix = (int) (random() * (w - 80));
205         iy = (int) (random() * (h - 80));
206     }
207 
208     @Override
step(int w, int h)209     public void step(int w, int h) {
210         if (doText && vector.isEmpty()) {
211             getFile();
212         }
213         if (doText) {
214             String s = getLine();
215             if (s == null || vector.size() == nStrs && !vector.isEmpty()) {
216                 vector.remove(0);
217             }
218             yy = (s == null) ? 0 : h - vector.size() * strH;
219         }
220 
221         for (int i = 0; i < animpts.length && doShape; i += 2) {
222             animate(animpts, deltas, i + 0, w);
223             animate(animpts, deltas, i + 1, h);
224         }
225         if (doImage && alphaDirection == UP) {
226             if ((alpha += 0.025) > .99) {
227                 alphaDirection = DOWN;
228                 alpha = 1.0f;
229             }
230         } else if (doImage && alphaDirection == DOWN) {
231             if ((alpha -= .02) < 0.01) {
232                 alphaDirection = UP;
233                 alpha = 0;
234                 ix = (int) (random() * (w - 80));
235                 iy = (int) (random() * (h - 80));
236             }
237         }
238         if (doImage) {
239             if ((imgX += 80) == 800) {
240                 imgX = 0;
241             }
242         }
243     }
244 
245     @Override
render(int w, int h, Graphics2D g2)246     public void render(int w, int h, Graphics2D g2) {
247 
248         if (doText) {
249             g2.setColor(LIGHT_GRAY);
250             g2.setFont(font);
251             float y = yy;
252             //for (int i = 0; i < vector.size(); i++) {
253             for (String string : vector) {
254                 g2.drawString(string, 1, y += strH);
255             }
256         }
257 
258         if (doShape) {
259             float[] ctrlpts = animpts;
260             int len = ctrlpts.length;
261             float prevx = ctrlpts[len - 2];
262             float prevy = ctrlpts[len - 1];
263             float curx = ctrlpts[0];
264             float cury = ctrlpts[1];
265             float midx = (curx + prevx) / 2.0f;
266             float midy = (cury + prevy) / 2.0f;
267             GeneralPath gp = new GeneralPath(Path2D.WIND_NON_ZERO);
268             gp.moveTo(midx, midy);
269             for (int i = 2; i <= ctrlpts.length; i += 2) {
270                 float x1 = (midx + curx) / 2.0f;
271                 float y1 = (midy + cury) / 2.0f;
272                 prevx = curx;
273                 prevy = cury;
274                 if (i < ctrlpts.length) {
275                     curx = ctrlpts[i + 0];
276                     cury = ctrlpts[i + 1];
277                 } else {
278                     curx = ctrlpts[0];
279                     cury = ctrlpts[1];
280                 }
281                 midx = (curx + prevx) / 2.0f;
282                 midy = (cury + prevy) / 2.0f;
283                 float x2 = (prevx + midx) / 2.0f;
284                 float y2 = (prevy + midy) / 2.0f;
285                 gp.curveTo(x1, y1, x2, y2, midx, midy);
286             }
287             gp.closePath();
288 
289             g2.setColor(blueBlend);
290             g2.setStroke(bs);
291             g2.draw(gp);
292             g2.setColor(greenBlend);
293             g2.fill(gp);
294 
295             PathIterator pi = gp.getPathIterator(null);
296             float[] pts = new float[6];
297             while (!pi.isDone()) {
298                 if (pi.currentSegment(pts) == PathIterator.SEG_CUBICTO) {
299                     g2.drawImage(hotj_img, (int) pts[0], (int) pts[1], this);
300                 }
301                 pi.next();
302             }
303         }
304 
305         if (doImage) {
306             AlphaComposite ac = AlphaComposite.getInstance(
307                     AlphaComposite.SRC_OVER, alpha);
308             g2.setComposite(ac);
309             g2.drawImage(img.getSubimage(imgX, 0, 80, 80), ix, iy, this);
310         }
311     }
312 
main(String[] argv)313     public static void main(String[] argv) {
314         createDemoFrame(new BezierScroller());
315     }
316 
317 
318     static final class DemoControls extends CustomControls implements
319             ActionListener {
320 
321         BezierScroller demo;
322         JToolBar toolbar;
323         JComboBox combo;
324 
DemoControls(BezierScroller demo)325         public DemoControls(BezierScroller demo) {
326             super(demo.name);
327             this.demo = demo;
328             add(toolbar = new JToolBar());
329             toolbar.setFloatable(false);
330             addTool("Image", false);
331             addTool("Shape", true);
332             addTool("Text", true);
333         }
334 
addTool(String str, boolean state)335         public void addTool(String str, boolean state) {
336             JToggleButton b =
337                     (JToggleButton) toolbar.add(new JToggleButton(str));
338             b.setFocusPainted(false);
339             b.setSelected(state);
340             b.addActionListener(this);
341             int width = b.getPreferredSize().width;
342             Dimension prefSize = new Dimension(width, 21);
343             b.setPreferredSize(prefSize);
344             b.setMaximumSize(prefSize);
345             b.setMinimumSize(prefSize);
346         }
347 
348         @Override
actionPerformed(ActionEvent e)349         public void actionPerformed(ActionEvent e) {
350             JToggleButton b = (JToggleButton) e.getSource();
351             if (b.getText().equals("Image")) {
352                 demo.doImage = b.isSelected();
353             } else if (b.getText().equals("Shape")) {
354                 demo.doShape = b.isSelected();
355             } else {
356                 demo.doText = b.isSelected();
357             }
358             if (!demo.animating.running()) {
359                 demo.repaint();
360             }
361         }
362 
363         @Override
getPreferredSize()364         public Dimension getPreferredSize() {
365             return new Dimension(200, 40);
366         }
367 
368         @Override
369         @SuppressWarnings("SleepWhileHoldingLock")
run()370         public void run() {
371             Thread me = Thread.currentThread();
372             int i = 0;
373             while (thread == me) {
374                 try {
375                     Thread.sleep(250);
376                 } catch (InterruptedException e) {
377                     return;
378                 }
379                 if (demo.buttonToggle) {
380                     ((AbstractButton) toolbar.getComponentAtIndex(i++ % 2)).
381                             doClick();
382                     demo.buttonToggle = false;
383                 }
384             }
385             thread = null;
386         }
387     } // End DemoControls
388 } // End BezierScroller
389 
390