Log server activity, scrollable chat tabs, and move info panel to a chat tab

Native TS3 logs client joins/leaves/moves, group changes and channel edits
to the server tab; minor local-only notices (mic mute, tray) no longer
spam the log. Chat tabs scroll by mouse wheel like server tabs. The info
panel can now be moved into a persistent, generically-labelled chat tab
that tracks tree selection and collapses the panel's space entirely; a
tree rebuild no longer briefly fires a null selection that reset this.
Added "Find Client in Channel Tree" to the client context menu, and tree
selection now survives model rebuilds.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-17 21:47:12 +00:00
parent 047c89404c
commit 71084ea309
9 changed files with 439 additions and 35 deletions

View File

@@ -243,6 +243,31 @@ public final class Icons {
return themed("ACTIVATE_MICROPHONE", Icons::paintMicActive);
}
/**
* A fixed-width "channel icon / edit icon" label icon, used where a tab must not
* change width as the object it shows changes (e.g. the info-panel-in-chat tab).
*/
public static ImageIcon channelClientPair() {
ImageIcon channel = channel(true);
ImageIcon edit = themed("EDIT", Icons::paintEdit);
int gap = 8;
int width = channel.getIconWidth() + gap + edit.getIconWidth();
int height = Math.max(channel.getIconHeight(), edit.getIconHeight());
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = img.createGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.drawImage(channel.getImage(), 0, (height - channel.getIconHeight()) / 2, null);
g.setColor(Theme.IDLE_CLIENT);
g.setFont(Theme.UI_FONT);
java.awt.FontMetrics fm = g.getFontMetrics();
int slashX = channel.getIconWidth() + (gap - fm.stringWidth("/")) / 2;
g.drawString("/", slashX, (height + fm.getAscent()) / 2 - 1);
g.drawImage(edit.getImage(), channel.getIconWidth() + gap,
(height - edit.getIconHeight()) / 2, null);
g.dispose();
return new ImageIcon(img);
}
/** The toolbar's away marker. */
public static ImageIcon away() {
return themed("AWAY", IconTheme.TOOLBAR_SIZE, g -> paintPerson(g, Theme.AWAY));
@@ -398,6 +423,18 @@ public final class Icons {
g.drawLine(8, 11, 8, 13);
}
/** A pencil glyph, drawn when no icon pack ships an "EDIT" icon. */
private static void paintEdit(Graphics2D g) {
g.setColor(new Color(0x37474F));
g.setStroke(new BasicStroke(1.4f));
g.drawLine(3, 13, 11, 5);
g.drawLine(3, 13, 4, 10);
g.drawLine(4, 10, 11, 3);
g.drawLine(11, 3, 13, 5);
g.drawLine(13, 5, 11, 7);
g.drawLine(11, 5, 13, 7);
}
private static void paintSettings(Graphics2D g) {
g.setColor(new Color(0x37474F));
g.setStroke(new BasicStroke(2f));