Java/Advanced Graphics/Animation

Материал из Java эксперт
Перейти к: навигация, поиск

Animated Graphics

   <source lang="java">


import java.awt.Color; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.SwingUtilities; import javax.swing.Timer; /*

* AnimatedGraphics_2008.java
*
* Created on May 2, 2007, 4:02 PM
*
* Copyright (c) 2007, Sun Microsystems, Inc
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the TimingFramework project nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**

*
* @author Chet
*/

public class AnimatedGraphics_2008 extends JComponent implements ActionListener {

   Color startColor = Color.GRAY;  // where we start
   Color endColor = Color.BLACK;         // where we end
   Color currentColor = startColor;
   int animationDuration = 2000;   // each animation will take 2 seconds
   long animStartTime;     // start time for each animation
   
   /**
    * Set up and start the timer
    */
   public AnimatedGraphics_2008() {
       Timer timer = new Timer(30, this);
       // initial delay while window gets set up
       timer.setInitialDelay(1000);
       animStartTime = 1000 + System.nanoTime() / 1000000;
       timer.start();
   }
   
   /**
    * Erase to the background color and fill an oval with the current
    * color (which is being animated elsewhere)
    */
   public void paintComponent(Graphics g) {
       g.setColor(getBackground());
       g.fillRect(0, 0, getWidth(), getHeight());
       g.setColor(currentColor);
       g.fillOval(0, 0, getWidth(), getHeight());
   }
   
   /**
    * Callback from the Swing Timer. Calculate the fraction elapsed of
    * our desired animation duration and interpolate between our start and
    * end colors accordingly.
    */
   public void actionPerformed(ActionEvent ae) {
       // calculate elapsed fraction of animation
       long currentTime = System.nanoTime() / 1000000;
       long totalTime = currentTime - animStartTime;
       if (totalTime > animationDuration) {
           animStartTime = currentTime;
       }
       float fraction = (float)totalTime / animationDuration;
       fraction = Math.min(1.0f, fraction);
       // interpolate between start and end colors with current fraction
       int red = (int)(fraction * endColor.getRed() + 
               (1 - fraction) * startColor.getRed());
       int green = (int)(fraction * endColor.getGreen() + 
               (1 - fraction) * startColor.getGreen());
       int blue = (int)(fraction * endColor.getBlue() + 
               (1 - fraction) * startColor.getBlue());
       // set our new color appropriately
       currentColor = new Color(red, green, blue);
       // force a repaint to display our oval with its new color
       repaint();
   }
   
   private static void createAndShowGUI() {    
       JFrame f = new JFrame("Animated Graphics");
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.setSize(200, 200);
       f.add(new AnimatedGraphics_2008());
       f.setVisible(true);
   }
   
   public static void main(String args[]) {
       Runnable doCreateAndShowGUI = new Runnable() {
           public void run() {
               createAndShowGUI();
           }
       };
       SwingUtilities.invokeLater(doCreateAndShowGUI);
   }

}

</source>
   
  
 
  



Background Animation

   <source lang="java">


/*

* Copyright (c) 2007, Romain Guy
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the TimingFramework project nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import java.awt.AlphaComposite; import java.awt.BorderLayout; import java.awt.Color; import java.awt.ruponent; import java.awt.ruposite; import java.awt.Container; import java.awt.Cursor; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridBagLayout; import java.awt.HeadlessException; import java.awt.Image; import java.awt.Insets; import java.awt.LayoutManager; import java.awt.LayoutManager2; import java.awt.Paint; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ruponentAdapter; import java.awt.event.ruponentEvent; import java.awt.event.ruponentListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.awt.font.FontRenderContext; import java.awt.font.TextLayout; import java.awt.geom.AffineTransform; import java.awt.geom.Area; import java.awt.geom.Ellipse2D; import java.awt.geom.GeneralPath; import java.awt.geom.Rectangle2D; import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.imageio.ImageIO; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSeparator; import javax.swing.JSlider; import javax.swing.SwingUtilities; import javax.swing.Timer; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; /**

* @author Romain Guy
*/

public class BackgroundAnimation_2008 extends JFrame {

