/*
* Copyright 2013-2016 consulo.io
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package consulo.spash;
import com.intellij.util.concurrency.AppExecutorUtil;
import com.intellij.util.ui.JBUI;
import com.intellij.util.ui.UIUtil;
import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
/**
* @author VISTALL
* @since 11-Dec-16.
*/
public class AnimatedLogoLabel extends JComponent {
private static class MyComponentUI extends ComponentUI {
private final int[][] myEmptyData = new int[43][7];
private MyComponentUI() {
for (int i = 0; i < ourOffsets.length; i++) {
fillAtOffset(Alphabet.validCharacters, ' ', i, myEmptyData);
}
}
@Override
public Dimension getPreferredSize(JComponent c) {
AnimatedLogoLabel logoLabel = (AnimatedLogoLabel)c;
return new Dimension(JBUI.scale(logoLabel.myData.length * logoLabel.myLetterHeight), JBUI.scale(logoLabel.myData[0].length * logoLabel.myLetterHeight));
}
@Override
public Dimension getMinimumSize(JComponent c) {
return getPreferredSize(c);
}
@Override
public Dimension getMaximumSize(JComponent c) {
return getPreferredSize(c);
}
@Override
public void paint(Graphics g, JComponent c) {
AnimatedLogoLabel logoLabel = (AnimatedLogoLabel)c;
BufferedImage image = UIUtil.createImage(c.getWidth(), c.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics graphics = image.getGraphics();
paint(graphics, logoLabel, myEmptyData, c.getBackground());
paint(graphics, logoLabel, logoLabel.myData, c.getForeground());
graphics.dispose();
g.drawImage(image, 0, 0, c.getWidth(), c.getHeight(), c);
}
private void paint(Graphics g, AnimatedLogoLabel c, int[][] data, Color color) {
for (int y = 0; y < data.length; y++) {
int[] ints = data[y];
for (int x = 0; x < ints.length; x++) {
int a = ints[x];
if (a > 0) {
int size = JBUI.scale(c.myLetterHeight);
g.setColor(color);
g.fillRect(y * size, x * size, size, size);
}
}
}
}
}
private static final int[] ourOffsets = new int[]{1, 7, 13, 19, 25, 31, 37};
private int[][] myData = new int[43][7];
private int myValue;
private Runnable myTask;
private final int myLetterHeight;
private final boolean myAnimated;
private boolean[] myStates = new boolean[Names.ourName.length()];
private Future<?> myFuture;
private final Object lock = new Object();
public AnimatedLogoLabel(int letterHeightInPixels, boolean animated) {
myLetterHeight = letterHeightInPixels;
myAnimated = animated;
Random random = new Random();
Map<Character, AlphabetDraw> characterDraws = Alphabet.validCharacters;
Character[] abc = Alphabet.alphabet;
char[] str;
if (myAnimated) {
if (random.nextInt(100_000) < 100) {
str = Names.ourEasterNames[random.nextInt(Names.ourEasterNames.length)].toCharArray();
}
else {
str = new char[Names.ourName.length()];
for (int i = 0; i < str.length; i++) {
while (true) {
str[i] = abc[random.nextInt(abc.length)];
if (str[i] != Names.ourName.charAt(i)) {
break;
}
}
}
}
}
else {
str = Names.ourName.toCharArray();
}
for (int i = 0; i < ourOffsets.length; i++) {
int offset = ourOffsets[i];
char c = str[i];
characterDraws.get(c).draw(offset, myData);
}
if (myAnimated) {
myTask = () -> {
synchronized (lock) {
float per = 100f / Names.ourName.length();
boolean end = myValue >= 93;
int letterPosition = (int)(myValue / per);
if (end) {
letterPosition = Names.ourName.length();
}
for (int i = 0; i < letterPosition; i++) {
boolean state = myStates[i];
if (!state) {
myStates[i] = true;
fillAtOffset(characterDraws, Names.ourName.charAt(i), i);
}
}
// last pos
if (end) {
repaintAll();
stop();
}
else {
int randomIndex = -1;
while (true) {
randomIndex = random.nextInt(abc.length);
if (abc[randomIndex] != Names.ourName.charAt(letterPosition)) {
break;
}
}
fillAtOffset(characterDraws, abc[randomIndex], letterPosition);
repaintAll();
}
}
};
}
updateUI();
}
private void repaintAll() {
update(getGraphics());
}
public void start() {
if (myAnimated) {
myFuture = AppExecutorUtil.getAppScheduledExecutorService().scheduleWithFixedDelay(myTask, 50, 20, TimeUnit.MILLISECONDS);
}
}
public void stop() {
if (myFuture != null) {
myFuture.cancel(false);
}
}
private void fillAtOffset(Map<Character, AlphabetDraw> characterDraws, char c, int pos) {
fillAtOffset(characterDraws, c, pos, myData);
}
private static void fillAtOffset(Map<Character, AlphabetDraw> characterDraws, char c, int pos, int[][] data) {
int offset = ourOffsets[pos];
for (int i = 0; i < 5; i++) {
int[] ints = data[i + offset];
for (int j = 0; j < ints.length; j++) {
ints[j] = 0;
}
}
characterDraws.get(c).draw(offset, data);
}
public void setValue(int value) {
synchronized (lock) {
myValue = value;
}
}
@Override
public void updateUI() {
setUI(new MyComponentUI());
}
}