mirror of https://github.com/sipwise/jitsi.git
Fixes the issue with OTR padlock icon not being transparent when displaying .gifs for animation. Instead of .gif, a series of .png images will be displayed in a predetermined sequence.
parent
93f526c1b2
commit
fc55fff305
|
After Width: | Height: | Size: 455 B |
|
After Width: | Height: | Size: 454 B |
|
After Width: | Height: | Size: 452 B |
@ -0,0 +1,443 @@
|
||||
/*
|
||||
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.plugin.desktoputil;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.awt.image.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.Timer;
|
||||
|
||||
/**
|
||||
* AnimatedImage will display a series of Images in a predetermined sequence.
|
||||
* This sequence can be configured to keep repeating or stop after a specified
|
||||
* number of cycles.
|
||||
*
|
||||
* An AnimatedImage cannot be shared by different components. However,
|
||||
* the Images added to the AnimatedImage can be shared.
|
||||
*
|
||||
* The animation sequence is a simple sequential display of each Image. When the
|
||||
* end is reached the animation restarts at the first Image. Images are
|
||||
* displayed in the order in which they were added. To create custom animation
|
||||
* sequences you will need to override the getNextIconIndex() and
|
||||
* isCycleCompleted() methods.
|
||||
*
|
||||
* @author Marin Dzhigarov
|
||||
*/
|
||||
public class AnimatedImage
|
||||
extends BufferedImage
|
||||
implements ActionListener
|
||||
{
|
||||
/**
|
||||
* The default delay between switching over the next image.
|
||||
*/
|
||||
private final static int DEFAULT_DELAY = 500;
|
||||
|
||||
/**
|
||||
* The default number of cycles for the animation.
|
||||
* -1 means that the animation will go on forever.
|
||||
*/
|
||||
private final static int DEFAULT_CYCLES = -1;
|
||||
|
||||
/**
|
||||
* The list of actual images that are going to be displayed
|
||||
*/
|
||||
private List<Image> images = new ArrayList<Image>();
|
||||
|
||||
/**
|
||||
* The JComponent that will display the Image
|
||||
*/
|
||||
private JComponent component;
|
||||
|
||||
/**
|
||||
* The number of cycles for the animation.
|
||||
* -1 means that the animation will go on forever.
|
||||
*/
|
||||
private int cycles;
|
||||
|
||||
private boolean showFirstImage = false;
|
||||
|
||||
private int imageWidth;
|
||||
|
||||
private int imageHeight;
|
||||
|
||||
/**
|
||||
* The index of the currently displayed Image
|
||||
*/
|
||||
private int currentImageIndex;
|
||||
|
||||
/**
|
||||
* The current number of completed cycles. The animation will go on while
|
||||
* cyclesCompleted < cycles.
|
||||
*/
|
||||
private int cyclesCompleted;
|
||||
|
||||
private boolean animationFinished = true;
|
||||
|
||||
/**
|
||||
* The Timer that handles switching between Images.
|
||||
*/
|
||||
private Timer timer;
|
||||
|
||||
/**
|
||||
* The Graphics2D object used for painting.
|
||||
*/
|
||||
private final Graphics2D g2d;
|
||||
|
||||
/**
|
||||
* Create an AnimatedImage that will continuously cycle with the
|
||||
* default (500ms).
|
||||
*
|
||||
* @param component the component the image will be painted on
|
||||
* @param images the Images to be painted as part of the animation
|
||||
*/
|
||||
public AnimatedImage(JComponent component, Image... images)
|
||||
{
|
||||
this(component, DEFAULT_DELAY, images);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an AnimatedImage that will continuously cycle with the specified
|
||||
* delay
|
||||
*
|
||||
* @param component the component the image will be painted on
|
||||
* @param delay the delay between painting each image, in milli seconds
|
||||
* @param images the Images to be painted as part of the animation
|
||||
*/
|
||||
public AnimatedImage(JComponent component, int delay, Image... images)
|
||||
{
|
||||
this(component, delay, DEFAULT_CYCLES, images);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an AnimatedImage specifying the required delay between painting
|
||||
* each image and the number of times to repeat the animation sequence
|
||||
*
|
||||
* @param component the component the image will be painted on
|
||||
* @param delay the delay between painting each image, in milli seconds
|
||||
* @param cycles the number of times to repeat the animation sequence
|
||||
* @param images the Images to be painted as part of the animation
|
||||
*/
|
||||
public AnimatedImage(
|
||||
JComponent component, int delay, int cycles, Image... images)
|
||||
{
|
||||
super( images[0].getWidth(null),
|
||||
images[0].getHeight(null),
|
||||
BufferedImage.TYPE_INT_ARGB);
|
||||
|
||||
this.component = component;
|
||||
|
||||
g2d = (Graphics2D) getGraphics();
|
||||
|
||||
setCycles( cycles );
|
||||
|
||||
for (int i = 0; i < images.length; i++)
|
||||
{
|
||||
if (images[i] == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Images can not be null");
|
||||
}
|
||||
else
|
||||
{
|
||||
addImage(images[i]);
|
||||
}
|
||||
}
|
||||
|
||||
timer = new Timer(delay, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Image to be used in the animation.
|
||||
*
|
||||
* @param image the image to be added
|
||||
*/
|
||||
public void addImage(Image image)
|
||||
{
|
||||
if (image != null)
|
||||
{
|
||||
this.images.add(image);
|
||||
calculateImageDimensions();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the width and height of the Image based on the maximum
|
||||
* width and height of any individual Image.
|
||||
*/
|
||||
private void calculateImageDimensions()
|
||||
{
|
||||
imageWidth = 0;
|
||||
imageHeight = 0;
|
||||
|
||||
for (Image image : images)
|
||||
{
|
||||
imageWidth = Math.max(imageWidth, image.getWidth(null));
|
||||
imageHeight = Math.max(imageHeight, image.getHeight(null));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index of the currently visible Image
|
||||
*
|
||||
* @return the index of the Icon
|
||||
*/
|
||||
public int getCurrentImageIndex()
|
||||
{
|
||||
return currentImageIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the index of the Image to be displayed and then repaint the Image.
|
||||
*
|
||||
* @param index the index of the Image to be displayed
|
||||
*/
|
||||
public void setCurrentImageIndex(int index)
|
||||
{
|
||||
currentImageIndex = index;
|
||||
|
||||
AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC);
|
||||
g2d.setComposite(ac);
|
||||
g2d.drawImage(getImage(currentImageIndex), 0, 0, component);
|
||||
|
||||
component.repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the remaining cycles to complete before the animation stops.
|
||||
*
|
||||
* @return the number of remaining cycles
|
||||
*/
|
||||
public int getRemainingCycles()
|
||||
{
|
||||
return cycles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the number of times to repeat each animation sequence, or cycle.
|
||||
*
|
||||
* @param cycles the number of cycles to complete before the animation
|
||||
* stops. The default is -1, which means the animation is
|
||||
* continuous.
|
||||
*/
|
||||
public void setCycles(int cycles)
|
||||
{
|
||||
this.cycles = cycles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the delay between painting each Image
|
||||
*
|
||||
* @return the delay
|
||||
*/
|
||||
public int getDelay()
|
||||
{
|
||||
return timer.getDelay();
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the delay between painting each Image
|
||||
*
|
||||
* @param delay the delay between painting each Image (in milli seconds)
|
||||
*/
|
||||
public void setDelay(int delay)
|
||||
{
|
||||
timer.setDelay(delay);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Image at the specified index.
|
||||
*
|
||||
* @param index the index of the Image to be returned
|
||||
* @return the Image at the specifed index
|
||||
* @exception IndexOutOfBoundsException if the index is out of range
|
||||
*/
|
||||
public Image getImage(int index)
|
||||
{
|
||||
return images.get( index );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of Images that are contained in the animation
|
||||
*
|
||||
* @return the total number of Images
|
||||
*/
|
||||
public int getImagesCount()
|
||||
{
|
||||
return images.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the showFirstImage
|
||||
*
|
||||
* @return the showFirstImage value
|
||||
*/
|
||||
public boolean isShowFirstImage()
|
||||
{
|
||||
return showFirstImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the first image of the animation after the last cycle has passed
|
||||
* If set to false, the last image will remain set after the last
|
||||
* animation cycle.
|
||||
*
|
||||
* @param showFirstImage true when the first image is to be displayed,
|
||||
* false otherwise
|
||||
*/
|
||||
public void setShowFirstImage(boolean showFirstImage)
|
||||
{
|
||||
this.showFirstImage = showFirstImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pauses the animation. The animation can be restarted from the
|
||||
* current Image using the restart() method.
|
||||
*/
|
||||
public void pause()
|
||||
{
|
||||
timer.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the animation from the beginning.
|
||||
*/
|
||||
public void start()
|
||||
{
|
||||
if (!timer.isRunning())
|
||||
{
|
||||
setCurrentImageIndex(0);
|
||||
animationFinished = false;
|
||||
cyclesCompleted = 0;
|
||||
timer.start();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restarts the animation from where the animation was paused. Or, if the
|
||||
* animation has finished, it will be restarted from the beginning.
|
||||
*/
|
||||
public void restart()
|
||||
{
|
||||
if (!timer.isRunning())
|
||||
{
|
||||
if (animationFinished)
|
||||
start();
|
||||
else
|
||||
timer.restart();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the animation. The first icon will be redisplayed.
|
||||
*/
|
||||
public void stop()
|
||||
{
|
||||
timer.stop();
|
||||
setCurrentImageIndex(0);
|
||||
animationFinished = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the width of this image.
|
||||
*
|
||||
* @return the width of the image in pixels.
|
||||
*/
|
||||
public int getWidth(ImageObserver obs)
|
||||
{
|
||||
return imageWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the height of this image.
|
||||
*
|
||||
* @return the height of the image in pixels.
|
||||
*/
|
||||
public int getHeight(ImageObserver obs)
|
||||
{
|
||||
return imageHeight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls the image animation that is scheduled by the Timer
|
||||
*/
|
||||
public void actionPerformed(ActionEvent e)
|
||||
{
|
||||
// Display the next Image in the animation sequence
|
||||
setCurrentImageIndex(
|
||||
getNextImageIndex(currentImageIndex, images.size()));
|
||||
|
||||
// Track the number of cycles that have been completed
|
||||
if (isCycleCompleted(currentImageIndex, images.size()))
|
||||
{
|
||||
cyclesCompleted++;
|
||||
}
|
||||
|
||||
// Stop the animation when the specified number of cycles is completed
|
||||
if (cycles > 0
|
||||
&& cycles <= cyclesCompleted)
|
||||
{
|
||||
timer.stop();
|
||||
animationFinished = true;
|
||||
|
||||
// Display the first Image when required
|
||||
if (isShowFirstImage()
|
||||
&& getCurrentImageIndex() != 0)
|
||||
{
|
||||
new Thread(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
// Wait one more delay interval before displaying the
|
||||
// first Image
|
||||
try
|
||||
{
|
||||
Thread.sleep( timer.getDelay() );
|
||||
setCurrentImageIndex(0);
|
||||
}
|
||||
catch(InterruptedException e) {}
|
||||
}
|
||||
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index of the next Image to be displayed. Normally, images will
|
||||
* be displayed in the order they were added to the AnimatedImage.
|
||||
* If however, a custom animation sequence is required one can extend this
|
||||
* method and achieve a greater control over the animation sequence.
|
||||
*
|
||||
* @param currentIndex the index of the Image currently displayed
|
||||
* @param imageCount the number of Images to be displayed
|
||||
* @return the index of the next Image to be displayed
|
||||
*/
|
||||
protected int getNextImageIndex(int currentIndex, int imageCount)
|
||||
{
|
||||
return ++currentIndex % imageCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the currently displayed Image is the last image of the
|
||||
* animation sequence. This marks the completion of a single animation
|
||||
* cycle.
|
||||
* If a custom animation sequence is required one can extend this
|
||||
* method to achieve a greater control over the animation sequence.
|
||||
*
|
||||
* @param currentIndex the index of the Image currently displayed
|
||||
* @param imageCount the number of Images to be displayed
|
||||
* @return the index of the next Image to be displayed
|
||||
*/
|
||||
protected boolean isCycleCompleted(int currentIndex, int imageCount)
|
||||
{
|
||||
return currentIndex == imageCount - 1;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in new issue