package com.ts3client.ui; import javax.swing.ImageIcon; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; /** * Programmatically drawn vector icons (no external image assets), so the client * is fully self-contained. All icons are rendered at 16×16 with a small * cache. */ public final class Icons { private static final int SZ = 16; private Icons() { } private interface Painter { void paint(Graphics2D g); } private static ImageIcon make(Painter p) { BufferedImage img = new BufferedImage(SZ, SZ, BufferedImage.TYPE_INT_ARGB); Graphics2D g = img.createGraphics(); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); p.paint(g); g.dispose(); return new ImageIcon(img); } // ---- tree icons ---- public static ImageIcon server() { return make(g -> { g.setColor(new Color(0x2C6EA5)); g.fillRoundRect(2, 3, 12, 4, 2, 2); g.fillRoundRect(2, 9, 12, 4, 2, 2); g.setColor(new Color(0x9FD0F0)); g.fillOval(4, 4, 2, 2); g.fillOval(4, 10, 2, 2); }); } public static ImageIcon channel() { return channelPainted(new Color(0x3E7CB1), false); } public static ImageIcon channelLocked() { return channelPainted(new Color(0x8A6D3B), true); } private static ImageIcon channelPainted(Color c, boolean lock) { return make(g -> { g.setColor(c); g.setStroke(new BasicStroke(1.6f)); // simple speaker-cone glyph g.fillRect(2, 6, 3, 4); int[] xs = {5, 9, 9, 5}; int[] ys = {6, 3, 13, 10}; g.fillPolygon(xs, ys, 4); g.setStroke(new BasicStroke(1.4f)); g.drawArc(9, 5, 4, 6, -60, 120); if (lock) { g.setColor(new Color(0xB8860B)); g.fillRoundRect(10, 9, 5, 5, 1, 1); g.setColor(Color.WHITE); g.fillRect(12, 10, 1, 2); } }); } // ---- client status icons ---- public static ImageIcon clientIdle() { return person(Theme.IDLE_CLIENT); } public static ImageIcon clientTalking() { return person(Theme.TALKING); } public static ImageIcon clientAway() { return person(Theme.AWAY); } private static ImageIcon person(Color c) { return make(g -> { g.setColor(c); g.fillOval(5, 2, 6, 6); // head g.fillRoundRect(3, 9, 10, 6, 4, 4); // shoulders }); } public static ImageIcon micMuted() { return make(g -> { g.setColor(Theme.MUTED); g.fillRoundRect(6, 2, 4, 7, 2, 2); g.setStroke(new BasicStroke(1.4f)); g.drawArc(4, 6, 8, 6, 200, 140); g.drawLine(8, 12, 8, 14); g.setStroke(new BasicStroke(2f)); g.drawLine(2, 2, 14, 14); // slash }); } public static ImageIcon speakerMuted() { return make(g -> { g.setColor(Theme.MUTED); g.fillRect(2, 6, 3, 4); int[] xs = {5, 9, 9, 5}; int[] ys = {6, 3, 13, 10}; g.fillPolygon(xs, ys, 4); g.setStroke(new BasicStroke(2f)); g.drawLine(2, 2, 14, 14); }); } // ---- toolbar / action icons ---- public static ImageIcon connect() { return make(g -> { g.setColor(new Color(0x2E8B57)); g.setStroke(new BasicStroke(2f)); g.drawLine(3, 8, 8, 8); g.fillRoundRect(8, 5, 5, 6, 2, 2); g.drawLine(10, 3, 10, 5); g.drawLine(12, 3, 12, 5); }); } public static ImageIcon disconnect() { return make(g -> { g.setColor(Theme.MUTED); g.setStroke(new BasicStroke(2f)); g.drawLine(3, 8, 8, 8); g.fillRoundRect(8, 5, 5, 6, 2, 2); g.drawLine(2, 3, 6, 13); }); } public static ImageIcon mic() { return make(g -> { g.setColor(new Color(0x37474F)); g.fillRoundRect(6, 2, 4, 7, 2, 2); g.setStroke(new BasicStroke(1.4f)); g.drawArc(4, 6, 8, 6, 200, 140); g.drawLine(8, 12, 8, 14); g.drawLine(6, 14, 10, 14); }); } public static ImageIcon speaker() { return make(g -> { g.setColor(new Color(0x37474F)); g.fillRect(2, 6, 3, 4); int[] xs = {5, 9, 9, 5}; int[] ys = {6, 3, 13, 10}; g.fillPolygon(xs, ys, 4); g.setStroke(new BasicStroke(1.4f)); g.drawArc(9, 5, 4, 6, -60, 120); }); } /** Marks the server that currently owns the microphone. */ public static ImageIcon micActive() { return make(g -> { g.setColor(Theme.TALKING); g.fillOval(1, 1, 14, 14); g.setColor(Color.WHITE); g.fillRoundRect(6, 3, 4, 6, 2, 2); g.setStroke(new BasicStroke(1.4f)); g.drawArc(4, 6, 8, 6, 200, 140); g.drawLine(8, 11, 8, 13); }); } public static ImageIcon settings() { return make(g -> { g.setColor(new Color(0x37474F)); g.setStroke(new BasicStroke(2f)); g.drawOval(5, 5, 6, 6); for (int a = 0; a < 360; a += 45) { double r = Math.toRadians(a); int x1 = (int) (8 + Math.cos(r) * 5); int y1 = (int) (8 + Math.sin(r) * 5); int x2 = (int) (8 + Math.cos(r) * 7); int y2 = (int) (8 + Math.sin(r) * 7); g.drawLine(x1, y1, x2, y2); } }); } public static ImageIcon app() { return make(g -> { g.setColor(Theme.ACCENT); g.fillRoundRect(1, 1, 14, 14, 4, 4); g.setColor(Color.WHITE); g.setStroke(new BasicStroke(1.6f)); g.drawArc(4, 5, 8, 8, 30, 120); g.drawArc(2, 3, 12, 12, 30, 120); g.fillOval(7, 9, 2, 2); }); } }