 private AvatarChooser chooser;
 private CurvesPanel curves;
 public BackgroundAnimation_2008() throws HeadlessException {
   super("Stack Layout");
   buildContentPane();
   // buildDebugControls();
   startAnimation();
   setSize(640, 400);
   setLocationRelativeTo(null);
   setDefaultCloseOperation(EXIT_ON_CLOSE);
 }
 private void startAnimation() {
   Timer timer = new Timer(50, new ActionListener() {
     public void actionPerformed(ActionEvent e) {
       curves.animate();
       curves.repaint();
     }
   });
   timer.start();
 }
 private void buildDebugControls() {
   JPanel pane = new JPanel(new BorderLayout());
   pane.setBackground(Color.WHITE);
   pane.add(new JSeparator(), BorderLayout.NORTH);
   final GraphPanel grapher = new GraphPanel();
   JPanel graphPane = new JPanel(new FlowLayout(FlowLayout.CENTER));
   graphPane.setOpaque(false);
   graphPane.add(grapher);
   JPanel buttonsPane = new JPanel(new FlowLayout(FlowLayout.CENTER));
   buttonsPane.setOpaque(false);
   JSlider spacing = new JSlider(JSlider.HORIZONTAL, 0, 100, 40);
   spacing.setBackground(Color.WHITE);
   spacing.setPreferredSize(new Dimension(95, spacing.getPreferredSize().height));
   spacing.addChangeListener(new ChangeListener() {
     public void stateChanged(ChangeEvent e) {
       JSlider slider = (JSlider) e.getSource();
       double spacing = slider.getValue() / 100.0;
       chooser.setSpacing(spacing);
       grapher.spacing = spacing;
       grapher.repaint();
     }
   });
   JSlider sigma = new JSlider(JSlider.HORIZONTAL, 0, 100, 50);
   sigma.setBackground(Color.WHITE);
   sigma.setPreferredSize(new Dimension(95, sigma.getPreferredSize().height));
   sigma.addChangeListener(new ChangeListener() {
     public void stateChanged(ChangeEvent e) {
       JSlider slider = (JSlider) e.getSource();
       double sigma = slider.getValue() / 100.0;
       chooser.setSigma(sigma);
       grapher.sigma = sigma;
       grapher.repaint();
     }
   });
   JSlider position = new JSlider(JSlider.HORIZONTAL, -100, 100, 0);
   position.setBackground(Color.WHITE);
   position.setPreferredSize(new Dimension(95, position.getPreferredSize().height));
   position.addChangeListener(new ChangeListener() {
     public void stateChanged(ChangeEvent e) {
       JSlider slider = (JSlider) e.getSource();
       double position = slider.getValue() / 100.0;
       chooser.setPosition(position);
       grapher.position = position;
       grapher.repaint();
     }
   });
   JSlider amount = new JSlider(JSlider.HORIZONTAL, 1, 15, 5);
   amount.setBackground(Color.WHITE);
   amount.setPreferredSize(new Dimension(95, position.getPreferredSize().height));
   amount.addChangeListener(new ChangeListener() {
     public void stateChanged(ChangeEvent e) {
       JSlider slider = (JSlider) e.getSource();
       int amount = slider.getValue();
       chooser.setAmount(amount);
       grapher.amount = amount;
       grapher.repaint();
     }
   });
   buttonsPane.add(new JLabel("Spacing: "));
   buttonsPane.add(spacing);
   buttonsPane.add(new JLabel("Sigma: "));
   buttonsPane.add(sigma);
   buttonsPane.add(new JLabel("Position: "));
   buttonsPane.add(position);
   buttonsPane.add(new JLabel("Amount: "));
   buttonsPane.add(amount);
   pane.add(buttonsPane, BorderLayout.NORTH);
   pane.add(graphPane, BorderLayout.CENTER);
   add(pane, BorderLayout.SOUTH);
 }
 private void buildContentPane() {
   JPanel pane = new JPanel();
   pane.setLayout(new StackLayout());
   GradientPanel gradient = new GradientPanel();
   chooser = new AvatarChooser();
   curves = new CurvesPanel();
   pane.add(gradient, StackLayout.TOP);
   pane.add(chooser, StackLayout.TOP);
   pane.add(curves, StackLayout.TOP);
   add(pane);
 }
 private class GraphPanel extends JComponent {
   private double spacing = 0.4;
   private double position = 0.0;
   private double sigma = 0.5;
   private int amount = 5;
   @Override
   public Dimension getPreferredSize() {
     return new Dimension(200, 60);
   }
   @Override
   public boolean isOpaque() {
     return false;
   }
   @Override
   protected void paintComponent(Graphics g) {
     Graphics2D g2 = (Graphics2D) g;
     g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
     g2.setColor(Color.BLACK);
     g2.drawLine(0, 50, 100, 50);
     g2.drawLine(50, 0, 50, 60);
     g2.setColor(Color.BLUE);
     double lastY = 50.0;
     for (int x = 0; x < 100; x++) {
       double y = chooser.ruputeModifier((50.0 - x) / 25.0) * 45.0 + 10;
       if (x == 0) {
         lastY = y;
       }
       g2.drawLine(x - 1, 60 - (int) lastY, x, 60 - (int) y);
       lastY = y;
     }
     g2.setColor(Color.RED);
     for (int i = 0; i < amount; i++) {
       double offset = ((amount / 2) - i) * spacing;
       double x = (100.0 - 5.0) / 2.0;
       x += 25.0 * (position + offset);
       if (x > 100) {
         continue;
       }
       double y = 60.0 - (chooser.ruputeModifier(position + offset) * 45.0 + 10);
       g2.fill(new Rectangle2D.Double(x, y - 1, 5.0, 5.0));
     }
     g2.setColor(Color.GREEN.darker());
     g2.drawLine(25, 0, 25, 60);
     g2.drawLine(75, 0, 75, 60);
     g2.setColor(Color.DARK_GRAY);
     g2.drawString("Sigma: " + sigma, 110.0f, 16.0f);
     g2.drawString("Spacing: " + spacing, 110.0f, 30.0f);
     g2.drawString("Position: " + position, 110.0f, 44.0f);
   }
 }
 public static void main(String[] args) {
   try {
     UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
   } catch (ClassNotFoundException ex) {
     ex.printStackTrace();
   } catch (IllegalAccessException ex) {
     ex.printStackTrace();
   } catch (InstantiationException ex) {
     ex.printStackTrace();
   } catch (UnsupportedLookAndFeelException ex) {
     ex.printStackTrace();
   }
   SwingUtilities.invokeLater(new Runnable() {
     public void run() {
       BackgroundAnimation_2008 tester = new BackgroundAnimation_2008();
       tester.setVisible(true);
     }
   });
 }

} /*

* Copyright (c) 2007, Romain Guy All rights reserved.
* 
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*  * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. * Neither the name of the
* TimingFramework project nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior
* written permission.
* 
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

class AvatarChooser extends JPanel {

 private static final double ANIM_SCROLL_DELAY = 450;
 private List<Image> avatars = null;
 private boolean loadingDone = false;
 private Thread picturesFinder = null;
 private Timer scrollerTimer = null;
 private Timer faderTimer = null;
 private Timer passwordTimer;
 private float veilAlphaLevel = 0.0f;
 private float alphaLevel = 0.0f;
 private float textAlphaLevel = 0.0f;
 private int avatarIndex;
 private double avatarPosition = 0.0;
 private double avatarSpacing = 0.4;
 private int avatarAmount = 5;
 private double sigma;
 private double rho;
 private double exp_multiplier;
 private double exp_member;
 private boolean damaged = true;
 private DrawableAvatar[] drawableAvatars;
 private String textAvatar;
 private FocusGrabber focusGrabber;
 private AvatarScroller avatarScroller;
 private CursorChanger cursorChanger;
 private MouseWheelScroller wheelScroller;
 private KeyScroller keyScroller;
 public AvatarChooser() {
   GridBagLayout layout = new GridBagLayout();
   setLayout(layout);
   findAvatars();
   setSigma(0.5);
   addComponentListener(new DamageManager());
   initInputListeners();
   addInputListeners();
 }
 public void setAmount(int amount) {
   if (amount > avatars.size()) {
     throw new IllegalArgumentException("Too many avatars");
   }
   this.avatarAmount = amount;
   repaint();
 }
 // XXX package access for debugging purpose only
 void setPosition(double position) {
   this.avatarPosition = position;
   this.damaged = true;
   repaint();
 }
 public void setSigma(double sigma) {
   this.sigma = sigma;
   this.rho = 1.0;
   computeEquationParts();
   this.rho = computeModifierUnprotected(0.0);
   computeEquationParts();
   this.damaged = true;
   repaint();
 }
 public void setSpacing(double avatarSpacing) {
   if (avatarSpacing < 0.0 || avatarSpacing > 1.0) {
     throw new IllegalArgumentException("Spacing must be < 1.0 and > 0.0");
   }
   this.avatarSpacing = avatarSpacing;
   this.damaged = true;
   repaint();
 }
 @Override
 public Dimension getPreferredSize() {
   return new Dimension(128 * 3, 128 * 2);
 }
 @Override
 public Dimension getMaximumSize() {
   return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
 }
 @Override
 public boolean isOpaque() {
   return false;
 }
 @Override
 public boolean isFocusable() {
   return true;
 }
 @Override
 protected void paintChildren(Graphics g) {
   Graphics2D g2 = (Graphics2D) g;
   Composite oldComposite = g2.getComposite();
   g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, veilAlphaLevel));
   super.paintChildren(g);
   g2.setComposite(oldComposite);
 }
 @Override
 protected void paintComponent(Graphics g) {
   super.paintComponent(g);
   if (!loadingDone && faderTimer == null) {
     return;
   }
   Insets insets = getInsets();
   int x = insets.left;
   int y = insets.top;
   int width = getWidth() - insets.left - insets.right;
   int height = getHeight() - insets.top - insets.bottom;
   Graphics2D g2 = (Graphics2D) g;
   g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
       RenderingHints.VALUE_INTERPOLATION_BILINEAR);
   g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
   Composite oldComposite = g2.getComposite();
   if (damaged) {
     drawableAvatars = sortAvatarsByDepth(x, y, width, height);
     damaged = false;
   }
   drawAvatars(g2, drawableAvatars);
   if (drawableAvatars.length > 0) {
     drawAvatarName(g2);
   }
   g2.setComposite(oldComposite);
 }
 private void drawAvatars(Graphics2D g2, DrawableAvatar[] drawableAvatars) {
   for (DrawableAvatar avatar : drawableAvatars) {
     AlphaComposite composite = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, (float) avatar
         .getAlpha());
     g2.setComposite(composite);
     g2.drawImage(avatars.get(avatar.getIndex()), (int) avatar.getX(), (int) avatar.getY(), avatar
         .getWidth(), avatar.getHeight(), null);
   }
 }
 private DrawableAvatar[] sortAvatarsByDepth(int x, int y, int width, int height) {
   List<DrawableAvatar> drawables = new LinkedList<DrawableAvatar>();
   for (int i = 0; i < avatars.size(); i++) {
     promoteAvatarToDrawable(drawables, x, y, width, height, i - avatarIndex);
   }
   DrawableAvatar[] drawableAvatars = new DrawableAvatar[drawables.size()];
   drawableAvatars = drawables.toArray(drawableAvatars);
   Arrays.sort(drawableAvatars);
   return drawableAvatars;
 }
 private void drawAvatarName(Graphics2D g2) {
   Composite composite = g2.getComposite();
   g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, textAlphaLevel));
   double bulletWidth = 150.0;
   double bulletHeight = 30.0;
   double x = (getWidth() - bulletWidth) / 2.0;
   double y = (getHeight() - 164) / 2.0 - bulletHeight * 1.4;
   drawAvatarBullet(g2, x, y, bulletWidth, bulletHeight);
   drawAvatarText(g2, y, bulletHeight);
   g2.setComposite(composite);
 }
 private void drawAvatarText(Graphics2D g2, double y, double bulletHeight) {
   FontRenderContext context = g2.getFontRenderContext();
   Font font = new Font("Dialog", Font.PLAIN, 18);
   TextLayout layout = new TextLayout(textAvatar, font, context);
   Rectangle2D bounds = layout.getBounds();
   float text_x = (float) ((getWidth() - bounds.getWidth()) / 2.0);
   float text_y = (float) (y + (bulletHeight - layout.getAscent() - layout.getDescent()) / 2.0)
       + layout.getAscent() - layout.getLeading();
   g2.setColor(Color.BLACK);
   layout.draw(g2, text_x, text_y + 1);
   g2.setColor(Color.WHITE);
   layout.draw(g2, text_x, text_y);
 }
 private void drawAvatarBullet(Graphics2D g2, double x, double y, double bulletWidth,
     double bulletHeight) {
   RoundRectangle2D bullet = new RoundRectangle2D.Double(0.0, 0.0, bulletWidth, bulletHeight,
       bulletHeight, bulletHeight);
   Ellipse2D curve = new Ellipse2D.Double(-20.0, bulletHeight / 2.0, bulletWidth + 40.0,
       bulletHeight);
   g2.translate(x, y);
   g2.translate(-1, -2);
   g2.setColor(new Color(0, 0, 0, 170));
   g2.fill(new RoundRectangle2D.Double(0.0, 0.0, bulletWidth + 2, bulletHeight + 4,
       bulletHeight + 4, bulletHeight + 4));
   g2.translate(1, 2);
   Color startColor = new Color(10, 0, 40);
   Color endColor = new Color(175, 165, 225);
   Paint paint = g2.getPaint();
   g2.setPaint(new GradientPaint(0.0f, 0.0f, startColor, 0.0f, (float) bulletHeight, endColor));
   g2.fill(bullet);
   startColor = new Color(5, 0, 50);
   endColor = new Color(105, 100, 155);
   g2.setPaint(new GradientPaint(0.0f, 0.0f, startColor, 0.0f, (float) bulletHeight, endColor));
   Area area = new Area(bullet);
   area.intersect(new Area(curve));
   g2.fill(area);
   g2.setPaint(paint);
   g2.translate(-x, -y);
 }
 private void promoteAvatarToDrawable(List<DrawableAvatar> drawables, int x, int y, int width,
     int height, int offset) {
   double spacing = offset * avatarSpacing;
   double avatarPosition = this.avatarPosition + spacing;
   if (avatarIndex + offset < 0 || avatarIndex + offset >= avatars.size()) {
     return;
   }
   Image avatar = avatars.get(avatarIndex + offset);
   int avatarWidth = avatar.getWidth(null);
   int avatarHeight = avatar.getHeight(null);
   double result = computeModifier(avatarPosition);
   int newWidth = (int) (avatarWidth * result);
   if (newWidth == 0) {
     return;
   }
   int newHeight = (int) (avatarHeight * result);
   if (newHeight == 0) {
     return;
   }
   double avatar_x = x + (width - newWidth) / 2.0;
   double avatar_y = y + (height - newHeight / 2.0) / 2.0;
   double semiWidth = width / 2.0;
   avatar_x += avatarPosition * semiWidth;
   if (avatar_x >= width || avatar_x < -newWidth) {
     return;
   }
   drawables.add(new DrawableAvatar(avatarIndex + offset, avatar_x, avatar_y, newWidth, newHeight,
       avatarPosition, result));
 }
 private void startFader() {
   faderTimer = new Timer(35, new FaderAction());
   faderTimer.start();
 }
 private void computeEquationParts() {
   exp_multiplier = Math.sqrt(2.0 * Math.PI) / sigma / rho;
   exp_member = 4.0 * sigma * sigma;
 }
 // XXX package access for debug purpose only
 double computeModifier(double x) {
   double result = computeModifierUnprotected(x);
   if (result > 1.0) {
     result = 1.0;
   } else if (result < -1.0) {
     result = -1.0;
   }
   return result;
 }
 private double computeModifierUnprotected(double x) {
   return exp_multiplier * Math.exp((-x * x) / exp_member);
 }
 private void addInputListeners() {
   addMouseListener(focusGrabber);
   addMouseListener(avatarScroller);
   addMouseMotionListener(cursorChanger);
   addMouseWheelListener(wheelScroller);
   addKeyListener(keyScroller);
 }
 private void initInputListeners() {
   // input listeners are all stateless
   // hence they can be instantiated once
   focusGrabber = new FocusGrabber();
   avatarScroller = new AvatarScroller();
   cursorChanger = new CursorChanger();
   wheelScroller = new MouseWheelScroller();
   keyScroller = new KeyScroller();
 }
 private void removeInputListeners() {
   removeMouseListener(focusGrabber);
   removeMouseListener(avatarScroller);
   removeMouseMotionListener(cursorChanger);
   removeMouseWheelListener(wheelScroller);
   removeKeyListener(keyScroller);
 }
 private void findAvatars() {
   avatars = new ArrayList<Image>();
   picturesFinder = new Thread(new PicturesFinderThread());
   picturesFinder.start();
 }
 private void setAvatarIndex(int index) {
   avatarIndex = index;
   textAvatar = "Photo " + index;
 }
 private void scrollBy(int increment) {
   if (loadingDone) {
     setAvatarIndex(avatarIndex + increment);
     if (avatarIndex < 0) {
       setAvatarIndex(0);
     } else if (avatarIndex >= avatars.size()) {
       setAvatarIndex(avatars.size() - 1);
     }
     damaged = true;
     repaint();
   }
 }
 private void scrollAndAnimateBy(int increment) {
   if (loadingDone && (scrollerTimer == null || !scrollerTimer.isRunning())) {
     int index = avatarIndex + increment;
     if (index < 0) {
       index = 0;
     } else if (index >= avatars.size()) {
       index = avatars.size() - 1;
     }
     DrawableAvatar drawable = null;
     for (DrawableAvatar avatar : drawableAvatars) {
       if (avatar.index == index) {
         drawable = avatar;
         break;
       }
     }
     if (drawable != null) {
       scrollAndAnimate(drawable);
     }
   }
 }
 private void scrollAndAnimate(DrawableAvatar avatar) {
   if (loadingDone) {
     scrollerTimer = new Timer(10, new AutoScroller(avatar));
     scrollerTimer.start();
   }
 }
 private BufferedImage createReflectedPicture(BufferedImage avatar) {
   int avatarWidth = avatar.getWidth();
   int avatarHeight = avatar.getHeight();
   BufferedImage alphaMask = createGradientMask(avatarWidth, avatarHeight);
   return createReflectedPicture(avatar, alphaMask);
 }
 private BufferedImage createReflectedPicture(BufferedImage avatar, BufferedImage alphaMask) {
   int avatarWidth = avatar.getWidth();
   int avatarHeight = avatar.getHeight();
   BufferedImage buffer = createReflection(avatar, avatarWidth, avatarHeight);
   applyAlphaMask(buffer, alphaMask, avatarWidth, avatarHeight);
   return buffer;
 }
 private void applyAlphaMask(BufferedImage buffer, BufferedImage alphaMask, int avatarWidth,
     int avatarHeight) {
   Graphics2D g2 = buffer.createGraphics();
   g2.setComposite(AlphaComposite.DstOut);
   g2.drawImage(alphaMask, null, 0, avatarHeight);
   g2.dispose();
 }
 private BufferedImage createReflection(BufferedImage avatar, int avatarWidth, int avatarHeight) {
   BufferedImage buffer = new BufferedImage(avatarWidth, avatarHeight << 1,
       BufferedImage.TYPE_INT_ARGB);
   Graphics2D g = buffer.createGraphics();
   g.drawImage(avatar, null, null);
   g.translate(0, avatarHeight << 1);
   AffineTransform reflectTransform = AffineTransform.getScaleInstance(1.0, -1.0);
   g.drawImage(avatar, reflectTransform, null);
   g.translate(0, -(avatarHeight << 1));
   g.dispose();
   return buffer;
 }
 private BufferedImage createGradientMask(int avatarWidth, int avatarHeight) {
   BufferedImage gradient = new BufferedImage(avatarWidth, avatarHeight,
       BufferedImage.TYPE_INT_ARGB);
   Graphics2D g = gradient.createGraphics();
   GradientPaint painter = new GradientPaint(0.0f, 0.0f, new Color(1.0f, 1.0f, 1.0f, 0.5f), 0.0f,
       avatarHeight / 2.0f, new Color(1.0f, 1.0f, 1.0f, 1.0f));
   g.setPaint(painter);
   g.fill(new Rectangle2D.Double(0, 0, avatarWidth, avatarHeight));
   g.dispose();
   return gradient;
 }
 private DrawableAvatar getHitAvatar(int x, int y) {
   for (DrawableAvatar avatar : drawableAvatars) {
     Rectangle hit = new Rectangle((int) avatar.getX(), (int) avatar.getY(), avatar.getWidth(),
         avatar.getHeight() / 2);
     if (hit.contains(x, y)) {
       return avatar;
     }
   }
   return null;
 }
 private class PicturesFinderThread implements Runnable {
   public void run() {
     UnixGlobFileFilter allPngs = new UnixGlobFileFilter("*.jpg");
     try {
       FileTreeWalker walker = new FileTreeWalker(new File("."), allPngs);
       PictureLoader loader = new PictureLoader();
       walker.walk(loader);
       List<File> files = loader.getFilesList();
       for (int i = 0; i < files.size(); i++) {
         BufferedImage image = ImageIO.read(files.get(i));
         avatars.add(createReflectedPicture(image));
         if (i == (files.size() / 2) + avatarAmount / 2) {
           setAvatarIndex(i - avatarAmount / 2);
           startFader();
         }
       }
     } catch (IOException e) {
     }
     loadingDone = true;
   }
   private class PictureLoader implements FileTreeWalk {
     private List<File> filesList;
     private PictureLoader() {
       filesList = new ArrayList<File>();
     }
     private List<File> getFilesList() {
       Collections.sort(filesList);
       return filesList;
     }
     public void walk(File path) {
       filesList.add(path);
     }
   }
 }
 private class FaderAction implements ActionListener {
   private long start = 0;
   private FaderAction() {
     alphaLevel = 0.0f;
     textAlphaLevel = 0.0f;
   }
   public void actionPerformed(ActionEvent e) {
     if (start == 0) {
       start = System.currentTimeMillis();
     }
     alphaLevel = (System.currentTimeMillis() - start) / 500.0f;
     textAlphaLevel = alphaLevel;
     if (alphaLevel > 1.0f) {
       alphaLevel = 1.0f;
       textAlphaLevel = 1.0f;
       faderTimer.stop();
     }
     repaint();
   }
 }
 private class DrawableAvatar implements Comparable {
   private int index;
   private double x;
   private double y;
   private int width;
   private int height;
   private double zOrder;
   private double position;
   private DrawableAvatar(int index, double x, double y, int width, int height, double position,
       double zOrder) {
     this.index = index;
     this.x = x;
     this.y = y;
     this.width = width;
     this.height = height;
     this.position = position;
     this.zOrder = zOrder;
   }
   public int compareTo(Object o) {
     double zOrder2 = ((DrawableAvatar) o).zOrder;
     if (zOrder < zOrder2) {
       return -1;
     } else if (zOrder > zOrder2) {
       return 1;
     }
     return 0;
   }
   public double getPosition() {
     return position;
   }
   public double getAlpha() {
     return zOrder * alphaLevel;
   }
   public int getHeight() {
     return height;
   }
   public int getIndex() {
     return index;
   }
   public int getWidth() {
     return width;
   }
   public double getX() {
     return x;
   }
   public double getY() {
     return y;
   }
 }
 private class MouseWheelScroller implements MouseWheelListener {
   public void mouseWheelMoved(MouseWheelEvent e) {
     int increment = e.getWheelRotation();
     scrollAndAnimateBy(increment);
   }
 }
 private class KeyScroller extends KeyAdapter {
   @Override
   public void keyPressed(KeyEvent e) {
     int keyCode = e.getKeyCode();
     switch (keyCode) {
     case KeyEvent.VK_LEFT:
     case KeyEvent.VK_UP:
       scrollAndAnimateBy(-1);
       break;
     case KeyEvent.VK_RIGHT:
     case KeyEvent.VK_DOWN:
       scrollAndAnimateBy(1);
       break;
     case KeyEvent.VK_END:
       scrollBy(avatars.size() - avatarIndex - 1);
       break;
     case KeyEvent.VK_HOME:
       scrollBy(-avatarIndex - 1);
       break;
     case KeyEvent.VK_PAGE_UP:
       scrollAndAnimateBy(-avatarAmount / 2);
       break;
     case KeyEvent.VK_PAGE_DOWN:
       scrollAndAnimateBy(avatarAmount / 2);
       break;
     }
   }
 }
 private class FocusGrabber extends MouseAdapter {
   @Override
   public void mouseClicked(MouseEvent e) {
     requestFocus();
   }
 }
 private class AvatarScroller extends MouseAdapter {
   @Override
   public void mouseClicked(MouseEvent e) {
     if ((faderTimer != null && faderTimer.isRunning())
         || (scrollerTimer != null && scrollerTimer.isRunning()) || drawableAvatars == null) {
       return;
     }
     if (e.getButton() == MouseEvent.BUTTON1) {
       DrawableAvatar avatar = getHitAvatar(e.getX(), e.getY());
       if (avatar != null && avatar.getIndex() != avatarIndex) {
         scrollAndAnimate(avatar);
       }
     }
   }
 }
 private class DamageManager extends ComponentAdapter {
   @Override
   public void componentResized(ComponentEvent e) {
     damaged = true;
   }
 }
 private class AutoScroller implements ActionListener {
   private double position;
   private int index;
   private long start;
   private AutoScroller(DrawableAvatar avatar) {
     this.index = avatar.getIndex();
     this.position = avatar.getPosition();
     this.start = System.currentTimeMillis();
   }
   public void actionPerformed(ActionEvent e) {
     long elapsed = System.currentTimeMillis() - start;
     if (elapsed < ANIM_SCROLL_DELAY / 2.0) {
       textAlphaLevel = (float) (1.0 - 2.0 * (elapsed / ANIM_SCROLL_DELAY));
     } else {
       textAlphaLevel = (float) (((elapsed / ANIM_SCROLL_DELAY) - 0.5) * 2.0);
       if (textAlphaLevel > 1.0f) {
         textAlphaLevel = 1.0f;
       }
     }
     if (textAlphaLevel < 0.1f) {
       textAlphaLevel = 0.1f;
       textAvatar = "LoginName" + index;
     }
     double newPosition = (elapsed / ANIM_SCROLL_DELAY) * -position;
     if (elapsed >= ANIM_SCROLL_DELAY) {
       ((Timer) e.getSource()).stop();
       setAvatarIndex(index);
       setPosition(0.0);
       return;
     }
     setPosition(newPosition);
   }
 }
 private class CursorChanger extends MouseMotionAdapter {
   @Override
   public void mouseMoved(MouseEvent e) {
     if ((scrollerTimer != null && scrollerTimer.isRunning()) || drawableAvatars == null) {
       return;
     }
     DrawableAvatar avatar = getHitAvatar(e.getX(), e.getY());
     if (avatar != null) {
       getParent().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
     } else {
       getParent().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
     }
   }
 }

} /*

* Copyright (c) 2007, Romain Guy All rights reserved.
* 
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*  * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. * Neither the name of the
* TimingFramework project nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior
* written permission.
* 
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

class CurvesPanel extends JPanel {

 protected RenderingHints hints;
 protected int counter = 0;
 protected Color start = new Color(255, 255, 255, 200);
 protected Color end = new Color(255, 255, 255, 0);
 public CurvesPanel() {
   this(new BorderLayout());
 }
 public CurvesPanel(LayoutManager manager) {
   super(manager);
   hints = createRenderingHints();
 }
 protected RenderingHints createRenderingHints() {
   RenderingHints hints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,
       RenderingHints.VALUE_ANTIALIAS_ON);
   hints.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
   hints.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
   return hints;
 }
 public void animate() {
   counter++;
 }
 @Override
 public boolean isOpaque() {
   return false;
 }
 @Override
 protected void paintComponent(Graphics g) {
   Graphics2D g2 = (Graphics2D) g;
   RenderingHints oldHints = g2.getRenderingHints();
   g2.setRenderingHints(hints);
   float width = getWidth();
   float height = getHeight();
   g2.translate(0, -30);
   drawCurve(g2, 20.0f, -10.0f, 20.0f, -10.0f, width / 2.0f - 40.0f, 10.0f, 0.0f, -5.0f,
       width / 2.0f + 40, 1.0f, 0.0f, 5.0f, 50.0f, 5.0f, false);
   g2.translate(0, 30);
   g2.translate(0, height - 60);
   drawCurve(g2, 30.0f, -15.0f, 50.0f, 15.0f, width / 2.0f - 40.0f, 1.0f, 15.0f, -25.0f,
       width / 2.0f, 1.0f / 2.0f, 0.0f, 25.0f, 15.0f, 9.0f, false);
   g2.translate(0, -height + 60);
   drawCurve(g2, height - 35.0f, -5.0f, height - 50.0f, 10.0f, width / 2.0f - 40.0f, 1.0f,
       height - 35.0f, -25.0f, width / 2.0f, 1.0f / 2.0f, height - 20.0f, 25.0f, 25.0f, 7.0f, true);
   g2.setRenderingHints(oldHints);
 }
 protected void drawCurve(Graphics2D g2, float y1, float y1_offset, float y2, float y2_offset,
     float cx1, float cx1_offset, float cy1, float cy1_offset, float cx2, float cx2_offset,
     float cy2, float cy2_offset, float thickness, float speed, boolean invert) {
   float width = getWidth();
   float offset = (float) Math.sin(counter / (speed * Math.PI));
   float start_x = 0.0f;
   float start_y = offset * y1_offset + y1;
   float end_x = width;
   float end_y = offset * y2_offset + y2;
   float ctrl1_x = offset * cx1_offset + cx1;
   float ctrl1_y = offset * cy1_offset + cy1;
   float ctrl2_x = offset * cx2_offset + cx2;
   float ctrl2_y = offset * cy2_offset + cy2;
   GeneralPath thickCurve = new GeneralPath();
   thickCurve.moveTo(start_x, start_y);
   thickCurve.curveTo(ctrl1_x, ctrl1_y, ctrl2_x, ctrl2_y, end_x, end_y);
   thickCurve.lineTo(end_x, end_y + thickness);
   thickCurve.curveTo(ctrl2_x, ctrl2_y + thickness, ctrl1_x, ctrl1_y + thickness, start_x, start_y
       + thickness);
   thickCurve.lineTo(start_x, start_y);
   Rectangle bounds = thickCurve.getBounds();
   if (!bounds.intersects(g2.getClipBounds())) {
     return;
   }
   GradientPaint painter = new GradientPaint(0, bounds.y, invert ? end : start, 0, bounds.y
       + bounds.height, invert ? start : end);
   Paint oldPainter = g2.getPaint();
   g2.setPaint(painter);
   g2.fill(thickCurve);
   g2.setPaint(oldPainter);
 }

} /*

* Copyright (c) 2007, Romain Guy All rights reserved.
* 
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*  * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. * Neither the name of the
* TimingFramework project nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior
* written permission.
* 
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

class GradientPanel extends JPanel {

 protected BufferedImage gradientImage;
 protected Color gradientStart = new Color(204, 249, 124);
 protected Color gradientEnd = new Color(174, 222, 94);
 public GradientPanel() {
   this(new BorderLayout());
 }
 public GradientPanel(LayoutManager layout) {
   super(layout);
   addComponentListener(new GradientCacheManager());
 }
 @Override
 protected void paintComponent(Graphics g) {
   createImageCache();
   if (gradientImage != null) {
     g.drawImage(gradientImage, 0, 0, getWidth(), getHeight(), null);
   }
 }
 protected void createImageCache() {
   int width = 2;
   int height = getHeight();
   if (width == 0 || height == 0) {
     return;
   }
   if (gradientImage == null || width != gradientImage.getWidth()
       || height != gradientImage.getHeight()) {
     gradientImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
     Graphics2D g2 = gradientImage.createGraphics();
     GradientPaint painter = new GradientPaint(0, 0, gradientEnd, 0, height / 2, gradientStart);
     g2.setPaint(painter);
     Rectangle2D rect = new Rectangle2D.Double(0, 0, width, height / 2.0);
     g2.fill(rect);
     painter = new GradientPaint(0, height / 2, gradientStart, 0, height, gradientEnd);
     g2.setPaint(painter);
     rect = new Rectangle2D.Double(0, (height / 2.0) - 1.0, width, height);
     g2.fill(rect);
     g2.dispose();
   }
 }
 private void disposeImageCache() {
   synchronized (gradientImage) {
     gradientImage.flush();
     gradientImage = null;
   }
 }
 private class GradientCacheManager implements ComponentListener {
   public void componentResized(ComponentEvent e) {
   }
   public void componentMoved(ComponentEvent e) {
   }
   public void componentShown(ComponentEvent e) {
   }
   public void componentHidden(ComponentEvent e) {
     disposeImageCache();
   }
 }

} /*

* Copyright (c) 2007, Romain Guy All rights reserved.
* 
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*  * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. * Neither the name of the
* TimingFramework project nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior
* written permission.
* 
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

/**

* 
* @author Romain Guy <romain.guy@mac.ru>
*/

