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      */
 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")
 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 
 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 
 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 
 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
 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
 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
 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 
 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 
 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 
 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
 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
 364         public Dimension getPreferredSize() {
 365             return new Dimension(200, 40);
 366         }
 367 
 368         @Override
 369         @SuppressWarnings("SleepWhileHoldingLock")
 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