Paint the client with FlatLaf, in a light and a dark theme
The look-and-feel is FlatLaf now, chosen light or dark on the new Design tab and remembered in the settings. Theme keeps only the colours TeamSpeak gives meaning to (talking, away, muted, channel and server names) and takes its surfaces and fonts from the look-and-feel, so a switch recolours the whole window, chat logs included: the HTML panes share one themed stylesheet and re-parse their content when the theme changes. Also fixes the channel tree not scrolling: the tree listened for the mouse wheel to re-check its hover row, and AWT only forwards a wheel event to the enclosing scroll pane when the component under the pointer has no wheel listener of its own. The hover row now follows the viewport instead, which also covers scrollbar drags and keyboard scrolling. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -34,7 +34,7 @@ public final class InfoPanel extends JScrollPane {
|
||||
|
||||
private static final String TOGGLE_HREF = "app:toggle-info-tab";
|
||||
|
||||
private final JEditorPane pane = new JEditorPane();
|
||||
private final JEditorPane pane = HtmlStyles.pane("font-family:sans-serif; font-size:11px;");
|
||||
private DescriptionHandler descriptionHandler;
|
||||
private ChannelNode shownChannel;
|
||||
private ClientEntry shownClient;
|
||||
@@ -43,20 +43,6 @@ public final class InfoPanel extends JScrollPane {
|
||||
private boolean inChatTab;
|
||||
|
||||
public InfoPanel() {
|
||||
javax.swing.text.html.HTMLEditorKit kit = new javax.swing.text.html.HTMLEditorKit();
|
||||
javax.swing.text.html.StyleSheet css = new javax.swing.text.html.StyleSheet();
|
||||
css.addStyleSheet(kit.getStyleSheet());
|
||||
css.addRule("a { color:" + hex(Theme.CHAT_NAME) + "; text-decoration:none; }");
|
||||
// Client references look exactly like a message author's name.
|
||||
css.addRule("a." + BBCode.IDENTITY_LINK_CLASS
|
||||
+ " { color:" + hex(Theme.CHAT_NAME) + "; font-weight:bold; text-decoration:none; }");
|
||||
// External links are underlined so they can't be mistaken for an identity.
|
||||
css.addRule("a." + BBCode.EXTERNAL_LINK_CLASS
|
||||
+ " { color:" + hex(Theme.LINK) + "; text-decoration:underline; }");
|
||||
kit.setStyleSheet(css);
|
||||
pane.setEditorKit(kit);
|
||||
pane.setEditable(false);
|
||||
pane.setBackground(Theme.CHAT_BG);
|
||||
pane.setBorder(BorderFactory.createEmptyBorder(6, 8, 6, 8));
|
||||
pane.addHyperlinkListener(e -> {
|
||||
if (e.getEventType() != javax.swing.event.HyperlinkEvent.EventType.ACTIVATED) return;
|
||||
@@ -69,10 +55,15 @@ public final class InfoPanel extends JScrollPane {
|
||||
}
|
||||
});
|
||||
setViewportView(pane);
|
||||
setBorder(BorderFactory.createLineBorder(new java.awt.Color(0xD0D0D0)));
|
||||
clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateUI() {
|
||||
super.updateUI();
|
||||
setBorder(BorderFactory.createLineBorder(Theme.border()));
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
shownChannel = null;
|
||||
shownClient = null;
|
||||
@@ -118,7 +109,7 @@ public final class InfoPanel extends JScrollPane {
|
||||
private String body() {
|
||||
if (shownChannel != null) return channelBody(shownChannel);
|
||||
if (shownClient != null) return clientBody(shownClient, shownModel, shownIcons);
|
||||
return "<i style='color:#8a8a8a'>Select a channel or client to see details.</i>";
|
||||
return "<i class='muted'>Select a channel or client to see details.</i>";
|
||||
}
|
||||
|
||||
private static String channelBody(ChannelNode ch) {
|
||||
@@ -132,16 +123,16 @@ public final class InfoPanel extends JScrollPane {
|
||||
if (ch.description != null && !ch.description.isEmpty()) {
|
||||
sb.append("<div>").append(multiline(ch.description)).append("</div>");
|
||||
} else if (ch.descriptionLoaded) {
|
||||
sb.append("<i style='color:#8a8a8a'>No description.</i>");
|
||||
sb.append("<i class='muted'>No description.</i>");
|
||||
} else {
|
||||
sb.append("<i style='color:#8a8a8a'>Loading description…</i>");
|
||||
sb.append("<i class='muted'>Loading description…</i>");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String clientBody(ClientEntry cl, ServerModel model, IconRepository icons) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(heading(esc(cl.nickname) + (cl.self ? " <span style='color:#8a8a8a'>(you)</span>" : "")));
|
||||
sb.append(heading(esc(cl.nickname) + (cl.self ? " <span class='muted'>(you)</span>" : "")));
|
||||
|
||||
List<Group> serverGroups = model.serverGroupsOf(cl.serverGroupIds);
|
||||
if (serverGroups.isEmpty()) {
|
||||
@@ -184,8 +175,7 @@ public final class InfoPanel extends JScrollPane {
|
||||
}
|
||||
|
||||
private void setHtml(String body) {
|
||||
pane.setText("<html><body style='font-family:sans-serif;font-size:11px;color:#202020'>"
|
||||
+ body + "</body></html>");
|
||||
pane.setText("<html><body>" + body + "</body></html>");
|
||||
pane.setCaretPosition(0);
|
||||
}
|
||||
|
||||
@@ -206,7 +196,7 @@ public final class InfoPanel extends JScrollPane {
|
||||
}
|
||||
|
||||
private static void row(StringBuilder sb, String label, String value) {
|
||||
sb.append("<div style='margin:1px 0'><span style='color:#5a6b7b'>")
|
||||
sb.append("<div style='margin:1px 0'><span class='muted'>")
|
||||
.append(label).append(":</span> ").append(value).append("</div>");
|
||||
}
|
||||
|
||||
@@ -219,7 +209,4 @@ public final class InfoPanel extends JScrollPane {
|
||||
return BBCode.escape(s);
|
||||
}
|
||||
|
||||
private static String hex(java.awt.Color c) {
|
||||
return String.format("#%06X", c.getRGB() & 0xFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user