class StackLayout implements LayoutManager2 {

 public static final String BOTTOM = "bottom";
 public static final String TOP = "top";
 private List<Component> components = new LinkedList<Component>();
 public void addLayoutComponent(Component comp, Object constraints) {
   synchronized (comp.getTreeLock()) {
     if (BOTTOM.equals(constraints)) {
       components.add(0, comp);
     } else if (TOP.equals(constraints)) {
       components.add(comp);
     } else {
       components.add(comp);
     }
   }
 }
 public void addLayoutComponent(String name, Component comp) {
   addLayoutComponent(comp, TOP);
 }
 public void removeLayoutComponent(Component comp) {
   synchronized (comp.getTreeLock()) {
     components.remove(comp);
   }
 }
 public float getLayoutAlignmentX(Container target) {
   return 0.5f;
 }
 public float getLayoutAlignmentY(Container target) {
   return 0.5f;
 }
 public void invalidateLayout(Container target) {
 }
 public Dimension preferredLayoutSize(Container parent) {
   synchronized (parent.getTreeLock()) {
     int width = 0;
     int height = 0;
     for (Component comp : components) {
       Dimension size = comp.getPreferredSize();
       width = Math.max(size.width, width);
       height = Math.max(size.height, height);
     }
     Insets insets = parent.getInsets();
     width += insets.left + insets.right;
     height += insets.top + insets.bottom;
     return new Dimension(width, height);
   }
 }
 public Dimension minimumLayoutSize(Container parent) {
   synchronized (parent.getTreeLock()) {
     int width = 0;
     int height = 0;
     for (Component comp : components) {
       Dimension size = comp.getMinimumSize();
       width = Math.max(size.width, width);
       height = Math.max(size.height, height);
     }
     Insets insets = parent.getInsets();
     width += insets.left + insets.right;
     height += insets.top + insets.bottom;
     return new Dimension(width, height);
   }
 }
 public Dimension maximumLayoutSize(Container target) {
   return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
 }
 public void layoutContainer(Container parent) {
   synchronized (parent.getTreeLock()) {
     int width = parent.getWidth();
     int height = parent.getHeight();
     Rectangle bounds = new Rectangle(0, 0, width, height);
     int componentsCount = components.size();
     for (int i = 0; i < componentsCount; i++) {
       Component comp = components.get(i);
       comp.setBounds(bounds);
       parent.setComponentZOrder(comp, componentsCount - i - 1);
     }
   }
 }

} /*

* Copyright (c) 2007, Romain Guy All rights reserved.
* 
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*  * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. * Neither the name of the
* TimingFramework project nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior
* written permission.
* 
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

class FileTreeWalker {

 private File path;
 private static final FileFilter directoryFilter = new FileFilter() {
   public boolean accept(File pathname) {
     return pathname.isDirectory();
   }
 };
 private FileFilter filter;
 public FileTreeWalker(File path) throws IOException {
   this(path, new FileFilter() {
     public boolean accept(File pathname) {
       return pathname.isFile();
     }
   });
 }
 public FileTreeWalker(File path, FileFilter filter) throws IOException {
   if (path == null || !path.exists() || path.isFile()) {
     throw new IOException("Path " + path + " is not a valid directory.");
   }
   this.path = path;
   this.filter = filter;
 }
 public void walk(FileTreeWalk walk) {
   walkDirectory(walk, path);
 }
 private void walkDirectory(FileTreeWalk walk, File dir) {
   File[] files = dir.listFiles(filter);
   for (File file : files) {
     walk.walk(file);
   }
   File[] dirs = dir.listFiles(directoryFilter);
   for (File subDir : dirs) {
     walkDirectory(walk, subDir);
   }
 }

} /*

* Copyright (c) 2007, Romain Guy All rights reserved.
* 
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*  * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. * Neither the name of the
* TimingFramework project nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior
* written permission.
* 
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

interface FileTreeWalk {

 public void walk(File path);

} /*

* Copyright (c) 2007, Romain Guy All rights reserved.
* 
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*  * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer. * Redistributions in
* binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution. * Neither the name of the
* TimingFramework project nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior
* written permission.
* 
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

/**

* @author Romain Guy
*/

