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; } }