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