1 /*
   2  *
   3  * Copyright (c) 2007, 2019, 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 
  33 
  34 import javax.swing.*;
  35 import javax.swing.event.*;
  36 import javax.swing.text.*;
  37 import javax.swing.border.*;
  38 import javax.swing.colorchooser.*;
  39 import javax.swing.filechooser.*;
  40 import javax.accessibility.*;
  41 
  42 import java.awt.*;
  43 import java.awt.font.*;
  44 import java.awt.geom.*;
  45 import java.awt.image.*;
  46 import java.lang.reflect.InvocationTargetException;
  47 import java.awt.event.*;
  48 
  49 /**
  50  * BezierAnimationPanel
  51  *
  52  * @author Jim Graham
  53  * @author Jeff Dinkins (removed dynamic setting changes, made swing friendly)
  54  */
  55 class BezierAnimationPanel extends JPanel implements Runnable {
  56 
  57     Color backgroundColor =  new Color(0,     0, 153);
  58     Color outerColor      =  new Color(255, 255, 255);
  59     Color gradientColorA  =  new Color(255,   0, 101);
  60     Color gradientColorB  =  new Color(255, 255,   0);
  61 
  62     boolean bgChanged = false;
  63 
  64     GradientPaint gradient = null;
  65 
  66     public final int NUMPTS = 6;
  67 
  68     float[] animpts = new float[NUMPTS * 2];
  69 
  70     float[] deltas = new float[NUMPTS * 2];
  71 
  72     float[] staticpts = {
  73          50.0f,   0.0f,
  74         150.0f,   0.0f,
  75         200.0f,  75.0f,
  76         150.0f, 150.0f,
  77          50.0f, 150.0f,
  78           0.0f,  75.0f,
  79     };
  80 
  81     float[] movepts = new float[staticpts.length];
  82 
  83     BufferedImage img;
  84 
  85     Rectangle bounds = null;
  86 
  87     Thread anim;
  88 
  89     private final Object lock = new Object();
  90 
  91     /**
  92      * BezierAnimationPanel Constructor
  93      */
  94     public BezierAnimationPanel() {
  95         addHierarchyListener(
  96             new HierarchyListener() {
  97                public void hierarchyChanged(HierarchyEvent e) {
  98                    if(isShowing()) {
  99                        start();
 100                    } else {
 101                        stop();
 102                    }
 103                }
 104            }
 105         );
 106         setBackground(getBackgroundColor());
 107     }
 108 
 109     public boolean isOpaque() {
 110         return true;
 111     }
 112 
 113     public Color getGradientColorA() {
 114         return gradientColorA;
 115     }
 116 
 117     public void setGradientColorA(Color c) {
 118         if(c != null) {
 119             gradientColorA = c;
 120         }
 121     }
 122 
 123     public Color getGradientColorB() {
 124         return gradientColorB;
 125     }
 126 
 127     public void setGradientColorB(Color c) {
 128         if(c != null) {
 129             gradientColorB = c;
 130         }
 131     }
 132 
 133     public Color getOuterColor() {
 134         return outerColor;
 135     }
 136 
 137     public void setOuterColor(Color c) {
 138         if(c != null) {
 139             outerColor = c;
 140         }
 141     }
 142 
 143     public Color getBackgroundColor() {
 144         return backgroundColor;
 145     }
 146 
 147     public void setBackgroundColor(Color c) {
 148         if(c != null) {
 149             backgroundColor = c;
 150             setBackground(c);
 151             bgChanged = true;
 152         }
 153     }
 154 
 155     public void start() {
 156         Dimension size = getSize();
 157         for (int i = 0; i < animpts.length; i += 2) {
 158             animpts[i + 0] = (float) (Math.random() * size.width);
 159             animpts[i + 1] = (float) (Math.random() * size.height);
 160             deltas[i + 0] = (float) (Math.random() * 4.0 + 2.0);
 161             deltas[i + 1] = (float) (Math.random() * 4.0 + 2.0);
 162             if (animpts[i + 0] > size.width / 6.0f) {
 163                 deltas[i + 0] = -deltas[i + 0];
 164             }
 165             if (animpts[i + 1] > size.height / 6.0f) {
 166                 deltas[i + 1] = -deltas[i + 1];
 167             }
 168         }
 169         anim = new Thread(this);
 170         anim.setPriority(Thread.MIN_PRIORITY);
 171         anim.start();
 172     }
 173 
 174     public synchronized void stop() {
 175         anim = null;
 176         notify();
 177     }
 178 
 179     public void animate(float[] pts, float[] deltas, int index, int limit) {
 180         float newpt = pts[index] + deltas[index];
 181         if (newpt <= 0) {
 182             newpt = -newpt;
 183             deltas[index] = (float) (Math.random() * 3.0 + 2.0);
 184         } else if (newpt >= (float) limit) {
 185             newpt = 2.0f * limit - newpt;
 186             deltas[index] = - (float) (Math.random() * 3.0 + 2.0);
 187         }
 188         pts[index] = newpt;
 189     }
 190 
 191     public void run() {
 192         Thread me = Thread.currentThread();
 193         while (getSize().width <= 0) {
 194             try {
 195                 anim.sleep(500);
 196             } catch (InterruptedException e) {
 197                 return;
 198             }
 199         }
 200 
 201         Graphics2D g2d = null;
 202         Graphics2D BufferG2D = null;
 203         Graphics2D ScreenG2D = null;
 204         BasicStroke solid = new BasicStroke(9.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 9.0f);
 205         GeneralPath gp = new GeneralPath(GeneralPath.WIND_NON_ZERO);
 206         int rule = AlphaComposite.SRC_OVER;
 207         AlphaComposite opaque = AlphaComposite.SrcOver;
 208         AlphaComposite blend = AlphaComposite.getInstance(rule, 0.9f);
 209         AlphaComposite set = AlphaComposite.Src;
 210         int frame = 0;
 211         int frametmp = 0;
 212         Dimension oldSize = getSize();
 213         Shape clippath = null;
 214         while (anim == me) {
 215             Dimension size = getSize();
 216             if (size.width != oldSize.width || size.height != oldSize.height) {
 217                 img = null;
 218                 clippath = null;
 219                 if (BufferG2D != null) {
 220                     BufferG2D.dispose();
 221                     BufferG2D = null;
 222                 }
 223                 if (ScreenG2D != null) {
 224                     ScreenG2D.dispose();
 225                     ScreenG2D = null;
 226                 }
 227             }
 228             oldSize = size;
 229 
 230             if (img == null) {
 231                 img = (BufferedImage) createImage(size.width, size.height);
 232             }
 233 
 234         if (BufferG2D == null) {
 235                 BufferG2D = img.createGraphics();
 236                 BufferG2D.setRenderingHint(RenderingHints.KEY_RENDERING,
 237                                            RenderingHints.VALUE_RENDER_DEFAULT);
 238                 BufferG2D.setClip(clippath);
 239             }
 240             g2d = BufferG2D;
 241 
 242             float[] ctrlpts;
 243             for (int i = 0; i < animpts.length; i += 2) {
 244                 animate(animpts, deltas, i + 0, size.width);
 245                 animate(animpts, deltas, i + 1, size.height);
 246             }
 247             ctrlpts = animpts;
 248             int len = ctrlpts.length;
 249             gp.reset();
 250             int dir = 0;
 251             float prevx = ctrlpts[len - 2];
 252             float prevy = ctrlpts[len - 1];
 253             float curx = ctrlpts[0];
 254             float cury = ctrlpts[1];
 255             float midx = (curx + prevx) / 2.0f;
 256             float midy = (cury + prevy) / 2.0f;
 257             gp.moveTo(midx, midy);
 258             for (int i = 2; i <= ctrlpts.length; i += 2) {
 259                 float x1 = (midx + curx) / 2.0f;
 260                 float y1 = (midy + cury) / 2.0f;
 261                 prevx = curx;
 262                 prevy = cury;
 263                 if (i < ctrlpts.length) {
 264                     curx = ctrlpts[i + 0];
 265                     cury = ctrlpts[i + 1];
 266                 } else {
 267                     curx = ctrlpts[0];
 268                     cury = ctrlpts[1];
 269                 }
 270                 midx = (curx + prevx) / 2.0f;
 271                 midy = (cury + prevy) / 2.0f;
 272                 float x2 = (prevx + midx) / 2.0f;
 273                 float y2 = (prevy + midy) / 2.0f;
 274                 gp.curveTo(x1, y1, x2, y2, midx, midy);
 275             }
 276             gp.closePath();
 277 
 278             synchronized(lock) {
 279         g2d.setComposite(set);
 280             g2d.setBackground(backgroundColor);
 281             g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
 282                                  RenderingHints.VALUE_ANTIALIAS_OFF);
 283 
 284             if(bgChanged || bounds == null) {
 285                 bounds = new Rectangle(0, 0, getWidth(), getHeight());
 286                 bgChanged = false;
 287             }
 288 
 289         // g2d.clearRect(bounds.x-5, bounds.y-5, bounds.x + bounds.width + 5, bounds.y + bounds.height + 5);
 290             g2d.clearRect(0, 0, getWidth(), getHeight());
 291 
 292             g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
 293                                  RenderingHints.VALUE_ANTIALIAS_ON);
 294             g2d.setColor(outerColor);
 295             g2d.setComposite(opaque);
 296             g2d.setStroke(solid);
 297             g2d.draw(gp);
 298             g2d.setPaint(gradient);
 299 
 300             if(!bgChanged) {
 301                 bounds = gp.getBounds();
 302             } else {
 303                 bounds = new Rectangle(0, 0, getWidth(), getHeight());
 304                 bgChanged = false;
 305             }
 306             gradient = new GradientPaint(bounds.x, bounds.y, gradientColorA,
 307                                          bounds.x + bounds.width, bounds.y + bounds.height,
 308                                          gradientColorB, true);
 309             g2d.setComposite(blend);
 310             g2d.fill(gp);
 311         }
 312             if (g2d == BufferG2D) {
 313                 try {
 314                     SwingUtilities.invokeAndWait(new Runnable() {
 315 
 316                         @Override
 317                         public void run() {
 318                             repaint();
 319                         }
 320                     });
 321                 } catch (InvocationTargetException | InterruptedException e) {
 322                     e.printStackTrace();
 323                 }
 324             }
 325             ++frame;
 326         }
 327         if (g2d != null) {
 328             g2d.dispose();
 329         }
 330     }
 331 
 332     public void paint(Graphics g) {
 333         synchronized (lock) {
 334            Graphics2D g2d = (Graphics2D) g;
 335            if (img != null) {
 336                g2d.setComposite(AlphaComposite.Src);
 337                g2d.drawImage(img, null, 0, 0);
 338            }
 339         }
 340     }
 341 }