class UnixGlobFileFilter implements FileFilter {

 private Pattern pattern;
 public UnixGlobFileFilter(String filter) {
   pattern = Pattern.rupile(globToRegex(filter));
 }
 public boolean accept(File file) {
   String path = file.getName();
   Matcher matcher = pattern.matcher(path);
   return matcher.matches();
 }
 private String globToRegex(String glob) {
   char c = "\0";
   boolean escape = false;
   boolean enclosed = false;
   StringBuffer buffer = new StringBuffer(glob.length());
   for (int i = 0; i < glob.length(); i++) {
     c = glob.charAt(i);
     if (escape) {
       buffer.append("\\");
       buffer.append(c);
       escape = false;
       continue;
     }
     switch (c) {
     case "*":
       buffer.append(".").append("*");
       break;
     case "?":
       buffer.append(".");
       break;
     case "\\":
       escape = true;
       break;
     case ".":
       buffer.append("\\").append(".");
       break;
     case "{":
       buffer.append("(");
       enclosed = true;
       break;
     case "}":
       buffer.append(")");
       enclosed = false;
       break;
     case ",":
       if (enclosed)
         buffer.append("|");
       else
         buffer.append(",");
       break;
     default:
       buffer.append(c);
     }
   }
   return buffer.toString();
 }

}


