package org.openslx.dozmod.gui.control;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
import javax.swing.JPanel;
import org.openslx.dozmod.gui.Gui;
import org.openslx.thrifthelper.TransferStatusWrapper;
@SuppressWarnings("serial")
public class BlockProgressBar extends JPanel {
private final Color[] blockColors = new Color[6];
private static final Color potentialCompleteColor = new Color(215, 230, 255, 255);
private final TransferStatusWrapper blocks = new TransferStatusWrapper(null);
private final TransferStatusWrapper.Progress progress = new TransferStatusWrapper.Progress();
private boolean simpleMode = true;
private boolean showEstimatedComplete = false;
public BlockProgressBar(byte[] blocks) {
super();
setPreferredSize(Gui.getScaledDimension(100, 32));
setupListeners();
// 0 = complete, 1 = missing, 2 = uploading, 3 = queued for copying, 4 = copying, 5 = hashing
blockColors[0] = Color.BLACK;
blockColors[1] = Color.RED;
blockColors[2] = Color.YELLOW;
blockColors[3] = Color.BLUE;
blockColors[4] = Color.GREEN;
blockColors[5] = Color.YELLOW.darker();
this.blocks.setBlocks(blocks);
}
public void setStatus(byte[] blocks) {
this.blocks.setBlocks(blocks);
this.repaint(100);
}
private void setupListeners() {
final BlockProgressBar me = this;
this.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() == 2) {
me.toggleMode();
}
}
});
}
private void toggleMode() {
simpleMode = !simpleMode;
this.repaint(100);
}
@Override
public void paintComponent(Graphics g) {
if (blocks.isEmpty()) {
// No valid block data, draw white window
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
} else if (simpleMode) {
drawSimple(g);
} else {
drawDetailed(g);
}
}
private void drawSimple(Graphics g) {
if (g instanceof Graphics2D) {
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
}
final int width = getWidth();
final int height = getHeight();
blocks.getCompleteEx(progress);
final int doneWidth = (int) ((float) width * progress.done);
final int potentialWidth = (int) ((float) width * progress.potentiallyDone);
int sumWidth = doneWidth;
g.setColor(Color.BLUE);
g.fillRect(0, 0, doneWidth, height);
if (showEstimatedComplete) {
g.setColor(potentialCompleteColor);
g.fillRect(doneWidth, 0, potentialWidth, height);
sumWidth += potentialWidth;
}
g.setColor(Color.WHITE);
g.fillRect(sumWidth, 0, width - sumWidth, height);
final String percentDisplay = (int) (progress.done * 100) + "%";
Rectangle2D textExtent = g.getFontMetrics().getStringBounds(percentDisplay, g);
final double tw = textExtent.getWidth();
final int textX = (int) ((width - tw) / 2);
final int textXEnd = (int) ((width + tw) / 2);
final int textY = (int) ((height + textExtent.getHeight()) / 2);
if (doneWidth >= textX) {
g.setColor(Color.WHITE);
g.setClip(0, 0, doneWidth, height);
g.drawString(percentDisplay, textX, textY);
}
if (doneWidth <= textXEnd) {
g.setColor(Color.BLACK);
g.setClip(doneWidth, 0, width - doneWidth, height);
g.drawString(percentDisplay, textX, textY);
}
}
private void drawDetailed(Graphics g) {
final int blockCount = blocks.getBlockCount();
// Calculate display mode
final int height = getHeight();
final float width = getWidth() - 2;
float blockWidth = width / blockCount;
int rows = 1;
while (blockWidth * rows < 6 && (float) height / rows > 7) {
rows++;
}
blockWidth *= rows;
final float blockHeight;
final float blockHeightVisible;
if (rows == 1) {
blockHeightVisible = blockHeight = height;
} else {
blockHeight = (height + 2) / rows;
blockHeightVisible = blockHeight - 2;
}
// Draw
g.setColor(Color.WHITE);
g.fillRect(0, 0, getWidth(), getHeight());
float x = 0, y = 0;
for (byte block : blocks.getBlocks()) {
float toX = x + blockWidth;
if (block >= 0 && block < blockColors.length) {
g.setColor(blockColors[block]);
final int boxWidth = ((int) toX) - ((int) x) - 1;
final int boxHeight = (int) (y + blockHeightVisible) - (int) y;
g.fillRect((int) x, (int) y, boxWidth > 1 ? boxWidth : 1, boxHeight > 1 ? boxHeight : 1);
}
x = toX;
if (x + 0.5 > width) {
x = 0;
y += blockHeight;
}
}
}
public void showOptimisticComplete(boolean b) {
this.showEstimatedComplete = b;
}
}