mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-24 13:11:47 +00:00
Merge remote-tracking branch
'origin/GP-4873-dragonmacher-theming-font-tables--SQUASHED' (Closes #6853)
This commit is contained in:
commit
493d87cee0
@ -165,6 +165,7 @@ font.splash.status = serif-bold-12
|
||||
|
||||
// default table renderer uses the JLabel font, which is mapped to system.font.control
|
||||
font.table.base = [font]system.font.control
|
||||
font.table.fixed.width = font.table.base[monospaced]
|
||||
font.table.header.number = arial-bold-12
|
||||
|
||||
font.task.monitor.label.message = sansserif-plain-10
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -141,7 +141,7 @@ public class ThemeFontTableModel extends GDynamicColumnTableModel<FontValue, Obj
|
||||
return "<No Value>";
|
||||
}
|
||||
if (resolvedFont.refId() != null) {
|
||||
return "[" + resolvedFont.refId() + "]";
|
||||
return resolvedFont.getValueText();
|
||||
}
|
||||
|
||||
Font font = resolvedFont.font();
|
||||
@ -193,7 +193,8 @@ public class ThemeFontTableModel extends GDynamicColumnTableModel<FontValue, Obj
|
||||
if (fontValue == null) {
|
||||
return null;
|
||||
}
|
||||
return new ResolvedFont(id, fontValue.getReferenceId(), valueMap.getResolvedFont(id));
|
||||
return new ResolvedFont(fontValue, id, fontValue.getReferenceId(),
|
||||
valueMap.getResolvedFont(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -237,7 +238,7 @@ public class ThemeFontTableModel extends GDynamicColumnTableModel<FontValue, Obj
|
||||
|
||||
Font font = resolvedFont.font();
|
||||
if (font != null) {
|
||||
setToolTipText(FontValue.fontToString(font));
|
||||
setToolTipText(resolvedFont.getFullValueText());
|
||||
}
|
||||
|
||||
return label;
|
||||
@ -250,6 +251,41 @@ public class ThemeFontTableModel extends GDynamicColumnTableModel<FontValue, Obj
|
||||
|
||||
}
|
||||
|
||||
private record ResolvedFont(String id, String refId, Font font) {
|
||||
/**/}
|
||||
// This class is used as a column cell value. It holds the info that defines the font in the
|
||||
// theme files, as long as the final font that was loaded by the system.
|
||||
private record ResolvedFont(FontValue fontValue, String id, String refId, Font font) {
|
||||
|
||||
String getValueText() {
|
||||
|
||||
if (refId == null) {
|
||||
return FontValue.fontToString(font);
|
||||
}
|
||||
|
||||
FontModifier modifier = fontValue.getModifier();
|
||||
String modifierText = "";
|
||||
if (modifier != null) {
|
||||
modifierText = "*";
|
||||
}
|
||||
|
||||
// ex: [font.foo]
|
||||
// [font.foo]*
|
||||
return "[" + refId + "]" + modifierText;
|
||||
}
|
||||
|
||||
String getFullValueText() {
|
||||
if (refId == null) {
|
||||
return FontValue.fontToString(font);
|
||||
}
|
||||
|
||||
FontModifier modifier = fontValue.getModifier();
|
||||
String modifierText = "";
|
||||
if (modifier != null) {
|
||||
modifierText = " [%s]%s".formatted(refId, modifier.toString());
|
||||
}
|
||||
|
||||
// ex: monospaced-PLAIN-13
|
||||
// monospaced-PLAIN-13 [font.foo][monospaced]
|
||||
return FontValue.fontToString(font) + modifierText;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,10 +16,12 @@
|
||||
package docking.widgets;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.plaf.LabelUI;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicHTML;
|
||||
import javax.swing.table.DefaultTableCellRenderer;
|
||||
@ -28,6 +30,7 @@ import docking.widgets.label.GDHtmlLabel;
|
||||
import generic.theme.*;
|
||||
import generic.theme.GThemeDefaults.Colors.Palette;
|
||||
import generic.theme.GThemeDefaults.Colors.Tables;
|
||||
import generic.theme.laf.FontChangeListener;
|
||||
import ghidra.util.Msg;
|
||||
import util.CollectionUtils;
|
||||
import utilities.util.reflection.ReflectionUtilities;
|
||||
@ -41,15 +44,19 @@ import utilities.util.reflection.ReflectionUtilities;
|
||||
* The preferred method to change the font used by this renderer is {@link #setBaseFontId(String)}.
|
||||
* If you would like this renderer to use a monospaced font, then, as an alternative to creating a
|
||||
* font ID, you can instead override {@link #getDefaultFont()} to return this
|
||||
* class's {@link #fixedWidthFont}. Also, the fixed width font of this class is based on the
|
||||
* class's {@link #fixedWidthFont}.
|
||||
*
|
||||
* Also, the fixed width font of this class is based on the
|
||||
* default font set when calling {@link #setBaseFontId(String)}, so it stays up-to-date with theme
|
||||
* changes.
|
||||
*/
|
||||
public abstract class AbstractGCellRenderer extends GDHtmlLabel {
|
||||
public abstract class AbstractGCellRenderer extends GDHtmlLabel implements FontChangeListener {
|
||||
|
||||
private static final Color BACKGROUND_COLOR = new GColor("color.bg.table.row");
|
||||
private static final Color ALT_BACKGROUND_COLOR = new GColor("color.bg.table.row.alt");
|
||||
|
||||
private static final String BASE_FONT_ID = "font.table.base";
|
||||
private static final String DEFAULT_BASE_FONT_ID = "font.table.base";
|
||||
private static final String MONOSPACED_FONT_ID = "font.table.fixed.width";
|
||||
|
||||
/** Allows the user to disable alternating row colors on JLists and JTables */
|
||||
private static final String DISABLE_ALTERNATING_ROW_COLORS_PROPERTY =
|
||||
@ -63,6 +70,8 @@ public abstract class AbstractGCellRenderer extends GDHtmlLabel {
|
||||
|
||||
protected Border focusBorder;
|
||||
protected Border noFocusBorder;
|
||||
protected String baseFontId;
|
||||
protected String fixedWidthFontId;
|
||||
protected Font defaultFont;
|
||||
protected Font fixedWidthFont;
|
||||
protected Font boldFont;
|
||||
@ -73,7 +82,8 @@ public abstract class AbstractGCellRenderer extends GDHtmlLabel {
|
||||
|
||||
public AbstractGCellRenderer() {
|
||||
|
||||
setBaseFontId(BASE_FONT_ID);
|
||||
setBaseFontId(DEFAULT_BASE_FONT_ID);
|
||||
setFixedWidthFontId(MONOSPACED_FONT_ID);
|
||||
|
||||
noFocusBorder = BorderFactory.createEmptyBorder(0, 5, 0, 5);
|
||||
Border innerBorder = BorderFactory.createEmptyBorder(0, 4, 0, 4);
|
||||
@ -135,21 +145,73 @@ public abstract class AbstractGCellRenderer extends GDHtmlLabel {
|
||||
* @see Gui#registerFont(Component, String)
|
||||
*/
|
||||
public void setBaseFontId(String fontId) {
|
||||
if (baseFontId != null) {
|
||||
Gui.unRegisterFont(this, baseFontId);
|
||||
}
|
||||
|
||||
Font f = Gui.getFont(fontId);
|
||||
updateDefaultFont(f);
|
||||
|
||||
baseFontId = fontId;
|
||||
Gui.registerFont(this, baseFontId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this renderer's fixed width theme font id.
|
||||
* @param fontId the font id
|
||||
* @see Gui#registerFont(Component, String)
|
||||
*/
|
||||
public void setFixedWidthFontId(String fontId) {
|
||||
if (fixedWidthFontId != null) {
|
||||
Gui.unRegisterFont(this, fixedWidthFontId);
|
||||
}
|
||||
|
||||
Font f = Gui.getFont(fontId);
|
||||
fixedWidthFont = f;
|
||||
|
||||
fixedWidthFontId = fontId;
|
||||
Gui.registerFont(this, fixedWidthFontId);
|
||||
}
|
||||
|
||||
private void updateDefaultFont(Font f) {
|
||||
if (Objects.equals(f, defaultFont)) {
|
||||
return;
|
||||
}
|
||||
|
||||
defaultFont = f;
|
||||
fixedWidthFont = new Font("monospaced", f.getStyle(), f.getSize());
|
||||
boldFont = f.deriveFont(Font.BOLD);
|
||||
italicFont = f.deriveFont(Font.ITALIC);
|
||||
}
|
||||
|
||||
// Gui does not allow registering the same component multiple times, so unregister first
|
||||
Gui.unRegisterFont(this, fontId);
|
||||
Gui.registerFont(this, fontId);
|
||||
@Override
|
||||
public void setUI(LabelUI ui) {
|
||||
|
||||
super.setUI(ui);
|
||||
|
||||
if (baseFontId == null) {
|
||||
return; // initializing
|
||||
}
|
||||
|
||||
Font font = Gui.getFont(baseFontId);
|
||||
updateDefaultFont(font);
|
||||
|
||||
font = Gui.getFont(fixedWidthFontId);
|
||||
fixedWidthFont = font;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fontChanged(String fontId, Font f) {
|
||||
if (fontId.equals(baseFontId)) {
|
||||
updateDefaultFont(f);
|
||||
}
|
||||
else if (fontId.equals(fixedWidthFontId)) {
|
||||
fixedWidthFont = f;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFont(Font f) {
|
||||
super.setFont(f);
|
||||
|
||||
checkForInvalidSetFont(f);
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -60,6 +60,7 @@ public class DefaultTableCellRendererWrapper extends GTableCellRenderer {
|
||||
|
||||
rendererComponent.setForeground(thisRenderer.getForeground());
|
||||
rendererComponent.setBackground(thisRenderer.getBackground());
|
||||
rendererComponent.setFont(thisRenderer.getFont());
|
||||
|
||||
if (rendererComponent instanceof JComponent) {
|
||||
((JComponent) rendererComponent).setBorder(thisRenderer.getBorder());
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -134,6 +134,11 @@ public class FontModifier {
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getSerializationString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given string as one or more font modifiers
|
||||
* @param value the string to parse as modifiers
|
||||
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -162,12 +162,15 @@ public class FontValue extends ThemeValue<Font> {
|
||||
|
||||
@Override
|
||||
protected Font getUnresolvedReferenceValue(String primaryId, String unresolvedId) {
|
||||
Msg.warn(this,
|
||||
"Could not resolve indirect font path for \"" + unresolvedId +
|
||||
"\" for primary id \"" + primaryId + "\", using last resort default");
|
||||
Msg.warn(this, "Could not resolve indirect font path for \"" + unresolvedId +
|
||||
"\" for primary id \"" + primaryId + "\", using last resort default");
|
||||
return LAST_RESORT_DEFAULT;
|
||||
}
|
||||
|
||||
public FontModifier getModifier() {
|
||||
return modifier;
|
||||
}
|
||||
|
||||
private static String toExternalId(String internalId) {
|
||||
if (internalId.startsWith(FONT_ID_PREFIX)) {
|
||||
return internalId;
|
||||
|
@ -17,20 +17,20 @@ package generic.theme.laf;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Font;
|
||||
import java.util.Iterator;
|
||||
import java.util.Objects;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import generic.theme.Gui;
|
||||
import ghidra.util.datastruct.WeakDataStructureFactory;
|
||||
import ghidra.util.datastruct.WeakSet;
|
||||
|
||||
/**
|
||||
* Maintains a weak set of components associated with a given font id. Whenever the font changes
|
||||
* for the font id, this class will update the component's font to the new value.
|
||||
*/
|
||||
public class ComponentFontRegistry {
|
||||
private WeakSet<StyledComponent> components =
|
||||
WeakDataStructureFactory.createCopyOnReadWeakSet();
|
||||
|
||||
// use a thread-safe set that allows for changes while iterating
|
||||
private Set<StyledComponent> components = ConcurrentHashMap.newKeySet();
|
||||
private String fontId;
|
||||
|
||||
/**
|
||||
@ -69,7 +69,7 @@ public class ComponentFontRegistry {
|
||||
Iterator<StyledComponent> it = components.iterator();
|
||||
while (it.hasNext()) {
|
||||
StyledComponent sc = it.next();
|
||||
if (component == sc.component) {
|
||||
if (sc.matches(component)) {
|
||||
it.remove();
|
||||
break;
|
||||
}
|
||||
@ -81,17 +81,51 @@ public class ComponentFontRegistry {
|
||||
*/
|
||||
public void updateComponentFonts() {
|
||||
Font font = Gui.getFont(fontId);
|
||||
for (StyledComponent c : components) {
|
||||
c.setFont(font);
|
||||
|
||||
List<StyledComponent> copy = new ArrayList<>(components);
|
||||
for (StyledComponent c : copy) {
|
||||
if (!c.isValid()) {
|
||||
// the component has been garbage collected
|
||||
components.remove(c);
|
||||
}
|
||||
else {
|
||||
c.setFont(font);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private record StyledComponent(Component component, int fontStyle) {
|
||||
/**
|
||||
* A simple container that holds a font style and the component that uses that style. The
|
||||
* component is managed using a weak reference to help prevent memory leaks.
|
||||
*/
|
||||
private class StyledComponent {
|
||||
|
||||
private int fontStyle;
|
||||
private WeakReference<Component> componentReference;
|
||||
|
||||
StyledComponent(Component component, int fontStyle) {
|
||||
this.fontStyle = fontStyle;
|
||||
this.componentReference = new WeakReference<>(component);
|
||||
}
|
||||
|
||||
boolean matches(Component c) {
|
||||
return componentReference.refersTo(c);
|
||||
}
|
||||
|
||||
boolean isValid() {
|
||||
return !componentReference.refersTo(null);
|
||||
}
|
||||
|
||||
void setFont(Font font) {
|
||||
|
||||
Component component = componentReference.get();
|
||||
if (component == null) {
|
||||
return; // garbage collected
|
||||
}
|
||||
|
||||
Font existingFont = component.getFont();
|
||||
Font styledFont = font;
|
||||
int style = fontStyle();
|
||||
int style = fontStyle;
|
||||
if (style != Font.PLAIN) {
|
||||
// Only style the font when it is not plain. Doing this means that clients cannot
|
||||
// override a non-plain font to be plain. If clients need that behavior, they must
|
||||
@ -99,7 +133,14 @@ public class ComponentFontRegistry {
|
||||
styledFont = font.deriveFont(style);
|
||||
}
|
||||
|
||||
if (!Objects.equals(existingFont, styledFont)) {
|
||||
if (Objects.equals(existingFont, styledFont)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (component instanceof FontChangeListener fontListener) {
|
||||
fontListener.fontChanged(fontId, styledFont);
|
||||
}
|
||||
else {
|
||||
component.setFont(styledFont);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,32 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package generic.theme.laf;
|
||||
|
||||
import java.awt.Font;
|
||||
|
||||
/**
|
||||
* A simple interface that signals the client has a font that should be updated when the theme is
|
||||
* updated.
|
||||
*/
|
||||
public interface FontChangeListener {
|
||||
|
||||
/**
|
||||
* Called when the client should update its font to the given font.
|
||||
* @param fontId the theme font id being updated
|
||||
* @param f the font
|
||||
*/
|
||||
public void fontChanged(String fontId, Font f);
|
||||
}
|
@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@ -230,8 +230,6 @@ public class PluginInstallerDialog extends DialogComponentProvider {
|
||||
private class NameCellRenderer extends GTableCellRenderer {
|
||||
|
||||
NameCellRenderer() {
|
||||
defaultFont = getFont();
|
||||
boldFont = defaultFont.deriveFont(defaultFont.getStyle() | Font.BOLD);
|
||||
setBorder(BorderFactory.createEmptyBorder(0, 5, 0, 0));
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user