</source>
   
  
 
  



Clock

   <source lang="java">

import java.util.Calendar; import java.util.Timer; import java.util.TimerTask; import java.awt.*; import javax.swing.*; import no.geosoft.cc.geometry.Geometry; import no.geosoft.cc.geometry.Matrix4x4; import no.geosoft.cc.graphics.*;

/**

* G demo program. Demonstrates:
*
*
    *
  • Advaced geometry generation *
  • Dynamic update *
  • Threading *
* 
* @author 


Curve Animation

   <source lang="java">

import java.awt.*; import java.applet.*; import graph.*; /*************************************************************************

    • Applet example0
    • Version 1.0 January 1996
    • Copyright (C) 1996 Leigh Brookshaw
    • This program is free software; you can redistribute it and/or modify
    • it under the terms of the GNU General Public License as published by
    • the Free Software Foundation; either version 2 of the License, or
    • (at your option) any later version.
    • This program is distributed in the hope that it will be useful,
    • but WITHOUT ANY WARRANTY; without even the implied warranty of
    • MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    • GNU General Public License for more details.
    • You should have received a copy of the GNU General Public License
    • along with this program; if not, write to the Free Software
    • Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
                                                                                                                                                  • /

public class example0 extends Applet implements Runnable {

     Graph2D graph;
     DataSet data;
     double max;
     double min;
     int steps;
     Thread thread;
     public void init() {
       int i;
       int j;
       graph = new Graph2D();
       setLayout( new BorderLayout() );
       add("Center", graph);
       graph.framecolor = new Color(0,0,0);
       graph.borderTop = 0;
       graph.borderBottom = 1;
       graph.borderLeft = 0;
       graph.borderRight = 1;
       graph.setGraphBackground(new Color(50,50,200));
       max = 15*Math.PI;
       min = Math.PI;
       steps = 20;
       thread = new Thread(this);
       thread.start();
     }
     public void run() {
         DataSet data = null;
         int count = 1;
         int direction = 1;
         double range;
         Color c = new Color(255,255,0);
         
         while(true) {
             graph.detachDataSet(data);
             data = null;
             if(count >= steps ) direction = -1;
             else
             if(count <= 0 )     direction = 1;
             count += direction;
             range = min + (max-min)*count/steps;

// System.out.println("Range="+range);

             data = sinx(range);

// data.xmax = max; // data.xmin = -max;

             data.ymax = 1.0;
             data.linecolor = c;              
             graph.repaint(75);
             try { thread.sleep(150); }
             catch(Exception e) { }
         }
     }
     public DataSet sinx(double range) {
           int i, j;
           int np = 100;
           double data[] = new double[2*np];
           double x, y;
           
           for(i=j=0; i<np; i++,j+=2) {
               x = (i-np/2)*range/(np/2);
               if( x == 0.0 )  y = 1.0;
               else           y = Math.sin(x)/x;
               data[j]   = x;
               data[j+1] = y;
           }
           
           return graph.loadDataSet(data,np);
     }
     public static void main(String[] a){
        javax.swing.JFrame f = new javax.swing.JFrame();
        Applet app = new example0();
        app.init();
        
        f.getContentPane().add (app);
        f.pack();
        f.setSize (new Dimension (500, 500));
        f.setVisible(true);
     }

}

      </source>
   
  
 
  



Custom move interaction, Switching interactions, Update world extent geometry and Scroll handling

   <source lang="java">

import java.awt.*; import java.awt.event.*; import javax.swing.*; import no.geosoft.cc.geometry.Geometry; import no.geosoft.cc.graphics.*;

/**

* G demo program. Demonstrates:
*
*
    *
  • Custom move interaction *
  • Switching interactions *
  • Update world extent geometry *
  • Scroll handling *
* 
* @author 


Moving Button

   <source lang="java">


import java.awt.Color; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; import javax.swing.Timer; /*

* MovingButton.java
*
* Created on May 2, 2007, 4:17 PM
*
* Copyright (c) 2007, Sun Microsystems, Inc
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the TimingFramework project nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**

*
* @author Chet
*/

