GP-2995 creating a better mapping of look and feel values to more standard ids and easier ways to override values for a specific LaF

This commit is contained in:
ghidragon
2023-01-13 17:58:27 -05:00
parent 898f12cc12
commit e5f1563c08
60 changed files with 1939 additions and 1283 deletions
@@ -5,12 +5,12 @@ color.bg.currentline.listing = color.bg.currentline
color.bg.selection.listing = color.bg.selection
color.bg.highlight.listing = color.bg.highlight
color.bg.listing.tabs.selected = [color]textHighlight
color.bg.listing.tabs.unselected = system.color.bg.application
color.bg.listing.tabs.selected = [color]system.color.bg.selected.view
color.bg.listing.tabs.unselected = [color]system.color.bg.control
color.bg.listing.tabs.highlighted = #ABC8FF
color.bg.listing.tabs.list = rgb(255, 255, 230)
color.bg.listing.tabs.more.tabs.hover = rgb(255, 226, 213)
color.fg.listing.tabs.text.selected = [color]textHighlightText
color.fg.listing.tabs.text.selected = [color]system.color.fg.selected.view
color.fg.listing.tabs.text.unselected = color.fg
color.fg.listing.tabs.list = black
@@ -6,8 +6,8 @@ color.flowtype.fall.through = red
color.flowtype.jump.conditional = #007C00 // dark green
color.flowtype.jump.unconditional = blue
color.bg.table.selection.bundle = [color]textHighlight
color.fg.table.selection.bundle = [color]textHighlightText
color.bg.table.selection.bundle = [color]system.color.bg.selected.view
color.fg.table.selection.bundle = [color]system.color.fg.selected.view
color.fg.table.bundle.disabled = darkGray
color.fg.table.bundle.busy = gray
color.fg.table.bundle.inactive = black
@@ -75,7 +75,7 @@ color.bg.plugin.datamgr.icon.highlight = rgb(204, 204, 255)
color.fg.plugin.disassembledview.address = color.fg
color.bg.plugin.editors.compositeeditor.text = color.fg
color.bg.plugin.editors.compositeeditor.line = system.color.border
color.bg.plugin.editors.compositeeditor.line = [color]system.color.bg.border
color.bg.plugin.editors.compositeeditor.line.interior = #D4D4D4
color.bg.plugin.editors.compositeeditor.byte.header = #DFDFDF
color.bg.plugin.editors.compositeeditor.bit.undefined = #F8F8F8
@@ -182,8 +182,6 @@ color.flowtype.fall.through = rgb(164, 66, 66)
color.flowtype.jump.conditional = rgb(95, 129, 157)
color.flowtype.jump.unconditional = rgb(140, 148, 64)
color.bg.table.selection.bundle = [color]textHighlight
color.fg.table.selection.bundle = [color]textHighlightText
color.fg.table.bundle.disabled = lightGray
color.fg.table.bundle.busy = gray
color.fg.table.bundle.inactive = lightGray
@@ -211,7 +209,7 @@ color.bg.plugin.datamgr.edge.default = deepskyblue
color.bg.plugin.datamgr.edge.composite = plum
color.bg.plugin.datamgr.edge.reference = deepskyblue
color.bg.plugin.editors.compositeeditor.byte.header = [color]text
color.bg.plugin.editors.compositeeditor.byte.header = [color]system.color.bg.view
color.fg.plugin.equate.enum = deepskyblue
@@ -46,7 +46,7 @@ import ghidra.util.bean.opteditor.OptionsVetoException;
public abstract class AbstractReferenceHover extends AbstractConfigurableHover {
private static final int WINDOW_OFFSET = 50;
private static final Color BACKGROUND_COLOR = Colors.BACKGROUND_TOOLTIP;
private static final Color BACKGROUND_COLOR = Colors.BG_TOOLTIP;
private static final Color FG_COLOR_NOT_IN_MEMORY = new GColor("color.fg.hint");
private CodeFormatService codeFormatService;
@@ -128,8 +128,7 @@ public abstract class AbstractReferenceHover extends AbstractConfigurableHover {
String widthOptionName = optionName + Options.DELIMITER + "Dialog Width";
String heightOptionName = optionName + Options.DELIMITER + "Dialog Height";
if (optionName.equals(widthOptionName) ||
optionName.equals(heightOptionName)) {
if (optionName.equals(widthOptionName) || optionName.equals(heightOptionName)) {
int dialogWidth = options.getInt(widthOptionName, 600);
if (dialogWidth <= 0) {
throw new OptionsVetoException(
@@ -38,7 +38,7 @@ import ghidra.app.plugin.core.console.CodeCompletion;
public class CodeCompletionWindow extends JDialog {
private static final long serialVersionUID = 1L;
/* from ReferenceHoverPlugin */
private static final Color BACKGROUND_COLOR = Colors.BACKGROUND_TOOLTIP;
private static final Color BACKGROUND_COLOR = Colors.BG_TOOLTIP;
protected final InterpreterPanel console;
protected final JTextPane outputTextField;
@@ -36,6 +36,7 @@ import resources.ResourceManager;
class DnDTreeCellRenderer extends DefaultTreeCellRenderer {
private static final Color BACKGROUND_UNSELECTED = new GColor("color.bg.tree");
private static final Color BACKGROUND_SELECTED = new GColor("color.bg.tree.selected");
private static final Color FOREGROUND_SELECTED = new GColor("color.fg.tree.selected");
private static final String DISABLED_DOCS = "DisabledDocument.gif";
private static final String DISABLED_FRAGMENT = "DisabledFragment";
@@ -68,6 +69,7 @@ class DnDTreeCellRenderer extends DefaultTreeCellRenderer {
private Color defaultNonSelectionColor;
private Color selectionForDragColor;
private Color nonSelectionForDragColor;
private Color defaultTextSelectionColor;
private int rowForFeedback;
/**
@@ -77,6 +79,7 @@ class DnDTreeCellRenderer extends DefaultTreeCellRenderer {
super();
defaultNonSelectionColor = BACKGROUND_UNSELECTED;
defaultSelectionColor = BACKGROUND_SELECTED;
defaultTextSelectionColor = FOREGROUND_SELECTED;
rowForFeedback = -1;
// disable HTML rendering
@@ -168,12 +171,14 @@ class DnDTreeCellRenderer extends DefaultTreeCellRenderer {
}
else {
setBackgroundSelectionColor(defaultSelectionColor);
setTextSelectionColor(defaultTextSelectionColor);
setBackgroundNonSelectionColor(defaultNonSelectionColor);
}
setToolTipText(null);
}
else {
setBackgroundSelectionColor(defaultSelectionColor);
setTextSelectionColor(defaultTextSelectionColor);
setBackgroundNonSelectionColor(defaultNonSelectionColor);
setToolTipText(dtree.getToolTipText(node));
}
@@ -315,11 +320,9 @@ class DnDTreeCellRenderer extends DefaultTreeCellRenderer {
private void loadImages() {
// try to load icon images
iconMap = new HashMap<>();
String[] iconIds =
{ DOCS, FRAGMENT, EMPTY_FRAGMENT, VIEWED_FRAGMENT, VIEWED_EMPTY_FRAGMENT,
VIEWED_CLOSED_FOLDER, VIEWED_OPEN_FOLDER, VIEWED_CLOSED_FOLDER_WITH_DESC,
CLOSED_FOLDER, OPEN_FOLDER,
};
String[] iconIds = { DOCS, FRAGMENT, EMPTY_FRAGMENT, VIEWED_FRAGMENT, VIEWED_EMPTY_FRAGMENT,
VIEWED_CLOSED_FOLDER, VIEWED_OPEN_FOLDER, VIEWED_CLOSED_FOLDER_WITH_DESC, CLOSED_FOLDER,
OPEN_FOLDER, };
String[] disabledNames = { DISABLED_DOCS, DISABLED_FRAGMENT, DISABLED_EMPTY_FRAGMENT,
DISABLED_VIEWED_EMPTY_FRAGMENT, DISABLED_VIEWED_FRAGMENT, DISABLED_VIEWED_CLOSED_FOLDER,
DISABLED_VIEWED_OPEN_FOLDER, DISABLED_VIEWED_CLOSED_FOLDER_WITH_DESC,
@@ -40,7 +40,7 @@ import ghidra.program.util.ProgramSelection;
*/
public interface FGVertex extends VisualVertex {
static final Color TOOLTIP_BACKGROUND_COLOR = Colors.BACKGROUND_TOOLTIP;
static final Color TOOLTIP_BACKGROUND_COLOR = Colors.BG_TOOLTIP;
public FGVertex cloneVertex(FGController newController);
@@ -4,9 +4,9 @@
color.bg.splashscreen = black
color.fg.splashscreen = gray
color.bg.header.active = [color]textHighlight
color.bg.header.active = [color]system.color.bg.selected.view
color.bg.header.inactive = #A1A1A1
color.fg.header.active = [color]textHighlightText
color.fg.header.active = [color]system.color.fg.selected.view
color.fg.header.inactive = black
color.header.drag.cursor = black
@@ -170,7 +170,7 @@ color.bg.fieldpanel.selection.and.highlight = #344028 // yellow greenish
// docking buttons
color.fg.button = darkGray
color.bg.filechooser.shortcut = system.color.bg.widget
color.bg.filechooser.shortcut = [color]system.color.bg.view
@@ -133,7 +133,7 @@ public class EditWindow extends JWindow {
private void create() {
textField = new JTextField(" ");
JPanel panel = new JPanel(new BorderLayout());
Color bgColor = Colors.BACKGROUND_TOOLTIP;
Color bgColor = Colors.BG_TOOLTIP;
panel.setBackground(bgColor);
panel.add(textField, BorderLayout.CENTER);
@@ -40,7 +40,7 @@ public class SplitPanel extends JPanel {
this.rightComp = rightComp;
this.isHorizontal = isHorizontal;
divider = new Divider();
divider.setBackground(new GColor("SplitPane.background"));
divider.setBackground(new GColor("laf.color.SplitPane.background"));
add(leftComp);
add(divider);
add(rightComp);
@@ -0,0 +1,80 @@
/* ###
* 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 docking.theme.gui;
import generic.theme.GThemeValueMap;
import generic.theme.ThemeManager;
/**
* Shares values for the three theme value tables so they all don't have their own copies
*/
public class GThemeValuesCache {
private ThemeManager themeManager;
private GThemeValueMap currentValues;
private GThemeValueMap themeValues;
private GThemeValueMap defaultValues;
private GThemeValueMap lightValues;
private GThemeValueMap darkValues;
public GThemeValuesCache(ThemeManager themeManager) {
this.themeManager = themeManager;
}
public void clear() {
currentValues = null;
themeValues = null;
defaultValues = null;
lightValues = null;
darkValues = null;
}
public GThemeValueMap getCurrentValues() {
if (currentValues == null) {
currentValues = themeManager.getCurrentValues();
}
return currentValues;
}
public GThemeValueMap getThemeValues() {
if (themeValues == null) {
themeValues = themeManager.getThemeValues();
}
return themeValues;
}
public GThemeValueMap getDefaultValues() {
if (defaultValues == null) {
defaultValues = themeManager.getDefaults();
}
return defaultValues;
}
public GThemeValueMap getLightValues() {
if (lightValues == null) {
lightValues = themeManager.getApplicationLightDefaults();
}
return lightValues;
}
public GThemeValueMap getDarkValues() {
if (darkValues == null) {
darkValues = themeManager.getApplicationDarkDefaults();
}
return darkValues;
}
}
@@ -43,14 +43,14 @@ public class ThemeColorTable extends JPanel implements ActionContextProvider {
private GFilterTable<ColorValue> filterTable;
private ThemeManager themeManager;
public ThemeColorTable(ThemeManager themeManager) {
public ThemeColorTable(ThemeManager themeManager, GThemeValuesCache valuesProvider) {
super(new BorderLayout());
this.themeManager = themeManager;
colorTableModel = new ThemeColorTableModel(themeManager);
colorTableModel = new ThemeColorTableModel(valuesProvider);
filterTable = new GFilterTable<>(colorTableModel);
table = filterTable.getTable();
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
table.addKeyListener(new KeyAdapter() {
@Override
@@ -43,11 +43,11 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
private GThemeValueMap defaultValues;
private GThemeValueMap lightDefaultValues;
private GThemeValueMap darkDefaultValues;
private ThemeManager themeManager;
private GThemeValuesCache valuesCache;
public ThemeColorTableModel(ThemeManager themeManager) {
public ThemeColorTableModel(GThemeValuesCache valuesProvider) {
super(new ServiceProviderStub());
this.themeManager = themeManager;
this.valuesCache = valuesProvider;
load();
}
@@ -55,7 +55,7 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
* Reloads the just the current values shown in the table. Called whenever a color changes.
*/
public void reloadCurrent() {
currentValues = themeManager.getCurrentValues();
currentValues = valuesCache.getCurrentValues();
colors = currentValues.getColors();
fireTableDataChanged();
}
@@ -74,12 +74,12 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
}
private void load() {
currentValues = themeManager.getCurrentValues();
currentValues = valuesCache.getCurrentValues();
colors = currentValues.getColors();
themeValues = themeManager.getThemeValues();
defaultValues = themeManager.getDefaults();
lightDefaultValues = themeManager.getApplicationLightDefaults();
darkDefaultValues = themeManager.getApplicationDarkDefaults();
themeValues = valuesCache.getThemeValues();
defaultValues = valuesCache.getDefaultValues();
lightDefaultValues = valuesCache.getLightValues();
darkDefaultValues = valuesCache.getDarkValues();
}
@@ -110,7 +110,7 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
return null;
}
class IdColumn extends AbstractDynamicTableColumn<ColorValue, String, Object> {
private class IdColumn extends AbstractDynamicTableColumn<ColorValue, String, Object> {
@Override
public String getColumnName() {
@@ -129,7 +129,8 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
}
}
class ValueColumn extends AbstractDynamicTableColumn<ColorValue, ResolvedColor, Object> {
private class ValueColumn
extends AbstractDynamicTableColumn<ColorValue, ResolvedColor, Object> {
private ThemeColorRenderer renderer;
private String name;
private Supplier<GThemeValueMap> valueSupplier;
@@ -236,7 +237,7 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
}
static class SwatchIcon implements Icon {
private static class SwatchIcon implements Icon {
private Color color;
private Color border;
@@ -264,8 +265,5 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
}
}
record ResolvedColor(String id, String refId, Color color) {
//
}
private record ResolvedColor(String id, String refId, Color color) { /**/ }
}
@@ -51,6 +51,8 @@ public class ThemeDialog extends DialogComponentProvider {
private ThemeManager themeManager;
private GThemeValuesCache valuesCache;
public ThemeDialog(ThemeManager themeManager) {
super("Theme Dialog", false);
this.themeManager = themeManager;
@@ -227,12 +229,17 @@ public class ThemeDialog extends DialogComponentProvider {
private Component buildTabedTables() {
tabbedPane = new JTabbedPane();
colorTable = new ThemeColorTable(themeManager);
fontTable = new ThemeFontTable(themeManager);
iconTable = new ThemeIconTable(themeManager);
valuesCache = new GThemeValuesCache(themeManager);
colorTable = new ThemeColorTable(themeManager, valuesCache);
iconTable = new ThemeIconTable(themeManager, valuesCache);
fontTable = new ThemeFontTable(themeManager, valuesCache);
tabbedPane.add("Colors", colorTable);
tabbedPane.add("Fonts", fontTable);
tabbedPane.add("Icons", iconTable);
return tabbedPane;
}
@@ -284,6 +291,7 @@ public class ThemeDialog extends DialogComponentProvider {
private class DialogThemeListener implements ThemeListener {
@Override
public void themeChanged(ThemeEvent event) {
valuesCache.clear();
if (event.haveAllValuesChanged()) {
reset();
return;
@@ -43,11 +43,11 @@ public class ThemeFontTable extends JPanel implements ActionContextProvider {
private GFilterTable<FontValue> filterTable;
private ThemeManager themeManager;
public ThemeFontTable(ThemeManager themeManager) {
public ThemeFontTable(ThemeManager themeManager, GThemeValuesCache valuesProvider) {
super(new BorderLayout());
this.themeManager = themeManager;
fontTableModel = new ThemeFontTableModel(themeManager);
fontTableModel = new ThemeFontTableModel(valuesProvider);
filterTable = new GFilterTable<>(fontTableModel);
table = filterTable.getTable();
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
@@ -24,7 +24,8 @@ import java.util.function.Supplier;
import javax.swing.JLabel;
import docking.widgets.table.*;
import generic.theme.*;
import generic.theme.FontValue;
import generic.theme.GThemeValueMap;
import ghidra.docking.settings.Settings;
import ghidra.framework.plugintool.ServiceProvider;
import ghidra.framework.plugintool.ServiceProviderStub;
@@ -39,11 +40,11 @@ public class ThemeFontTableModel extends GDynamicColumnTableModel<FontValue, Obj
private GThemeValueMap currentValues;
private GThemeValueMap themeValues;
private GThemeValueMap defaultValues;
private ThemeManager themeManager;
private GThemeValuesCache valuesProvider;
public ThemeFontTableModel(ThemeManager themeManager) {
public ThemeFontTableModel(GThemeValuesCache valuesProvider) {
super(new ServiceProviderStub());
this.themeManager = themeManager;
this.valuesProvider = valuesProvider;
load();
}
@@ -51,7 +52,7 @@ public class ThemeFontTableModel extends GDynamicColumnTableModel<FontValue, Obj
* Reloads the just the current values shown in the table. Called whenever a font changes.
*/
public void reloadCurrent() {
currentValues = themeManager.getCurrentValues();
currentValues = valuesProvider.getCurrentValues();
fonts = currentValues.getFonts();
fireTableDataChanged();
}
@@ -66,10 +67,10 @@ public class ThemeFontTableModel extends GDynamicColumnTableModel<FontValue, Obj
}
private void load() {
currentValues = themeManager.getCurrentValues();
currentValues = valuesProvider.getCurrentValues();
fonts = currentValues.getFonts();
themeValues = themeManager.getThemeValues();
defaultValues = themeManager.getDefaults();
themeValues = valuesProvider.getThemeValues();
defaultValues = valuesProvider.getDefaultValues();
}
@Override
@@ -97,19 +98,28 @@ public class ThemeFontTableModel extends GDynamicColumnTableModel<FontValue, Obj
return null;
}
private String getValueText(FontValue fontValue) {
if (fontValue == null) {
/**
* Returns the original value for the id as defined by the current theme
* @param id the resource id to get a font value for
* @return the original value for the id as defined by the current theme
*/
public FontValue getThemeValue(String id) {
return themeValues.getFont(id);
}
private String getValueText(ResolvedFont resolvedFont) {
if (resolvedFont == null) {
return "<No Value>";
}
if (fontValue.getReferenceId() != null) {
return "[" + fontValue.getReferenceId() + "]";
if (resolvedFont.refId() != null) {
return "[" + resolvedFont.refId() + "]";
}
Font font = fontValue.getRawValue();
Font font = resolvedFont.font();
return FontValue.fontToString(font);
}
class IdColumn extends AbstractDynamicTableColumn<FontValue, String, Object> {
private class IdColumn extends AbstractDynamicTableColumn<FontValue, String, Object> {
@Override
public String getColumnName() {
@@ -128,7 +138,8 @@ public class ThemeFontTableModel extends GDynamicColumnTableModel<FontValue, Obj
}
}
class FontValueColumn extends AbstractDynamicTableColumn<FontValue, FontValue, Object> {
private class FontValueColumn
extends AbstractDynamicTableColumn<FontValue, ResolvedFont, Object> {
private ThemeFontRenderer renderer;
private String name;
private Supplier<GThemeValueMap> valueSupplier;
@@ -145,19 +156,23 @@ public class ThemeFontTableModel extends GDynamicColumnTableModel<FontValue, Obj
}
@Override
public FontValue getValue(FontValue fontValue, Settings settings, Object data,
public ResolvedFont getValue(FontValue themeFont, Settings settings, Object data,
ServiceProvider provider) throws IllegalArgumentException {
GThemeValueMap valueMap = valueSupplier.get();
String id = fontValue.getId();
return valueMap.getFont(id);
String id = themeFont.getId();
FontValue fontValue = valueMap.getFont(id);
if (fontValue == null) {
return null;
}
return new ResolvedFont(id, fontValue.getReferenceId(), valueMap.getResolvedFont(id));
}
@Override
public GColumnRenderer<FontValue> getColumnRenderer() {
public GColumnRenderer<ResolvedFont> getColumnRenderer() {
return renderer;
}
public Comparator<FontValue> getComparator() {
public Comparator<ResolvedFont> getComparator() {
return (v1, v2) -> {
if (v1 == null && v2 == null) {
return 0;
@@ -179,33 +194,31 @@ public class ThemeFontTableModel extends GDynamicColumnTableModel<FontValue, Obj
}
private class ThemeFontRenderer extends AbstractGColumnRenderer<FontValue> {
private class ThemeFontRenderer extends AbstractGColumnRenderer<ResolvedFont> {
@Override
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
JLabel label = (JLabel) super.getTableCellRendererComponent(data);
FontValue fontValue = (FontValue) data.getValue();
ResolvedFont resolvedFont = (ResolvedFont) data.getValue();
String text = getValueText(fontValue);
String text = getValueText(resolvedFont);
label.setText(text);
label.setOpaque(true);
Font font = resolvedFont.font();
if (font != null) {
setToolTipText(FontValue.fontToString(font));
}
return label;
}
@Override
public String getFilterString(FontValue fontValue, Settings settings) {
return getValueText(fontValue);
public String getFilterString(ResolvedFont resolvedFont, Settings settings) {
return getValueText(resolvedFont);
}
}
/**
* Returns the original value for the id as defined by the current theme
* @param id the resource id to get a font value for
* @return the original value for the id as defined by the current theme
*/
public FontValue getThemeValue(String id) {
return themeValues.getFont(id);
}
private record ResolvedFont(String id, String refId, Font font) {/**/}
}
@@ -41,10 +41,10 @@ public class ThemeIconTable extends JPanel implements ActionContextProvider {
private GFilterTable<IconValue> filterTable;
private ThemeManager themeManager;
public ThemeIconTable(ThemeManager themeManager) {
public ThemeIconTable(ThemeManager themeManager, GThemeValuesCache valuesProvider) {
super(new BorderLayout());
this.themeManager = themeManager;
iconTableModel = new ThemeIconTableModel(themeManager);
iconTableModel = new ThemeIconTableModel(valuesProvider);
filterTable = new GFilterTable<>(iconTableModel);
table = filterTable.getTable();
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
@@ -39,11 +39,11 @@ public class ThemeIconTableModel extends GDynamicColumnTableModel<IconValue, Obj
private GThemeValueMap currentValues;
private GThemeValueMap themeValues;
private GThemeValueMap defaultValues;
private ThemeManager themeManager;
private GThemeValuesCache valuesProvider;
public ThemeIconTableModel(ThemeManager themeManager) {
public ThemeIconTableModel(GThemeValuesCache valuesProvider) {
super(new ServiceProviderStub());
this.themeManager = themeManager;
this.valuesProvider = valuesProvider;
load();
}
@@ -51,7 +51,7 @@ public class ThemeIconTableModel extends GDynamicColumnTableModel<IconValue, Obj
* Reloads the just the current values shown in the table. Called whenever an icon changes.
*/
public void reloadCurrent() {
currentValues = themeManager.getCurrentValues();
currentValues = valuesProvider.getCurrentValues();
icons = currentValues.getIcons();
fireTableDataChanged();
}
@@ -66,10 +66,10 @@ public class ThemeIconTableModel extends GDynamicColumnTableModel<IconValue, Obj
}
private void load() {
currentValues = themeManager.getCurrentValues();
currentValues = valuesProvider.getCurrentValues();
icons = currentValues.getIcons();
themeValues = themeManager.getThemeValues();
defaultValues = themeManager.getDefaults();
themeValues = valuesProvider.getThemeValues();
defaultValues = valuesProvider.getDefaultValues();
}
@Override
@@ -97,7 +97,16 @@ public class ThemeIconTableModel extends GDynamicColumnTableModel<IconValue, Obj
return null;
}
class IdColumn extends AbstractDynamicTableColumn<IconValue, String, Object> {
/**
* Returns the original value for the id as defined by the current theme
* @param id the resource id to get a font value for
* @return the original value for the id as defined by the current theme
*/
public IconValue getThemeValue(String id) {
return themeValues.getIcon(id);
}
private class IdColumn extends AbstractDynamicTableColumn<IconValue, String, Object> {
@Override
public String getColumnName() {
@@ -116,7 +125,8 @@ public class ThemeIconTableModel extends GDynamicColumnTableModel<IconValue, Obj
}
}
class IconValueColumn extends AbstractDynamicTableColumn<IconValue, ResolvedIcon, Object> {
private class IconValueColumn
extends AbstractDynamicTableColumn<IconValue, ResolvedIcon, Object> {
private ThemeIconRenderer renderer;
private String name;
private Supplier<GThemeValueMap> valueSupplier;
@@ -232,14 +242,6 @@ public class ThemeIconTableModel extends GDynamicColumnTableModel<IconValue, Obj
}
}
record ResolvedIcon(String id, String refId, Icon icon) {/**/}
private record ResolvedIcon(String id, String refId, Icon icon) {/**/}
/**
* Returns the original value for the id as defined by the current theme
* @param id the resource id to get a font value for
* @return the original value for the id as defined by the current theme
*/
public IconValue getThemeValue(String id) {
return themeValues.getIcon(id);
}
}
@@ -34,6 +34,7 @@ public class GTreeRenderer extends DefaultTreeCellRenderer implements GComponent
private static final int DEFAULT_MIN_ICON_WIDTH = 22;
private static final Color BACKGROUND_UNSELECTED = new GColor("color.bg.tree");
private static final Color BACKGROUND_SELECTED = new GColor("color.bg.tree.selected");
private static final Color FOREGROUND_SELECTED = new GColor("color.fg.tree.selected");
private Object dropTarget;
private boolean paintDropTarget;
@@ -46,6 +47,7 @@ public class GTreeRenderer extends DefaultTreeCellRenderer implements GComponent
setHTMLRenderingEnabled(false);
setBackgroundNonSelectionColor(BACKGROUND_UNSELECTED);
setBackgroundSelectionColor(BACKGROUND_SELECTED);
setTextSelectionColor(FOREGROUND_SELECTED);
}
@Override
@@ -8,7 +8,6 @@
##MODULE IP: Tango Icons - Public Domain
.classpath||GHIDRA||||END|
Module.manifest||GHIDRA||||END|
data/gui.laf.overrides.theme.properties||GHIDRA||||END|
data/gui.palette.theme.properties||GHIDRA||||END|
data/gui.theme.properties||GHIDRA||||END|
src/main/java/ghidra/framework/options/package.html||GHIDRA||||END|
@@ -1,55 +0,0 @@
[Defaults]
// TODO these are only here because they are used in the dark section; remove from here if done in
// source code instead; otherwise, update error reporting to not require an entry in the default
// section for values defined in specific LaF sections
color.flat.text.original.bg = white // default 'text' value in Flat Light
color.flat.selection.inactive.bg = #d3d3d3 // default value in Flat Light
[Dark Defaults]
[Flat Dark]
// the default inactive selection color is too close to the bg color to be easily visible
color.flat.selection.inactive.bg = #0F4C6A
//
// We would like widgets to use a bg color. By default widgets and some other items are all mapped
// to 'text'. The easiest way to change all widgets is to change the value of 'text'. Then, for
// any values that should still use the old value, we need to remap those. (The foreground colors
// for these are mapped to 'textText'. For now, that value seems good enough that we do not need
// to change it.)
//
color.flat.text.original.bg = #46494b // default 'text' value
[color]text = color.bg
[color]desktop = color.flat.text.original.bg
[color]TableHeader = color.flat.text.original.bg
[color]Checkbox.icon.background = color.flat.text.original.bg
[color]Checkbox.icon.selectedBackground = color.flat.text.original.bg
[color]CheckBox.icon[filled].checkmarkColor = color.flat.text.original.bg
[color]ComboBox.buttonBackground = color.flat.text.original.bg
[color]Spinner.background = color.flat.text.original.bg
[color]TextArea.background = color.bg
[color]TextArea.foreground = color.fg
[color]TextPane.background = color.bg
[color]TextPane.foreground = color.fg
[Nimbus]
// Nimbus uses the ToolTipPainter class to paint tooltips. That class does not read the property
// we use for tooltips, which is 'ToolTip.background', even though that is defined by the LaF.
// Setting the 'info' value here to changes the key the painter users to paint tooltips. The info
// value seems to only be used for tooltips, which means this change affects no other components.
[color]info = [color]ToolTip.background
+9 -21
View File
@@ -1,7 +1,8 @@
[Defaults]
color.bg = white // note: this is the text/widget bg color
color.fg = black
// we define these as shortcuts for the view foreground, background
color.bg = [color]system.color.bg.view
color.fg = [color]system.color.fg.view
// On some LaFs the tables and tree use the bg color we define. Make that consistent for all LaFs.
[color]Viewport.background = color.bg
@@ -12,12 +13,10 @@ color.cursor.unfocused = pink
color.fg.error = red
color.bg.error = lightcoral
color.fg.disabled = lightGray
color.bg.uneditable = system.color.bg.application // TODO see if there exists an LaF setting for this
color.bg.uneditable = [color]system.color.bg.control
color.bg.filtered = yellow
color.fg.hint = gray
color.bg.tooltip = [color]ToolTip.background
color.fg.messages.hint = color.fg.hint
color.fg.messages.alert = orange
color.fg.messages.error = color.fg.error
@@ -35,14 +34,12 @@ color.fg.table.unselected = white
color.fg.error.table.unselected = color.fg.error
color.fg.error.table.selected = lightpink
color.bg.tree = color.bg
color.bg.tree.selected = [color]Tree.selectionBackground
color.bg.tree = [color]system.color.bg.view
color.bg.tree.selected = [color]system.color.bg.selected.view
color.fg.tree.selected = [color]system.color.fg.selected.view
// Fonts
font.standard = [font]Panel.font
font.bold = font.standard[bold]
font.italic = font.standard[italic]
font.bold.italic = font.standard[bold][italic]
font.standard = [font]system.font.control
font.monospaced = monospaced-PLAIN-12
// Icons files
@@ -109,9 +106,6 @@ icon.arrow.up.left = viewmagfit.png[rotate(275)]
[Dark Defaults]
color.fg = lightgray
color.bg = #1c1d1e
color.fg.error = indianRed
color.fg.disabled = gray
color.bg.filtered = beige
@@ -125,15 +119,9 @@ color.fg.table.uneditable.selected = lemonchiffon
color.fg.table.uneditable.unselected = lightgray
color.bg.tree = color.bg
color.bg.tree.selected = [color]Tree.selectionBackground
color.bg.tree.selected = [color]laf.color.Tree.selectionBackground
// this looks different than the light mode version; good enough until we make a better icon
icon.make.selection = stack.png
[CDE/Motif]
color.bg = [color]window // gray for motif
color.fg = [color]textText
@@ -16,28 +16,27 @@
package generic.theme;
/**
* Loads all the system theme.property files that contain all the default color, font, and
* icon values.
* Provides theme default values, such as those loaded from {@code *.theme.property} files.
*/
public interface ThemeDefaultsProvider {
public interface ApplicationThemeDefaults {
/**
* Returns the standard defaults {@link GThemeValueMap}
* @return the standard defaults {@link GThemeValueMap}
* Returns the light default {@link GThemeValueMap}
* @return the light default {@link GThemeValueMap}
*/
public GThemeValueMap getDefaults();
public GThemeValueMap getLightValues();
/**
* Returns the dark defaults {@link GThemeValueMap}
* @return the dark defaults {@link GThemeValueMap}
* Returns the dark default {@link GThemeValueMap}
* @return the dark default {@link GThemeValueMap}
*/
public GThemeValueMap getDarkDefaults();
public GThemeValueMap getDarkValues();
/**
* Returns the defaults specific to a given Look and Feel
* Returns the default values specific to a given Look and Feel
* @param lafType the Look and Feel type
* @return the defaults specific to a given Look and Feel
* @return the default values specific to a given Look and Feel
*/
public GThemeValueMap getLookAndFeelDefaults(LafType lafType);
public GThemeValueMap getLookAndFeelValues(LafType lafType);
}
@@ -73,7 +73,7 @@ public class ApplicationThemeManager extends ThemeManager {
@Override
public void reloadApplicationDefaults() {
themeDefaultsProvider = getThemeDefaultsProvider();
applicationDefaults = getApplicationDefaults();
buildCurrentValues();
lookAndFeelManager.resetAll(javaDefaults);
notifyThemeChanged(new AllValuesChangedThemeEvent(false));
@@ -127,6 +127,7 @@ public class ApplicationThemeManager extends ThemeManager {
if (theme.hasSupportedLookAndFeel()) {
activeTheme = theme;
LafType lafType = theme.getLookAndFeelType();
cleanUiDefaults(); // clear out any values previous themes may have installed
lookAndFeelManager = lafType.getLookAndFeelManager(this);
try {
lookAndFeelManager.installLookAndFeel();
@@ -247,20 +248,6 @@ public class ApplicationThemeManager extends ThemeManager {
return gColor;
}
/**
* Sets specially defined system UI values. These values are created by the application as a
* convenience for mapping generic concepts to values that differ by Look and Feel. This allows
* clients to use 'system' properties without knowing the actual Look and Feel terms.
*
* <p>For example, 'system.color.border' defaults to 'controlShadow', but maps to 'nimbusBorder'
* in the Nimbus Look and Feel.
*
* @param map the map
*/
public void setSystemDefaults(GThemeValueMap map) {
systemValues = map;
}
/**
* Sets the map of Java default UI values. These are the UI values defined by the current Java
* Look and Feel.
@@ -409,4 +396,9 @@ public class ApplicationThemeManager extends ThemeManager {
GColor.refreshAll(currentValues);
GIcon.refreshAll(currentValues);
}
private void cleanUiDefaults() {
UIDefaults defaults = UIManager.getDefaults();
defaults.clear();
}
}
@@ -30,7 +30,6 @@ import utilities.util.reflection.ReflectionUtilities;
public class ColorValue extends ThemeValue<Color> {
private static final String COLOR_ID_PREFIX = "color.";
private static final String EXTERNAL_PREFIX = "[color]";
private static final String SYSTEM_COLOR_PREFIX = "system.color";
public static final Color LAST_RESORT_DEFAULT = new Color(128, 128, 128);
@@ -72,8 +71,7 @@ public class ColorValue extends ThemeValue<Color> {
* @return true if the given key string is a valid external key for a color value
*/
public static boolean isColorKey(String key) {
return key.startsWith(COLOR_ID_PREFIX) || key.startsWith(EXTERNAL_PREFIX) ||
key.startsWith(SYSTEM_COLOR_PREFIX);
return key.startsWith(COLOR_ID_PREFIX) || key.startsWith(EXTERNAL_PREFIX);
}
/**
@@ -107,15 +105,14 @@ public class ColorValue extends ThemeValue<Color> {
"Application", "ghidra.GhidraRun", "java.lang.Class", "java.lang.Thread");
t.setStackTrace(filtered);
Msg.error(this,
"Could not resolve indirect color path for \"" + unresolvedId +
"\" for primary id \"" + primaryId + "\", using last resort default",
t);
Msg.error(this, "Could not resolve indirect color path for \"" + unresolvedId +
"\" for primary id \"" + primaryId + "\", using last resort default", t);
return LAST_RESORT_DEFAULT;
}
private static String toExternalId(String internalId) {
if (internalId.startsWith(COLOR_ID_PREFIX) || internalId.startsWith(SYSTEM_COLOR_PREFIX)) {
if (internalId.startsWith(COLOR_ID_PREFIX)) {
return internalId;
}
return EXTERNAL_PREFIX + internalId;
@@ -37,6 +37,8 @@ import ghidra.util.datastruct.WeakStore;
* set the default value by adding this line "color.mywidget.bg = white".
*/
public class GColor extends Color {
private static final int MISSING_COLOR_RGB = 0x808080;
// keeps a weak reference to all uses of GColor, so their cached color value can be refreshed
private static WeakStore<GColor> inUseColors = new WeakStore<>();
@@ -50,11 +52,22 @@ public class GColor extends Color {
* @param id the id used to lookup the current value for this color
*/
public GColor(String id) {
super(0x808080);
super(MISSING_COLOR_RGB);
this.id = id;
delegate = Gui.getColor(id);
inUseColors.add(this);
}
/**
* Copy constructor. Used primarily to convert a GColorUiResource to a GColor without having to
* lookup the color which can cause errors during theme transitions.
* @param gColor the gColor to copy
*/
protected GColor(GColor gColor) {
super(MISSING_COLOR_RGB);
this.id = gColor.id;
delegate = gColor.delegate;
inUseColors.add(this);
}
private GColor(String id, int alpha) {
@@ -15,8 +15,6 @@
*/
package generic.theme;
import java.awt.Color;
import javax.swing.UIDefaults;
import javax.swing.plaf.UIResource;
@@ -36,8 +34,8 @@ public class GColorUIResource extends GColor implements UIResource {
* Returns a non-UIResource GColor for this GColorUiResource's id
* @return a non-UIResource GColor for this GColorUiResource's id
*/
public Color toGColor() {
return new GColor(getId());
public GColor toGColor() {
return new GColor(this);
}
}
@@ -15,6 +15,8 @@
*/
package generic.theme;
import static generic.theme.SystemThemeIds.*;
import java.awt.Color;
/** TODO doc how clients should use this in their code, with
@@ -24,18 +26,9 @@ import java.awt.Color;
* Colors.Java.BORDER
*/
public class GThemeDefaults {
public static class Ids {
public static class Java {
public static final String BORDER = "system.color.border";
}
public static class Fonts {
public static final String STANDARD = "font.standard";
public static final String BOLD = "font.bold";
public static final String ITALIC = "font.italic";
public static final String BOLD_ITALIC = "font.bold.italic";
public static final String MONOSPACED = "font.monospaced";
}
}
@@ -44,11 +37,23 @@ public class GThemeDefaults {
* Colors mapped to system values
*/
public static class Colors {
//@formatter:off
// standard color concepts defined by LookAndFeel
public static final GColor BG_CONTROL = new GColor(BG_CONTROL_ID);
public static final GColor BG_VIEW = new GColor(BG_VIEW_ID);
public static final GColor BG_TOOLTIP = new GColor(BG_TOOLTIP_ID);
public static final GColor BG_VIEW_SELECTED = new GColor(BG_VIEW_SELECTED_ID);
public static final GColor BG_BORDER = new GColor(BG_BORDER_ID);
public static final GColor FG_CONTROL = new GColor(FG_CONTROL_ID);
public static final GColor FG_VIEW = new GColor(FG_VIEW_ID);
public static final GColor FG_TOOLTIP = new GColor(FG_TOOLTIP_ID);
public static final GColor FG_VIEW_SELECTED = new GColor(FG_VIEW_SELECTED_ID);
public static final GColor FG_DISABLED = new GColor(FG_DISABLED_ID);
// generic color concepts
//@formatter:off
public static final GColor BACKGROUND = new GColor("color.bg");
public static final GColor BACKGROUND_TOOLTIP = new GColor("color.bg.tooltip");
public static final GColor CURSOR = new GColor("color.cursor.focused");
public static final GColor DISABLED = new GColor("color.palette.disabled");
public static final GColor ERROR = new GColor("color.fg.error"); // TODO replace most uses of this with Messages.ERROR
@@ -57,7 +62,7 @@ public class GThemeDefaults {
//@formatter:on
public static class Java {
public static final GColor BORDER = new GColor(Ids.Java.BORDER);
public static final GColor BORDER = BG_BORDER;
}
public static class Tables {
@@ -15,6 +15,8 @@
*/
package generic.theme;
import java.awt.Color;
import java.awt.Font;
import java.io.File;
import java.net.URL;
import java.util.*;
@@ -340,4 +342,50 @@ public class GThemeValueMap {
public Set<String> getIconIds() {
return iconMap.keySet();
}
/**
* Returns the resolved color, following indirections as need to get the color ultimately
* assigned to the given id.
* @param id the id for which to get a color
* @return the resolved color, following indirections as need to get the color ultimately
* assigned to the given id.
*/
public Color getResolvedColor(String id) {
ColorValue colorValue = colorMap.get(id);
if (colorValue != null) {
return colorValue.get(this);
}
return null;
}
/**
* Returns the resolved font, following indirections as need to get the font ultimately
* assigned to the given id.
* @param id the id for which to get a font
* @return the resolved font, following indirections as need to get the font ultimately
* assigned to the given id
*/
public Font getResolvedFont(String id) {
FontValue fontValue = fontMap.get(id);
if (fontValue != null) {
return fontValue.get(this);
}
return null;
}
/**
* Returns the resolved icon, following indirections as need to get the icon ultimately
* assigned to the given id.
* @param id the id for which to get an icon
* @return the resolved icon, following indirections as need to get the icon ultimately
* assigned to the given id
*/
public Icon getResolvedIcon(String id) {
IconValue iconValue = iconMap.get(id);
if (iconValue != null) {
return iconValue.get(this);
}
return null;
}
}
@@ -26,13 +26,13 @@ import ghidra.util.Msg;
* Loads all the system theme.property files that contain all the default color, font, and
* icon values.
*/
public class ApplicationThemeDefaultsProvider implements ThemeDefaultsProvider {
public class PropertyFileThemeDefaults implements ApplicationThemeDefaults {
private GThemeValueMap defaults = new GThemeValueMap();
private GThemeValueMap darkDefaults = new GThemeValueMap();
private Map<LafType, GThemeValueMap> lafDefaultsMap = new HashMap<>();
ApplicationThemeDefaultsProvider() {
PropertyFileThemeDefaults() {
loadThemeDefaultFiles();
}
@@ -69,17 +69,17 @@ public class ApplicationThemeDefaultsProvider implements ThemeDefaultsProvider {
}
@Override
public GThemeValueMap getDefaults() {
public GThemeValueMap getLightValues() {
return defaults;
}
@Override
public GThemeValueMap getDarkDefaults() {
public GThemeValueMap getDarkValues() {
return darkDefaults;
}
@Override
public GThemeValueMap getLookAndFeelDefaults(LafType lafType) {
public GThemeValueMap getLookAndFeelValues(LafType lafType) {
return lafDefaultsMap.get(lafType);
}
@@ -215,21 +215,21 @@ public class StubThemeManager extends ThemeManager {
}
@Override
protected ThemeDefaultsProvider getThemeDefaultsProvider() {
return new ThemeDefaultsProvider() {
protected ApplicationThemeDefaults getApplicationDefaults() {
return new ApplicationThemeDefaults() {
@Override
public GThemeValueMap getDefaults() {
public GThemeValueMap getLightValues() {
return null;
}
@Override
public GThemeValueMap getDarkDefaults() {
public GThemeValueMap getDarkValues() {
return null;
}
@Override
public GThemeValueMap getLookAndFeelDefaults(LafType lafType) {
public GThemeValueMap getLookAndFeelValues(LafType lafType) {
return null;
}
@@ -0,0 +1,68 @@
/* ###
* 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;
import generic.theme.laf.UiDefaultsMapper;
/**
* These are the standard system ids defined to represent general LookAndFeel color and font
* concepts. Various LaF have different names for these concepts and even defines additional
* concepts. These are the ones we use regardless of the LookAndFeel being used. When we
* load a specific LookAndFeel, a {@link UiDefaultsMapper}, specific to that LaF is used to map
* its system ids to our standard system ids. Also, {@link GThemeDefaults} uses these system
* ids to define colors that can be used throughout the application without using these ids
* directly.
* <P>
* The ids are assigned to categories as follows:
* <UL>
* <LI>CONTROL- these ids are used for colors and fonts for general system components such as
* Buttons, Checkboxes, or anything that doesn't fit into one of the other areas</LI>
* <LI>VIEW - these ids are used for the colors and fonts used for widgets that display data
* such as Trees, Tables, TextFieds, and Lists</LI>
* <LI>MENU - these ids are used by menu components such as Menus and MenuItems.</LI>
* <LI>TOOLTIP - these ids are used just by the tooltip component
* </UL>
* <P>
* For each of those categories the ids specify a specific property for those components.
* <UL>
* <LI> BG - the background color
* <LI> FG - the foreground color
* <LI> BG_SELECTED - the background color when the component is selected
* <LI> FG_SELECTED - the foreground color when the component is selected
* <LI> FG_DISABLED - the foreground color when the component is disabled
* <LI> BG_BORDER - the border color
* <LI> FONT - the font
*
* </UL>
*/
public class SystemThemeIds {
public static final String FONT_CONTROL_ID = "system.font.control";
public static final String FONT_VIEW_ID = "system.font.view";
public static final String FONT_MENU_ID = "system.font.menu";
public static final String BG_CONTROL_ID = "system.color.bg.control";
public static final String BG_VIEW_ID = "system.color.bg.view";
public static final String BG_TOOLTIP_ID = "system.color.bg.tooltip";
public static final String BG_VIEW_SELECTED_ID = "system.color.bg.selected.view";
public static final String BG_BORDER_ID = "system.color.bg.border";
public static final String FG_CONTROL_ID = "system.color.fg.control";
public static final String FG_VIEW_ID = "system.color.fg.view";
public static final String FG_TOOLTIP_ID = "system.color.fg.tooltip";
public static final String FG_VIEW_SELECTED_ID = "system.color.fg.selected.view";
public static final String FG_DISABLED_ID = "system.color.fg.disabled";
}
@@ -30,7 +30,6 @@ import ghidra.util.datastruct.WeakDataStructureFactory;
import ghidra.util.datastruct.WeakSet;
import resources.ResourceManager;
import utilities.util.reflection.ReflectionUtilities;
import utility.function.Callback;
/**
* This class manages application themes and their values. The ThemeManager is an abstract
@@ -67,10 +66,9 @@ public abstract class ThemeManager {
protected GTheme activeTheme = getDefaultTheme();
protected GThemeValueMap javaDefaults = new GThemeValueMap();
protected GThemeValueMap systemValues = new GThemeValueMap();
protected GThemeValueMap currentValues = new GThemeValueMap();
protected ThemeDefaultsProvider themeDefaultsProvider;
protected ApplicationThemeDefaults applicationDefaults;
// these notifications are only when the user is manipulating theme values, so rare and at
// user speed, so using copy on read
@@ -86,11 +84,11 @@ public abstract class ThemeManager {
// default behavior is only install to INSTANCE if first time
INSTANCE = this;
}
themeDefaultsProvider = getThemeDefaultsProvider();
applicationDefaults = getApplicationDefaults();
}
protected ThemeDefaultsProvider getThemeDefaultsProvider() {
return new ApplicationThemeDefaultsProvider();
protected ApplicationThemeDefaults getApplicationDefaults() {
return new PropertyFileThemeDefaults();
}
protected void installInGui() {
@@ -101,12 +99,11 @@ public abstract class ThemeManager {
GThemeValueMap map = new GThemeValueMap();
map.load(javaDefaults);
map.load(systemValues);
map.load(themeDefaultsProvider.getDefaults());
map.load(applicationDefaults.getLightValues());
if (activeTheme.useDarkDefaults()) {
map.load(themeDefaultsProvider.getDarkDefaults());
map.load(applicationDefaults.getDarkValues());
}
map.load(themeDefaultsProvider.getLookAndFeelDefaults(getLookAndFeelType()));
map.load(applicationDefaults.getLookAndFeelValues(getLookAndFeelType()));
map.load(activeTheme);
currentValues = map;
}
@@ -270,12 +267,11 @@ public abstract class ThemeManager {
public GThemeValueMap getThemeValues() {
GThemeValueMap map = new GThemeValueMap();
map.load(javaDefaults);
map.load(systemValues);
map.load(themeDefaultsProvider.getDefaults());
map.load(applicationDefaults.getLightValues());
if (activeTheme.useDarkDefaults()) {
map.load(themeDefaultsProvider.getDarkDefaults());
map.load(applicationDefaults.getDarkValues());
}
map.load(themeDefaultsProvider.getLookAndFeelDefaults(getLookAndFeelType()));
map.load(applicationDefaults.getLookAndFeelValues(getLookAndFeelType()));
map.load(activeTheme);
return map;
}
@@ -418,9 +414,9 @@ public abstract class ThemeManager {
* theme.properties files
*/
public GThemeValueMap getApplicationDarkDefaults() {
GThemeValueMap map = new GThemeValueMap(themeDefaultsProvider.getDefaults());
map.load(themeDefaultsProvider.getDarkDefaults());
map.load(themeDefaultsProvider.getLookAndFeelDefaults(getLookAndFeelType()));
GThemeValueMap map = new GThemeValueMap(applicationDefaults.getLightValues());
map.load(applicationDefaults.getDarkValues());
map.load(applicationDefaults.getLookAndFeelValues(getLookAndFeelType()));
return map;
}
@@ -431,10 +427,25 @@ public abstract class ThemeManager {
* theme.properties files
*/
public GThemeValueMap getApplicationLightDefaults() {
GThemeValueMap map = new GThemeValueMap(themeDefaultsProvider.getDefaults());
GThemeValueMap map = new GThemeValueMap(applicationDefaults.getLightValues());
map.load(applicationDefaults.getLookAndFeelValues(getLookAndFeelType()));
return map;
}
/**
* Returns application defaults values (does not include java default values)
* @return application defaults values (does not include java default values)
*/
public GThemeValueMap getApplicationOverrides() {
GThemeValueMap currentDefaults = new GThemeValueMap();
currentDefaults.load(applicationDefaults.getLightValues());
if (activeTheme.useDarkDefaults()) {
currentDefaults.load(applicationDefaults.getDarkValues());
}
currentDefaults.load(applicationDefaults.getLookAndFeelValues(getLookAndFeelType()));
return currentDefaults;
}
/**
* Returns a {@link GThemeValueMap} containing all default values for the current theme. It
* is a combination of application defined defaults and java {@link LookAndFeel} defaults.
@@ -442,12 +453,11 @@ public abstract class ThemeManager {
*/
public GThemeValueMap getDefaults() {
GThemeValueMap currentDefaults = new GThemeValueMap(javaDefaults);
currentDefaults.load(systemValues);
currentDefaults.load(themeDefaultsProvider.getDefaults());
currentDefaults.load(applicationDefaults.getLightValues());
if (activeTheme.useDarkDefaults()) {
currentDefaults.load(themeDefaultsProvider.getDarkDefaults());
currentDefaults.load(applicationDefaults.getDarkValues());
}
currentDefaults.load(themeDefaultsProvider.getLookAndFeelDefaults(getLookAndFeelType()));
currentDefaults.load(applicationDefaults.getLookAndFeelValues(getLookAndFeelType()));
return currentDefaults;
}
@@ -0,0 +1,85 @@
/* ###
* 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.util.Map;
import javax.swing.LookAndFeel;
import javax.swing.UIDefaults;
import javax.swing.plaf.nimbus.NimbusLookAndFeel;
import generic.theme.ApplicationThemeManager;
import generic.theme.GThemeValueMap;
import generic.theme.laf.nimbus.SelectedTreePainter;
/**
* Extends the {@link NimbusLookAndFeel} (Nimbus) to intercept {@link #getDefaults()}. Nimbus
* does not honor changes to the UIDefaults after it is installed as the active
* {@link LookAndFeel}, so we have to make the changes at the time the UIDefaults are installed.
* <P>
* To get around this issue, we extend Nimbus so that we can install our GColors and
* overridden properties as Nimbus is being installed, specifically during the call to the
* getDefaults() method. For all other Look And Feels, the GColors and overridden properties are
* changed in the UIDefaults after the Look And Feel is installed, so they don't need to extend the
* Look and Feel class.
* <P>
* Also, unlike other LaFs, Nimbus needs to be reinstalled every time we need to make a change to
* any of the UIDefaults values, since it does not respond to changes other than when first
* installed.
*/
public class CustomNimbusLookAndFeel extends NimbusLookAndFeel {
private ApplicationThemeManager themeManager;
private Map<String, String> normalizedIdToLafIdMap;
CustomNimbusLookAndFeel(ApplicationThemeManager themeManager) {
this.themeManager = themeManager;
}
@Override
public UIDefaults getDefaults() {
UIDefaults defaults = super.getDefaults();
installCustomPainters(defaults);
// normally all of this wiring is handled by the LookAndFeelManager (see above)
UiDefaultsMapper uiDefaultsMapper = new NimbusUiDefaultsMapper(defaults);
installJavaDefaultsIntoThemeManager(uiDefaultsMapper);
uiDefaultsMapper.installValuesIntoUIDefaults(getApplicationOverrides());
normalizedIdToLafIdMap = uiDefaultsMapper.getNormalizedIdToLafIdMap();
return defaults;
}
protected void installJavaDefaultsIntoThemeManager(UiDefaultsMapper uiDefaultsMapper) {
GThemeValueMap javaDefaults = uiDefaultsMapper.getJavaDefaults();
themeManager.setJavaDefaults(javaDefaults);
}
private void installCustomPainters(UIDefaults defaults) {
defaults.put("Tree:TreeCell[Enabled+Selected].backgroundPainter",
new SelectedTreePainter());
defaults.put("Tree:TreeCell[Focused+Selected].backgroundPainter",
new SelectedTreePainter());
}
public Map<String, String> getNormalizedIdToLafIdMap() {
return normalizedIdToLafIdMap;
}
protected GThemeValueMap getApplicationOverrides() {
return themeManager.getApplicationOverrides();
}
}
@@ -0,0 +1,68 @@
/* ###
* 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 static generic.theme.SystemThemeIds.*;
import java.awt.Color;
import javax.swing.UIDefaults;
import ghidra.util.WebColors;
public class FlatDarkUiDefaultsMapper extends FlatUiDefaultsMapper {
protected FlatDarkUiDefaultsMapper(UIDefaults defaults) {
super(defaults);
}
@Override
protected void assignSystemColorValues() {
super.assignSystemColorValues();
// We don't think the FlatDark LaF's view background (Trees, Tables, Lists) is dark
// enough, so we are overriding the view group background and foreground colors
assignSystemColorDirect(BG_VIEW_ID, new Color(0x1c1d1e));
assignSystemColorDirect(FG_VIEW_ID, WebColors.LIGHT_GRAY);
}
@Override
protected void assignNormalizedColorValues() {
super.assignNormalizedColorValues();
//
// These components are initialized to "text", but we want them mapped to use
// our view background color so that they look like normal editable widgets
//
overrideColor("ComboBox.background", BG_VIEW_ID);
overrideColor("ComboBox.background", BG_VIEW_ID);
overrideColor("EditorPane.background", BG_VIEW_ID);
overrideColor("FormattedTextField.background", BG_VIEW_ID);
overrideColor("List.background", BG_VIEW_ID);
overrideColor("PasswordField.background", BG_VIEW_ID);
overrideColor("Table.background", BG_VIEW_ID);
overrideColor("Table.focusCellBackground", BG_VIEW_ID);
overrideColor("TableHeader.focusCellBackground", BG_VIEW_ID);
overrideColor("TextField.background", BG_VIEW_ID);
overrideColor("Tree.background", BG_VIEW_ID);
overrideColor("Tree.textBackground", BG_VIEW_ID);
overrideColor("TextArea.background", BG_VIEW_ID);
overrideColor("TextArea.foreground", BG_VIEW_ID);
overrideColor("TextPane.background", BG_VIEW_ID);
overrideColor("TextPane.foreground", BG_VIEW_ID);
}
}
@@ -15,18 +15,16 @@
*/
package generic.theme.laf;
import javax.swing.UIDefaults;
import javax.swing.UIManager;
import generic.theme.*;
import generic.theme.ApplicationThemeManager;
import generic.theme.LafType;
public class FlatLookAndFeelManager extends LookAndFeelManager {
public FlatLookAndFeelManager(LafType laf, ApplicationThemeManager themeManager) {
super(laf, themeManager);
// establish system color to LookAndFeel colors
systemToLafMap.addColor(new ColorValue(SYSTEM_WIDGET_BACKGROUND_COLOR_ID, "text"));
systemToLafMap.addColor(new ColorValue(SYSTEM_TOOLTIP_BACKGROUND_COLOR_ID, "info"));
}
@Override
@@ -39,7 +37,10 @@ public class FlatLookAndFeelManager extends LookAndFeelManager {
}
@Override
protected ThemeGrouper getThemeGrouper() {
return new FlatThemeGrouper();
protected UiDefaultsMapper getUiDefaultsMapper(UIDefaults defaults) {
if (getLookAndFeelType() == LafType.FLAT_DARK) {
return new FlatDarkUiDefaultsMapper(defaults);
}
return new FlatUiDefaultsMapper(defaults);
}
}
@@ -1,62 +0,0 @@
/* ###
* 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 generic.theme.GThemeValueMap;
/**
* Adds specialized groupings unique to the Flat LookAndFeels
*/
public class FlatThemeGrouper extends ThemeGrouper {
@Override
public void group(GThemeValueMap values) {
// @formatter:off
defineCustomColorGroup("color.flat.menu.hover.bg", "MenuBar.hoverBackground", values);
defineCustomColorGroup("color.flat.button.hover.bg", "Button.hoverBackground", values);
defineCustomColorGroup("color.flat.button.selected.bg", "Button.selectedBackground",values);
defineCustomColorGroup("color.flat.button.toolbar.hover.bg", "Button.toolbar.hoverBackground",values);
defineCustomColorGroup("color.flat.button.toolbar.pressed.bg", "Button.toolbar.pressedBackground",values);
defineCustomColorGroup("color.flat.checkbox.icon.focus.border", "CheckBox.icon.focusedBorderColor",values);
defineCustomColorGroup("color.flat.menu.accelerator.fg", "Menu.acceleratorForeground",values);
defineCustomColorGroup("color.flat.focus.border", "Button.focusedBorderColor", values);
defineCustomColorGroup("color.flat.focus", "Component.focusColor", values);
defineCustomColorGroup("color.flat.focus.bg", "Button.focusedBackground", values);
defineCustomColorGroup("color.flat.checkmark", "CheckBox.icon.checkmarkColor", values);
defineCustomColorGroup("color.flat.disabled", "Button.disabledBorderColor", values);
defineCustomColorGroup("color.flat.disabled.selected", "Button.disabledSelectedBackground",values);
defineCustomColorGroup("color.flat.arrow", "Spinner.buttonArrowColor",values);
defineCustomColorGroup("color.flat.arrow.disabled", "Spinner.buttonDisabledArrowColor",values);
defineCustomColorGroup("color.flat.arrow.hover", "Spinner.buttonHoverArrowColor",values);
defineCustomColorGroup("color.flat.arrow.pressed", "Spinner.buttonPressedArrowColor",values);
defineCustomColorGroup("color.flat.dropcell.bg", "List.dropCellBackground",values);
defineCustomColorGroup("color.flat.dropline", "List.dropLineColor",values);
defineCustomColorGroup("color.flat.underline", "MenuItem.underlineSelectionColor",values);
defineCustomColorGroup("color.flat.docking.bg", "ToolBar.dockingBackground",values);
defineCustomColorGroup("color.flat.progressbar.bg", "ProgressBar.background",values);
defineCustomColorGroup("color.flat.progressbar.fg", "ProgressBar.foreground",values);
defineCustomColorGroup("color.flat.icon.bg", "Tree.icon.openColor",values);
defineCustomColorGroup("color.flat.selection.inactive", "Tree.selectionInactiveBackground",values);
// @formatter:on
super.group(values);
}
}
@@ -0,0 +1,65 @@
/* ###
* 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 javax.swing.UIDefaults;
public class FlatUiDefaultsMapper extends UiDefaultsMapper {
protected FlatUiDefaultsMapper(UIDefaults defaults) {
super(defaults);
}
@Override
protected void registerIgnoredLafIds() {
super.registerIgnoredLafIds();
ignoredLafIds.add("Actions.Blue");
ignoredLafIds.add("Actions.Green");
ignoredLafIds.add("Actions.Grey");
ignoredLafIds.add("Actions.Greyinline");
ignoredLafIds.add("Actions.Red");
ignoredLafIds.add("Actions.Yellow");
ignoredLafIds.add("Objects.BlackText");
ignoredLafIds.add("Objects.Blue");
ignoredLafIds.add("Objects.Green");
ignoredLafIds.add("Objects.GreenAndroid");
ignoredLafIds.add("Objects.Grey");
ignoredLafIds.add("Objects.Pink");
ignoredLafIds.add("Objects.Purple");
ignoredLafIds.add("Objects.Red");
ignoredLafIds.add("Objects.RedStatus");
ignoredLafIds.add("Objects.Yellow");
ignoredLafIds.add("Objects.YellowDark");
ignoredLafIds.add("h0.font");
ignoredLafIds.add("h00.font");
ignoredLafIds.add("h1.font");
ignoredLafIds.add("h1.regular.font");
ignoredLafIds.add("h2.font");
ignoredLafIds.add("h2.regular.font");
ignoredLafIds.add("h3.font");
ignoredLafIds.add("h3.regular.font");
ignoredLafIds.add("h4.font");
ignoredLafIds.add("large.font");
ignoredLafIds.add("light.font");
ignoredLafIds.add("medium.font");
ignoredLafIds.add("mini.font");
ignoredLafIds.add("monospaced.font");
ignoredLafIds.add("small.font");
}
}
@@ -1,120 +0,0 @@
/* ###
* 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.Color;
import java.awt.Font;
import java.util.List;
import javax.swing.*;
import javax.swing.plaf.FontUIResource;
import javax.swing.plaf.nimbus.NimbusLookAndFeel;
import generic.theme.*;
import generic.theme.laf.nimbus.SelectedTreePainter;
/**
* Extends the {@link NimbusLookAndFeel} to intercept the {@link #getDefaults()}. Nimbus does
* not honor changes to the UIDefaults after it is installed as the active
* {@link LookAndFeel}, so we have to make the changes at the time the UIDefaults are installed.
*
* To get around this issue, we extend the NimbusLookAndFeel
* so that we can install our GColors and overridden properties as Nimbus is being installed,
* specifically during the call to the getDefaults() method. For all other Look And Feels, the
* GColors and overridden properties are changed in the UIDefaults after the Look And Feel is
* installed, so they don't need to extends the Look and Feel class.
*
* Also, note that Nimbus needs to be reinstalled every time we need to make a change to any of the
* UIDefaults values, since it does not respond to changes other than when first installed.
*/
public class GNimbusLookAndFeel extends NimbusLookAndFeel {
private ApplicationThemeManager themeManager;
GNimbusLookAndFeel(ApplicationThemeManager themeManager) {
this.themeManager = themeManager;
}
@Override
public UIDefaults getDefaults() {
UIDefaults defaults = super.getDefaults();
installCustomPainters(defaults);
GThemeValueMap javaDefaults = extractJavaDefaults(defaults);
// replace all colors with GColors
for (ColorValue colorValue : javaDefaults.getColors()) {
String id = colorValue.getId();
defaults.put(id, themeManager.getGColorUiResource(id));
}
// put fonts back into defaults in case they have been changed by the current theme
for (FontValue fontValue : javaDefaults.getFonts()) {
String id = fontValue.getId();
Font font = themeManager.getFont(id);
defaults.put(id, new FontUIResource(font));
}
// put icons back into defaults in case they have been changed by the current theme
for (IconValue iconValue : javaDefaults.getIcons()) {
String id = iconValue.getId();
// because some icons are weird, put raw icons into defaults, only use GIcons for
// setting Icons explicitly on components
Icon icon = themeManager.getIcon(id);
defaults.put(id, icon);
}
defaults.put("Label.textForeground", themeManager.getGColorUiResource("Label.foreground"));
themeManager.refreshGThemeValues();
return defaults;
}
private void installCustomPainters(UIDefaults defaults) {
defaults.put("Tree:TreeCell[Enabled+Selected].backgroundPainter",
new SelectedTreePainter());
defaults.put("Tree:TreeCell[Focused+Selected].backgroundPainter",
new SelectedTreePainter());
}
protected GThemeValueMap extractJavaDefaults(UIDefaults defaults) {
GThemeValueMap javaDefaults = new GThemeValueMap();
List<String> colorIds =
LookAndFeelManager.getLookAndFeelIdsForType(defaults, Color.class);
for (String id : colorIds) {
Color color = defaults.getColor(id);
ColorValue value = new ColorValue(id, color);
javaDefaults.addColor(value);
}
List<String> fontIds =
LookAndFeelManager.getLookAndFeelIdsForType(defaults, Font.class);
for (String id : fontIds) {
Font font = defaults.getFont(id);
FontValue value = new FontValue(id, LookAndFeelManager.fromUiResource(font));
javaDefaults.addFont(value);
}
List<String> iconIds =
LookAndFeelManager.getLookAndFeelIdsForType(defaults, Icon.class);
for (String id : iconIds) {
Icon icon = defaults.getIcon(id);
javaDefaults.addIcon(new IconValue(id, icon));
}
// need to set javaDefalts now to trigger building currentValues so the when
// we create GColors below, they can be resolved.
themeManager.setJavaDefaults(javaDefaults);
return javaDefaults;
}
}
@@ -15,6 +15,8 @@
*/
package generic.theme.laf;
import javax.swing.UIDefaults;
import generic.theme.ApplicationThemeManager;
import generic.theme.LafType;
@@ -26,4 +28,9 @@ public class GtkLookAndFeelManager extends LookAndFeelManager {
public GtkLookAndFeelManager(ApplicationThemeManager themeManager) {
super(LafType.GTK, themeManager);
}
@Override
protected UiDefaultsMapper getUiDefaultsMapper(UIDefaults defaults) {
return new GtkUiDefaultsMapper(defaults);
}
}
@@ -0,0 +1,41 @@
/* ###
* 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 static generic.theme.SystemThemeIds.*;
import javax.swing.UIDefaults;
public class GtkUiDefaultsMapper extends UiDefaultsMapper {
protected GtkUiDefaultsMapper(UIDefaults defaults) {
super(defaults);
}
@Override
protected void registerIgnoredLafIds() {
super.registerIgnoredLafIds();
ignoredLafIds.add("textInactiveText");
}
@Override
protected void assignColorMatchersToComponentIds() {
super.assignColorMatchersToComponentIds();
assignSystemColorFromLafId(FG_VIEW_ID, "windowText");
assignSystemColorFromLafId(FG_DISABLED_ID, "Label.disabledForeground");
}
}
@@ -36,32 +36,14 @@ import ghidra.util.SystemUtilities;
*/
public abstract class LookAndFeelManager {
/**
* These are color ids (see {@link GColor} used to represent general concepts that
* application developers can use to get the color for that concept as defined by
* a specific {@link LookAndFeel}. This class will define some standard default
* mappings in the constructor, but it is expected that each specific LookAndFeelManager
* will override these mappings with values appropriate for that LookAndFeel.
*/
protected static final String SYSTEM_APP_BACKGROUND_COLOR_ID = "system.color.bg.application";
protected static final String SYSTEM_WIDGET_BACKGROUND_COLOR_ID = "system.color.bg.widget";
protected static final String SYSTEM_TOOLTIP_BACKGROUND_COLOR_ID = "system.color.bg.tooltip";
protected static final String SYSTEM_BORDER_COLOR_ID = "system.color.border";
private LafType laf;
private Map<String, ComponentFontRegistry> fontRegistryMap = new HashMap<>();
protected GThemeValueMap systemToLafMap = new GThemeValueMap();
protected ApplicationThemeManager themeManager;
protected Map<String, String> normalizedIdToLafIdMap;
protected LookAndFeelManager(LafType laf, ApplicationThemeManager themeManager) {
this.laf = laf;
this.themeManager = themeManager;
// establish system color to LookAndFeel colors
systemToLafMap.addColor(new ColorValue(SYSTEM_APP_BACKGROUND_COLOR_ID, "control"));
systemToLafMap.addColor(new ColorValue(SYSTEM_WIDGET_BACKGROUND_COLOR_ID, "control"));
systemToLafMap.addColor(new ColorValue(SYSTEM_TOOLTIP_BACKGROUND_COLOR_ID, "control"));
systemToLafMap.addColor(new ColorValue(SYSTEM_BORDER_COLOR_ID, "controlShadow"));
}
/**
@@ -85,10 +67,8 @@ public abstract class LookAndFeelManager {
public void installLookAndFeel() throws ClassNotFoundException, InstantiationException,
IllegalAccessException, UnsupportedLookAndFeelException {
cleanUiDefaults();
themeManager.setSystemDefaults(systemToLafMap);
doInstallLookAndFeel();
installJavaDefaults();
processJavaDefaults();
fixupLookAndFeelIssues();
installGlobalProperties();
installCustomLookAndFeelActions();
@@ -119,10 +99,14 @@ public abstract class LookAndFeelManager {
UIDefaults defaults = UIManager.getDefaults();
for (FontValue fontValue : fonts) {
String id = fontValue.getId();
String lafId = normalizedIdToLafIdMap.get(id);
if (lafId == null) {
continue;
}
Font correctFont = Gui.getFont(id);
Font storedFont = defaults.getFont(id);
if (correctFont != null && !correctFont.equals(storedFont)) {
defaults.put(id, correctFont);
defaults.put(lafId, toUiResource(correctFont));
}
}
}
@@ -132,10 +116,11 @@ public abstract class LookAndFeelManager {
UIDefaults defaults = UIManager.getDefaults();
for (IconValue iconValue : icons) {
String id = iconValue.getId();
String lafId = normalizedIdToLafIdMap.get(id);
Icon correctIcon = Gui.getIcon(id);
Icon storedIcon = defaults.getIcon(id);
if (correctIcon != null && !correctIcon.equals(storedIcon)) {
defaults.put(id, correctIcon);
defaults.put(lafId, correctIcon);
}
}
}
@@ -154,14 +139,16 @@ public abstract class LookAndFeelManager {
* @param newIcon the new icon to use for the given set of icon ids
*/
public void iconsChanged(Set<String> changedIconIds, Icon newIcon) {
UIDefaults defaults = UIManager.getDefaults();
if (!(newIcon instanceof UIResource)) {
newIcon = new IconUIResource(newIcon);
}
for (String changedIconId : changedIconIds) {
String lafIconId = normalizedIdToLafIdMap.get(changedIconId);
defaults.put(lafIconId, newIcon);
}
if (!changedIconIds.isEmpty()) {
UIDefaults defaults = UIManager.getDefaults();
for (String javaIconId : changedIconIds) {
defaults.put(javaIconId, newIcon);
}
updateComponentUis();
}
themeManager.refreshGThemeValues();
@@ -173,16 +160,22 @@ public abstract class LookAndFeelManager {
* @param changedJavaFontIds the set of Java Font ids that are affected by this change
*/
public void fontsChanged(Set<String> changedJavaFontIds) {
if (!changedJavaFontIds.isEmpty()) {
UIDefaults defaults = UIManager.getDefaults();
for (String javaFontId : changedJavaFontIds) {
// even though all these derive from the new font, they might be different
// because of FontModifiers.
Font font = Gui.getFont(javaFontId);
defaults.put(javaFontId, new FontUIResource(font));
UIDefaults defaults = UIManager.getDefaults();
for (String changedFontId : changedJavaFontIds) {
// even though all these derive from the new font, they might be different
// because of FontModifiers.
Font font = Gui.getFont(changedFontId);
String lafFontId = normalizedIdToLafIdMap.get(changedFontId);
if (lafFontId != null) {
// lafFontId is null for group ids
defaults.put(lafFontId, new FontUIResource(font));
}
}
if (!changedJavaFontIds.isEmpty()) {
updateComponentUis();
}
updateAllRegisteredComponentFonts();
repaintAll();
}
@@ -212,26 +205,9 @@ public abstract class LookAndFeelManager {
register.addComponent(component);
}
/**
* Returns a color that is not a {@link UIResource}.
* @param color the color to return an non UIResource color for
* @return a color that is not a {@link UIResource}.
*/
public static Color fromUiResource(Color color) {
if (color.getClass() == Color.class) {
return color;
}
return new Color(color.getRGB(), true);
}
/**
* Returns a font that is not a {@link UIResource}.
* @param font the font to return an non UIResource font for
* @return a font that is not a {@link UIResource}.
*/
public static Font fromUiResource(Font font) {
if (font instanceof UIResource) {
return new FontNonUiResource(font);
private Font toUiResource(Font font) {
if (!(font instanceof UIResource)) {
return new FontUIResource(font);
}
return font;
}
@@ -261,80 +237,21 @@ public abstract class LookAndFeelManager {
}
/**
* Extracts java default colors, fonts, and icons and stores them in {@link Gui}.
* Extracts java default colors, fonts, and icons and stores them in the
* {@link ThemeManager} and updates the {@link UIDefaults} by installing GColors for all
* color values and installing any overridden fonts or icons.
*/
private void installJavaDefaults() {
GThemeValueMap javaDefaults = extractJavaDefaults();
ThemeGrouper grouper = getThemeGrouper();
grouper.group(javaDefaults);
protected void processJavaDefaults() {
UIDefaults defaults = UIManager.getDefaults();
UiDefaultsMapper uiDefaultsMapper = getUiDefaultsMapper(defaults);
GThemeValueMap javaDefaults = uiDefaultsMapper.getJavaDefaults();
themeManager.setJavaDefaults(javaDefaults);
installPropertiesBackIntoUiDefaults(javaDefaults);
uiDefaultsMapper.installValuesIntoUIDefaults(themeManager.getApplicationOverrides());
normalizedIdToLafIdMap = uiDefaultsMapper.getNormalizedIdToLafIdMap();
}
protected ThemeGrouper getThemeGrouper() {
return new ThemeGrouper();
}
protected void installPropertiesBackIntoUiDefaults(GThemeValueMap javaDefaults) {
UIDefaults defaults = UIManager.getDefaults();
GTheme theme = themeManager.getActiveTheme();
// we replace java default colors with GColor equivalents so that we
// can change colors without having to reinstall ui on each component
// This trick only works for colors. Fonts and icons don't universally
// allow being wrapped like colors do.
for (ColorValue colorValue : javaDefaults.getColors()) {
String id = colorValue.getId();
defaults.put(id, themeManager.getGColorUiResource(id));
}
// put fonts back into defaults in case they have been changed by the current theme
for (FontValue fontValue : javaDefaults.getFonts()) {
String id = fontValue.getId();
FontValue themeValue = theme.getFont(id);
if (themeValue != null) {
Font font = Gui.getFont(id);
defaults.put(id, new FontUIResource(font));
}
}
// put icons back into defaults in case they have been changed by the current theme
for (IconValue iconValue : javaDefaults.getIcons()) {
String id = iconValue.getId();
IconValue themeValue = theme.getIcon(id);
if (themeValue != null) {
// because some icons are weird, put raw icons into defaults, only use GIcons for
// setting Icons explicitly on components
Icon icon = Gui.getIcon(id);
defaults.put(id, icon);
}
}
}
protected GThemeValueMap extractJavaDefaults() {
UIDefaults defaults = UIManager.getDefaults();
GThemeValueMap values = new GThemeValueMap();
// for now, just doing color properties.
List<String> ids = getLookAndFeelIdsForType(defaults, Color.class);
for (String id : ids) {
// convert UIResource color to regular colors so if used, they don't get wiped
// out when we update the UIs
values.addColor(new ColorValue(id, fromUiResource(UIManager.getColor(id))));
}
ids = getLookAndFeelIdsForType(defaults, Font.class);
for (String id : ids) {
// convert UIResource fonts to regular fonts so if used, they don't get wiped
// out when we update UIs
values.addFont(new FontValue(id, fromUiResource(UIManager.getFont(id))));
}
ids = getLookAndFeelIdsForType(defaults, Icon.class);
for (String id : ids) {
Icon icon = UIManager.getIcon(id);
values.addIcon(new IconValue(id, icon));
}
return values;
}
protected abstract UiDefaultsMapper getUiDefaultsMapper(UIDefaults defaults);
protected String findLookAndFeelClassName(String lookAndFeelName) {
LookAndFeelInfo[] installedLookAndFeels = UIManager.getInstalledLookAndFeels();
@@ -463,26 +380,6 @@ public abstract class LookAndFeelManager {
installPopupMenuSettingsOverride();
}
private void cleanUiDefaults() {
GThemeValueMap javaDefaults = themeManager.getJavaDefaults();
if (javaDefaults == null) {
return;
}
UIDefaults defaults = UIManager.getDefaults();
for (ColorValue colorValue : javaDefaults.getColors()) {
String id = colorValue.getId();
defaults.put(id, null);
}
for (FontValue fontValue : javaDefaults.getFonts()) {
String id = fontValue.getId();
defaults.put(id, null);
}
for (IconValue iconValue : javaDefaults.getIcons()) {
String id = iconValue.getId();
defaults.put(id, null);
}
}
/**
* Searches the given UIDefaults for ids whose value matches the given class
* @param defaults the UIDefaults to search
@@ -15,6 +15,8 @@
*/
package generic.theme.laf;
import javax.swing.UIDefaults;
import generic.theme.ApplicationThemeManager;
import generic.theme.LafType;
@@ -25,7 +27,7 @@ public class MacLookAndFeelManager extends LookAndFeelManager {
}
@Override
protected ThemeGrouper getThemeGrouper() {
return new MacThemeGrouper();
protected UiDefaultsMapper getUiDefaultsMapper(UIDefaults defaults) {
return new MacUiDefaultsMapper(defaults);
}
}
@@ -1,38 +0,0 @@
/* ###
* 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 generic.theme.GThemeValueMap;
/**
* Adds specialized groupings unique to the Mac LookAndFeel
*/
public class MacThemeGrouper extends ThemeGrouper {
@Override
public void group(GThemeValueMap values) {
// @formatter:off
defineCustomColorGroup("color.mac.disabled.fg", "Menu.disabledForeground", values);
defineCustomColorGroup("color.mac.button.select", "Button.select", values);
defineCustomColorGroup("color.mac.menu.select", "Menu.selectionBackground",values);
defineCustomColorGroup("color.mac.seletion.inactive.bg", "List.selectionInactiveBackground",values);//d4d4d4
defineCustomFontGroup("font.mac.small.font", "IconButton.font", values);
// @formatter:on
super.group(values);
}
}
@@ -0,0 +1,25 @@
/* ###
* 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 javax.swing.UIDefaults;
public class MacUiDefaultsMapper extends UiDefaultsMapper {
protected MacUiDefaultsMapper(UIDefaults defaults) {
super(defaults);
}
}
@@ -15,6 +15,8 @@
*/
package generic.theme.laf;
import javax.swing.UIDefaults;
import generic.theme.ApplicationThemeManager;
import generic.theme.LafType;
@@ -23,4 +25,9 @@ public class MetalLookAndFeelManager extends LookAndFeelManager {
public MetalLookAndFeelManager(ApplicationThemeManager themeManager) {
super(LafType.METAL, themeManager);
}
@Override
protected UiDefaultsMapper getUiDefaultsMapper(UIDefaults defaults) {
return new MetalUiDefaultsMapper(defaults);
}
}
@@ -0,0 +1,41 @@
/* ###
* 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 static generic.theme.SystemThemeIds.*;
import javax.swing.UIDefaults;
public class MetalUiDefaultsMapper extends UiDefaultsMapper {
protected MetalUiDefaultsMapper(UIDefaults defaults) {
super(defaults);
}
@Override
protected void registerIgnoredLafIds() {
super.registerIgnoredLafIds();
ignoredLafIds.add("textInactiveText");
}
@Override
protected void assignSystemColorValues() {
super.assignSystemColorValues();
assignSystemColorFromLafId(FG_DISABLED_ID, "Label.disabledForeground");
assignSystemColorFromLafId(FG_VIEW_ID, "windowText");
}
}
@@ -15,7 +15,10 @@
*/
package generic.theme.laf;
import generic.theme.*;
import javax.swing.UIDefaults;
import generic.theme.ApplicationThemeManager;
import generic.theme.LafType;
/**
* Motif {@link LookAndFeelManager}. Specialized so that it can return the Motif installer
@@ -24,11 +27,11 @@ public class MotifLookAndFeelManager extends LookAndFeelManager {
public MotifLookAndFeelManager(ApplicationThemeManager themeManager) {
super(LafType.MOTIF, themeManager);
// establish system color to LookAndFeel colors
systemToLafMap.addColor(new ColorValue(SYSTEM_APP_BACKGROUND_COLOR_ID, "control"));
systemToLafMap.addColor(new ColorValue(SYSTEM_WIDGET_BACKGROUND_COLOR_ID, "window"));
systemToLafMap.addColor(new ColorValue(SYSTEM_TOOLTIP_BACKGROUND_COLOR_ID, "info"));
systemToLafMap.addColor(new ColorValue(SYSTEM_BORDER_COLOR_ID, "activeCaptionBorder"));
}
@Override
protected UiDefaultsMapper getUiDefaultsMapper(UIDefaults defaults) {
return new MotifUiDefaultsMapper(defaults);
}
@Override
@@ -46,10 +49,4 @@ public class MotifLookAndFeelManager extends LookAndFeelManager {
setKeyBinding("PASTE", "ctrl V", UIPrefixValues);
setKeyBinding("CUT", "ctrl X", UIPrefixValues);
}
@Override
protected ThemeGrouper getThemeGrouper() {
return new MotifThemeGrouper();
}
}
@@ -15,21 +15,18 @@
*/
package generic.theme.laf;
import generic.theme.GThemeValueMap;
import javax.swing.UIDefaults;
/**
* Adds specialized groupings unique to the Motif LookAndFeel
*/
public class MotifThemeGrouper extends ThemeGrouper {
public MotifThemeGrouper() {
public class MotifUiDefaultsMapper extends UiDefaultsMapper {
protected MotifUiDefaultsMapper(UIDefaults defaults) {
super(defaults);
}
@Override
public void group(GThemeValueMap values) {
defineCustomFontGroup("font.monospaced", "Spinner.font", values);
super.group(values);
protected void registerIgnoredLafIds() {
super.registerIgnoredLafIds();
ignoredLafIds.add("controlLightShadow");
}
}
@@ -32,9 +32,6 @@ public class NimbusLookAndFeelManager extends LookAndFeelManager {
public NimbusLookAndFeelManager(ApplicationThemeManager themeManager) {
super(LafType.NIMBUS, themeManager);
// establish system color specific to Nimbus
systemToLafMap.addColor(new ColorValue(SYSTEM_BORDER_COLOR_ID, "nimbusBorder"));
}
@Override
@@ -63,11 +60,30 @@ public class NimbusLookAndFeelManager extends LookAndFeelManager {
private void reinstallNimubus() {
try {
UIManager.setLookAndFeel(new GNimbusLookAndFeel(themeManager) {
/**
* In order to get Nimbus to honor changes to fonts and icons in the UiDefaults,
* we have to reinstall nimbus. Reinstalling nimbus is a bit different that the first
* install. First, we don't want to re-install the java defaults, the current ones are
* fine and we don't want loose any current theme values changes. Second, when we
* get font and theme value overrides, we want to use all the current values as they
* may include additional overrides than just the original values from theme.property
* files.
*/
UIManager.setLookAndFeel(new CustomNimbusLookAndFeel(themeManager) {
@Override
protected GThemeValueMap extractJavaDefaults(UIDefaults defaults) {
return themeManager.getJavaDefaults();
protected void installJavaDefaultsIntoThemeManager(
UiDefaultsMapper uiDefaultsMapper) {
// as explained above, don't change the java defaults in the theme manager
// on a reinstall
}
@Override
protected GThemeValueMap getApplicationOverrides() {
// on a reinstall, we may also have overrides in the current values and not
// just the theme.property files
return themeManager.getCurrentValues();
}
});
}
catch (UnsupportedLookAndFeelException e) {
@@ -78,18 +94,15 @@ public class NimbusLookAndFeelManager extends LookAndFeelManager {
@Override
protected void doInstallLookAndFeel() throws UnsupportedLookAndFeelException {
UIManager.setLookAndFeel(new GNimbusLookAndFeel(themeManager));
CustomNimbusLookAndFeel nimbusLookAndFeel = new CustomNimbusLookAndFeel(themeManager);
UIManager.setLookAndFeel(nimbusLookAndFeel);
normalizedIdToLafIdMap = nimbusLookAndFeel.getNormalizedIdToLafIdMap();
}
@Override
protected GThemeValueMap extractJavaDefaults() {
protected void processJavaDefaults() {
// The GNimbusLookAndFeel already extracted the java defaults and installed them in the Gui
return themeManager.getJavaDefaults();
}
@Override
protected ThemeGrouper getThemeGrouper() {
return new NimbusThemeGrouper();
}
@Override
@@ -105,8 +118,7 @@ public class NimbusLookAndFeelManager extends LookAndFeelManager {
}
@Override
protected void installPropertiesBackIntoUiDefaults(GThemeValueMap javaDefaults) {
// do nothing, this was handled when we overrode the getDefaults() method in the
// GNimubusLookAndFeel
protected UiDefaultsMapper getUiDefaultsMapper(UIDefaults defaults) {
return new NimbusUiDefaultsMapper(defaults);
}
}
@@ -1,43 +0,0 @@
/* ###
* 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 generic.theme.GThemeValueMap;
/**
* Adds specialized groupings unique to the Nimbus LookAndFeel
*/
public class NimbusThemeGrouper extends ThemeGrouper {
public NimbusThemeGrouper() {
// Nimbus defines a new type of button
buttonGroup.addComponents("ArrowButton");
// Nimbus defines some other color sources
colorSourceProperties.add("nimbusFocus");
colorSourceProperties.add("nimbusOrange");
colorSourceProperties.add("nimbusBorder");
}
@Override
public void group(GThemeValueMap values) {
defineCustomColorGroup("color.nimbus.text.alt", "Menu.foreground", values);
defineCustomFontGroup("font.titledborder", "TitledBorder.font", values);
super.group(values);
}
}

Some files were not shown because too many files have changed in this diff Show More