/*
* Copyright 2004 - 2008 Christian Sprajc. All rights reserved.
*
* This file is part of PowerFolder.
*
* PowerFolder 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.
*
* PowerFolder 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 PowerFolder. If not, see <http://www.gnu.org/licenses/>.
*
* $Id: RippleLabel.java 9547 2009-09-14 14:32:18Z tot $
*/
package de.dal33t.powerfolder.ui.dialog;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.ImageProducer;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import javax.swing.JLabel;
import de.dal33t.powerfolder.Controller;
/**
* This class displays an Image in a JLabel and animates a ripple effect when
* the mouse is moved over it. Based on some voodoo code by Neil Wallis.
* http://www.neilwallis.com/java/water.html
*/
public class RippleLabel extends JLabel {
private final int width;
private final int height;
private int[] imageTexture;
private ImageProducer source;
private short[] rippleMap;
private int[] rippleTexture;
private int oldInd;
private int newInd;
private volatile boolean active = true;
private ScheduledFuture<?> rippler;
/**
* Constructor
*
* @param controller
* @param image
*/
public RippleLabel(Controller controller, Image image) {
MediaTracker mediaTracker = new MediaTracker(this);
mediaTracker.addImage(image, 1);
try {
mediaTracker.waitForAll();
} catch (Exception e) {
}
width = image.getWidth(this);
height = image.getHeight(this);
int size = width * (height + 2) * 2;
PixelGrabber pg = new PixelGrabber(image, 0, 0, -1, -1, false);
try {
pg.grabPixels();
} catch (InterruptedException e) {
}
imageTexture = (int[]) pg.getPixels();
rippleMap = new short[size];
rippleTexture = new int[width * height];
source = new MemoryImageSource(width, height, rippleTexture, 0, width);
oldInd = width;
newInd = width * (height + 3);
addMouseMotionListener(new MyMouseListener());
rippler = controller.getThreadPool().scheduleAtFixedRate(new Runnable()
{
public void run() {
if (active) {
doRipple();
}
}
}, 10, 10, TimeUnit.MILLISECONDS);
}
public void deactivate() {
active = false;
rippler.cancel(false);
}
private void doRipple() {
// Do some random drops occasionally.
if (Math.random() > 0.999) {
int x = (int) (5 + (width - 10) * Math.random());
int y = (int) (5 + (height - 10) * Math.random());
drop(x, y);
}
// Toggle maps each frame
int i = oldInd;
oldInd = newInd;
newInd = i;
i = 0;
int mapind = oldInd;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
short data = (short) (rippleMap[mapind - width]
+ rippleMap[mapind + width] + rippleMap[mapind - 1]
+ rippleMap[mapind + 1] >> 1);
data -= rippleMap[newInd + i];
data -= data >> 5;
rippleMap[newInd + i] = data;
// Where data = 0 then still, where data > 0 then wave
data = (short) (1024 - data);
// Offsets
int a = (x - width / 2) * data / 1024 + width / 2;
int b = (y - height / 2) * data / 1024 + height / 2;
// Bounds check
if (a >= width) {
a = width - 1;
}
if (a < 0) {
a = 0;
}
if (b >= height) {
b = height - 1;
}
if (b < 0) {
b = 0;
}
rippleTexture[i] = imageTexture[a + b * width];
mapind++;
i++;
}
}
repaint();
}
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(createImage(source), 0, 0, width, height, this);
}
private void drop(int x, int y) {
for (int j = y - 3; j < y + 3; j++) {
for (int k = x - 3; k < x + 3; k++) {
if (j >= 0 && j < height && k >= 0 && k < width) {
rippleMap[oldInd + j * width + k] += 512;
}
}
}
}
private class MyMouseListener extends MouseAdapter {
public void mouseMoved(MouseEvent e) {
int x = e.getX();
int y = e.getY();
drop(x, y);
}
}
}