public class MovingButton extends JButton implements ActionListener {

   Timer timer;                        // for later start/stop actions
   int animationDuration = 2000;   // each animation will take 2 seconds
   long animStartTime;     // start time for each animation
   int translateY = 0;                 // y location of the button
   static final int MAX_Y = 100;
   
   /** Creates a new instance of TranslucentButton */
   public MovingButton(String label) {
       super(label);
       setOpaque(false);
       timer = new Timer(30, this);
       addActionListener(this);
   }
   
   /**
    * Displays our component in the location (0, translateY). Note that
    * this changes only the rendering location of the button, not the
    * physical location of it. Note, also, that rendering into g will
    * be clipped to the physical location of the button, so the button will
    * disappear as it moves away from that location.
    */
   public void paint(Graphics g) {
       g.translate(0, translateY);
       super.paint(g);
   }
   
   /**
    * This method handles both button clicks, which start/stop the animation,
    * and Swing Timer events.
    */
   public void actionPerformed(ActionEvent ae) {
       if (ae.getSource().equals(this)) {
           // button click
           if (!timer.isRunning()) {
               animStartTime = System.nanoTime() / 1000000;
               this.setText("Stop Animation");
               timer.start();
           } else {
               timer.stop();
               this.setText("Start Animation");
               // reset translation to 0
               translateY = 0;
           }
       } else {
           // Timer event
           // calculate the elapsed fraction
           long currentTime = System.nanoTime() / 1000000;
           long totalTime = currentTime - animStartTime;
           if (totalTime > animationDuration) {
               animStartTime = currentTime;
           }
           float fraction = (float)totalTime / animationDuration;
           fraction = Math.min(1.0f, fraction);
           // This calculation will cause translateY to go from 0 to MAX_Y
           // as the fraction goes from 0 to 1
           if (fraction < .5f) {
               translateY = (int)(MAX_Y * (2 * fraction));
           } else {
               translateY = (int)(MAX_Y * (2 * (1 - fraction)));
           }
           // redisplay our component with the new location
           repaint();
       }
   }
   private static void createAndShowGUI() {
       JFrame f = new JFrame("Moving Button");
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.setSize(300, 300);
       JPanel checkerboard = new Checkerboard();
       checkerboard.add(new MovingButton("Start Animation"));
       f.add(checkerboard);
       f.setVisible(true);
   }
   
   public static void main(String args[]) {
       Runnable doCreateAndShowGUI = new Runnable() {
           public void run() {
               createAndShowGUI();
           }
       };
       SwingUtilities.invokeLater(doCreateAndShowGUI);
   }
   /**
    * Paints a checkerboard background
    */
   private static class Checkerboard extends JPanel {
       private static final int DIVISIONS = 10;
       static final int CHECKER_SIZE = 60;
       public void paintComponent(Graphics g) {
           g.setColor(Color.white);
           g.fillRect(0, 0, getWidth(), getHeight());
           g.setColor(Color.BLACK);
           for (int stripeX = 0; stripeX < getWidth(); stripeX += CHECKER_SIZE) {
               for (int y = 0, row = 0; y < getHeight(); y += CHECKER_SIZE/2, ++row) {
                   int x = (row % 2 == 0) ? stripeX : (stripeX + CHECKER_SIZE/2);
                   g.fillRect(x, y, CHECKER_SIZE/2, CHECKER_SIZE/2);
               }
           }
       }
   }

}

</source>
   
  
 
  



Moving Button Container

   <source lang="java">


import java.awt.Color; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.SwingUtilities; import javax.swing.Timer; /*

* MovingButtonContainer.java
*
* Created on May 2, 2007, 4:39 PM
*
* Copyright (c) 2007, Sun Microsystems, Inc
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the TimingFramework project nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**

*
* @author Chet
*/

public class MovingButtonContainer extends JComponent implements ActionListener {

   Timer timer;                        // for later start/stop actions
   int animationDuration = 2000;   // each animation will take 2 seconds
   long animStartTime;     // start time for each animation
   int translateY = 0;                 // current Y location of button
   static final int MAX_Y = 100;
   JButton button = null;
   private static final int DIVISIONS = 10;
   static final int CHECKER_SIZE = 60;
   
   /** Creates a new instance of TranslucentButton */
   public MovingButtonContainer() {
       setLayout(new java.awt.FlowLayout());
       timer = new Timer(30, this);
       button = new JButton("Start Animation");
       // Need setOpaque(false) to force Swing to paint the button"s parent
       button.setOpaque(false);
       button.addActionListener(this);
       add(button);
   }
   
   /**
    * This method handles both button clicks, which start/stop the animation,
    * and Swing Timer events, which animate translateY.
    */
   public void actionPerformed(ActionEvent ae) {
       if (ae.getSource().equals(button)) {
           // button click
           if (!timer.isRunning()) {
               animStartTime = System.nanoTime() / 1000000;
               button.setText("Stop Animation");
               timer.start();
           } else {
               timer.stop();
               button.setText("Start Animation");
               // reset translation to 0
               translateY = 0;
               // Must force repaint to get final animated position erased
               repaint();
           }
       } else {
           // Timer event
           // calculate elapsed fraction
           long currentTime = System.nanoTime() / 1000000;
           long totalTime = currentTime - animStartTime;
           if (totalTime > animationDuration) {
               animStartTime = currentTime;
           }
           float fraction = (float)totalTime / animationDuration;
           fraction = Math.min(1.0f, fraction);
           // This calculation will cause translateY to go from 0 to MAX_Y
           // as the fraction goes from 0 to 1
            if (fraction < .5f) {
               translateY = (int)(MAX_Y * (2 * fraction));
           } else {
               translateY = (int)(MAX_Y * (2 * (1 - fraction)));
           }
           // redisplay our container to paint the button in the new location
           repaint();
       }
   }
   
   /**
    * Paint our container with a checkerboard background. Then set a
    * translation factor on the Graphics object and call the superclass,
    * which will paint the children (e.g, our button) with this 
    * translation.
    */
   public void paint(Graphics g) {
       g.setColor(Color.white);
       g.fillRect(0, 0, getWidth(), getHeight());
       g.setColor(Color.BLACK);
       for (int stripeX = 0; stripeX < getWidth(); stripeX += CHECKER_SIZE) {
           for (int y = 0, row = 0; y < getHeight(); y += CHECKER_SIZE/2, ++row) {
               int x = (row % 2 == 0) ? stripeX : (stripeX + CHECKER_SIZE/2);
               g.fillRect(x, y, CHECKER_SIZE/2, CHECKER_SIZE/2);
           }
       }
       // Translate our graphics according to the animated translateY value
       g.translate(0, translateY);
       // Defer to superclass to handle painting for component, which includes
       // painting the children of this container
       super.paint(g);
   }
   private static void createAndShowGUI() {
       JFrame f = new JFrame("Moving Button Container");
       f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       f.setSize(300, 300);
       JComponent buttonContainer = new MovingButtonContainer();
       f.add(buttonContainer);
       f.setVisible(true);
   }
   
   public static void main(String args[]) {
       Runnable doCreateAndShowGUI = new Runnable() {
           public void run() {
               createAndShowGUI();
           }
       };
       SwingUtilities.invokeLater(doCreateAndShowGUI);
   }

}

</source>
   
  
 
  



Scroll Handling

   <source lang="java">

import java.awt.*; import java.awt.event.*; import javax.swing.*; import no.geosoft.cc.geometry.Geometry; import no.geosoft.cc.graphics.*;

/**

* G demo program. Demonstrates:
*
*
    *
  • Custom move interaction *
  • Switching interactions *
  • Update world extent geometry *
  • Scroll handling *
* 
* @author 


Simple animation technique

   <source lang="java">

import java.awt.*; import javax.swing.*; import no.geosoft.cc.geometry.Geometry; import no.geosoft.cc.geometry.Matrix4x4; import no.geosoft.cc.graphics.*;

/**

* G demo program. Demonstrates:
*
*
    *
  • Simple animation technique *
* 
* @author 


Smooth Moves

   <source lang="java">



import java.awt.AlphaComposite; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GraphicsConfiguration; import java.awt.Image; import java.awt.Transparency; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.image.BufferedImage; import java.net.URL; import javax.imageio.ImageIO; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.SwingUtilities; import javax.swing.Timer; /*

* SmoothMoves.java
*
* Created on May 2, 2007, 4:49 PM
*
* Copyright (c) 2007, Sun Microsystems, Inc
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the TimingFramework project nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

/**

* 
* @author Chet
*/

public class SmoothMoves extends JComponent implements ActionListener, KeyListener {

 /** image holds the graphics we render for each animating object */
 BufferedImage image = null;
 static int imageW = 100;
 static int imageH = 150;
 /** Location of fading animation */
 int fadeX = 50;
 int fadeY = 50;
 /** X values that moving animation will move between */
 static int moveMinX = 150;
 static int moveMaxX = 350;
 /** Current x/y location of moving animation */
 int moveX = moveMinX;
 int moveY = 50;
 /** Current opacity of fading animation */
 float opacity = 0.0f;
 /** Toggles for various demo options (key to toggle in parentheses) */
 boolean useImage = false; // (i) image instead of rectangle
 boolean useAA = false; // (a) anti-aliased edges (rectangle only)
 boolean motionBlur = false; // (b) ghost images behind moving animation
 boolean alterColor = false; // (c) light-gray instead of black rectangle
 boolean linear = true; // (l) linear vs. non-linear motion
 /** Used for motion blur rendering; holds information for ghost trail */
 int blurSize = 5;
 int prevMoveX[];
 int prevMoveY[];
 float trailOpacity[];
 /** Basic Timer animation info */
 final static int CYCLE_TIME = 2000; // One cycle takes 2 seconds
 int currentResolution = 50; // current Timer resolution
 Timer timer = null; // animation Timer
 long cycleStart; // track start time for each cycle
 /** Creates a new instance of SmoothAnimation */
 public SmoothMoves() {
   // createAnimationImage();
   cycleStart = System.nanoTime() / 1000000;
   startTimer(currentResolution);
 }
 /**
  * Create the image that will be animated. This image may be an actual image
  * (duke.gif), or some graphics (a variation on a black filled rectangle) that
  * are rendered into an image. The contents of this image are dependent upon
  * the runtime toggles that have been set when this method is called.
  */
 void createAnimationImage() {
   GraphicsConfiguration gc = getGraphicsConfiguration();
   image = gc.createCompatibleImage(imageW, imageH, Transparency.TRANSLUCENT);
   Graphics2D gImg = image.createGraphics();
   if (useImage) {
     try {
       URL url = getClass().getResource("duke.gif");
       Image originalImage = ImageIO.read(url);
       gImg.drawImage(originalImage, 0, 0, imageW, imageH, null);
     } catch (Exception e) {
     }
   } else {
     // use graphics
     Color graphicsColor;
     if (alterColor) {
       graphicsColor = Color.LIGHT_GRAY;
     } else {
       graphicsColor = Color.BLACK;
     }
     gImg.setColor(graphicsColor);
     gImg.fillRect(0, 0, imageW, imageH);
     if (useAA) {
       // Antialiasing hack - just draw a fading-out border around the
       // rectangle
       gImg.setComposite(AlphaComposite.Src);
       int red = graphicsColor.getRed();
       int green = graphicsColor.getRed();
       int blue = graphicsColor.getRed();
       gImg.setColor(new Color(red, green, blue, 50));
       gImg.drawRect(0, 0, imageW - 1, imageH - 1);
       gImg.setColor(new Color(red, green, blue, 100));
       gImg.drawRect(1, 1, imageW - 3, imageH - 3);
       gImg.setColor(new Color(red, green, blue, 150));
       gImg.drawRect(2, 2, imageW - 5, imageH - 5);
       gImg.setColor(new Color(red, green, blue, 200));
       gImg.drawRect(3, 3, imageW - 7, imageH - 7);
       gImg.setColor(new Color(red, green, blue, 225));
       gImg.drawRect(4, 4, imageW - 9, imageH - 9);
     }
   }
   gImg.dispose();
 }
 public void paintComponent(Graphics g) {
   if (image == null) {
     createAnimationImage();
   }
   // Erase the background
   g.setColor(Color.WHITE);
   g.fillRect(0, 0, getWidth(), getHeight());
   // Draw the fading image
   Graphics2D gFade = (Graphics2D) g.create();
   gFade.setComposite(AlphaComposite.SrcOver.derive(opacity));
   gFade.drawImage(image, fadeX, fadeY, null);
   gFade.dispose();
   // Draw the moving image
   if (motionBlur) {
     // Draw previous locations of the image as a trail of
     // ghost images
     if (prevMoveX == null) {
       // blur location array not yet created; create it now
       prevMoveX = new int[blurSize];
       prevMoveY = new int[blurSize];
       trailOpacity = new float[blurSize];
       float incrementalFactor = .2f / (blurSize + 1);
       for (int i = 0; i < blurSize; ++i) {
         // default values, act as flag to not render these
         // until they have real values
         prevMoveX[i] = -1;
         prevMoveY[i] = -1;
         // vary the translucency by the number of the ghost
         // image; the further away it is from the current one,
         // the more faded it will be
         trailOpacity[i] = (.2f - incrementalFactor) - i * incrementalFactor;
       }
     } else {
       Graphics2D gTrail = (Graphics2D) g.create();
       for (int i = 0; i < blurSize; ++i) {
         if (prevMoveX[i] >= 0) {
           // Render each blur image with the appropriate
           // amount of translucency
           gTrail.setComposite(AlphaComposite.SrcOver.derive(trailOpacity[i]));
           gTrail.drawImage(image, prevMoveX[i], prevMoveY[i], null);
         }
       }
       gTrail.dispose();
     }
   }
   g.drawImage(image, moveX, moveY, null);
   if (motionBlur) {
     // shift the ghost positions to add the current position and
     // drop the oldest one
     for (int i = blurSize - 1; i > 0; --i) {
       prevMoveX[i] = prevMoveX[i - 1];
       prevMoveY[i] = prevMoveY[i - 1];
     }
     prevMoveX[0] = moveX;
     prevMoveY[0] = moveY;
   }
 }
 /**
  * This method handles the events from the Swing Timer
  */
 public void actionPerformed(ActionEvent ae) {
   // calculate the fraction elapsed of the animation and call animate()
   // to alter the values accordingly
   long currentTime = System.nanoTime() / 1000000;
   long totalTime = currentTime - cycleStart;
   if (totalTime > CYCLE_TIME) {
     cycleStart = currentTime;
   }
   float fraction = (float) totalTime / CYCLE_TIME;
   fraction = Math.min(1.0f, fraction);
   fraction = 1 - Math.abs(1 - (2 * fraction));
   animate(fraction);
 }
 /**
  * Animate the opacity and location factors, according to the current
  * fraction.
  */
 public void animate(float fraction) {
   float animationFactor;
   if (linear) {
     animationFactor = fraction;
   } else {
     // Our "nonlinear" motion just uses a sin function to get a
     // simple bounce behavior
     animationFactor = (float) Math.sin(fraction * (float) Math.PI / 2);
   }
   // Clamp the value to make sure it does not exceed the bounds
   animationFactor = Math.min(animationFactor, 1.0f);
   animationFactor = Math.max(animationFactor, 0.0f);
   // The opacity, used by the fading animation, will just use the
   // animation fraction directly
   opacity = animationFactor;
   // The move animation will calculate a location based on a linear
   // interpolation between its start and end points using the fraction
   moveX = moveMinX + (int) (.5f + animationFactor * (float) (moveMaxX - moveMinX));
   // redisplay our component with the new animated values
   repaint();
 }
 /**
  * Moves the frame rate up or down by changing the Timer resolution
  */
 private void changeResolution(boolean faster) {
   if (faster) {
     currentResolution -= 5;
   } else {
     currentResolution += 5;
   }
   currentResolution = Math.max(currentResolution, 0);
   currentResolution = Math.min(currentResolution, 500);
   startTimer(currentResolution);
 }
 /**
  * Starts the animation
  */
 private void startTimer(int resolution) {
   if (timer != null) {
     timer.stop();
     timer.setDelay(resolution);
   } else {
     timer = new Timer(resolution, this);
   }
   timer.start();
 }
 /**
  * Toggles various rendering flags
  */
 public void keyPressed(KeyEvent ke) {
   int keyCode = ke.getKeyCode();
   if (keyCode == KeyEvent.VK_B) {
     // B: Motion blur - displays trail of ghost images
     motionBlur = !motionBlur;
   } else if (keyCode == KeyEvent.VK_A) {
     // A: Antialiasing - Displays soft edges around graphics
     useAA = !useAA;
     createAnimationImage();
   } else if (keyCode == KeyEvent.VK_C) {
     // C: Color - Toggles rectangle color between dark and light colors
     alterColor = !alterColor;
     createAnimationImage();
   } else if (keyCode == KeyEvent.VK_I) {
     // I: Image - Toggles use of image or filled rectangle to show how
     // straight edges affect animation perception
     useImage = !useImage;
     createAnimationImage();
   } else if (keyCode == KeyEvent.VK_UP) {
     // Up Arrow: Speed - Speeds up frame rate
     changeResolution(true);
   } else if (keyCode == KeyEvent.VK_DOWN) {
     // Down Arrow: Speed - Slows down frame rate
     changeResolution(false);
   } else if (keyCode == KeyEvent.VK_L) {
     // L: Linearity: Toggles linear/nonlinear motion
     linear = !linear;
   } else if (keyCode >= KeyEvent.VK_1 && keyCode <= KeyEvent.VK_9) {
     // 0-9: Blur size: Toggles size of ghost trail for motion blur
     blurSize = keyCode - KeyEvent.VK_0;
     prevMoveX = prevMoveY = null;
   }
 }
 // Unused KeyListener implementations
 public void keyReleased(KeyEvent ke) {
 }
 public void keyTyped(KeyEvent ke) {
 }
 private static void createAndShowGUI() {
   JFrame f = new JFrame("Smooth Moves");
   f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   f.setSize(moveMaxX + imageW + 50, 300);
   SmoothMoves component = new SmoothMoves();
   f.add(component);
   f.setVisible(true);
   f.addKeyListener(component);
 }
 public static void main(String[] args) {
   Runnable doCreateAndShowGUI = new Runnable() {
     public void run() {
       createAndShowGUI();
     }
   };
   SwingUtilities.invokeLater(doCreateAndShowGUI);
 }

}

</source>