mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
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:
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
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
/* ###
|
||||
* 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;
|
||||
|
||||
import generic.theme.*;
|
||||
|
||||
public class NimbusUiDefaultsMapper extends UiDefaultsMapper {
|
||||
|
||||
protected NimbusUiDefaultsMapper(UIDefaults defaults) {
|
||||
super(defaults);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerIgnoredLafIds() {
|
||||
super.registerIgnoredLafIds();
|
||||
ignoredLafIds.add("background");
|
||||
|
||||
ignoredLafIds.add("controlLHighlight");
|
||||
|
||||
ignoredLafIds.add("nimbusAlertYellow");
|
||||
ignoredLafIds.add("nimbusBase");
|
||||
ignoredLafIds.add("nimbusBlueGrey");
|
||||
ignoredLafIds.add("nimbusDisabledText");
|
||||
ignoredLafIds.add("nimbusFocus");
|
||||
ignoredLafIds.add("nimbusGreen");
|
||||
ignoredLafIds.add("nimbusInfoBlue");
|
||||
ignoredLafIds.add("nimbusOrange");
|
||||
ignoredLafIds.add("nimbusRed");
|
||||
ignoredLafIds.add("nimbusSelectedText");
|
||||
ignoredLafIds.add("nimbusSelection");
|
||||
ignoredLafIds.add("nimbusSelectionBackground");
|
||||
|
||||
ignoredLafIds.add("defaultFont");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assignSystemColorValues() {
|
||||
|
||||
// different from base class
|
||||
assignSystemColorFromLafId(BG_CONTROL_ID, "Button.background");
|
||||
assignSystemColorFromLafId(FG_CONTROL_ID, "Button.foreground");
|
||||
assignSystemColorFromLafId(BG_BORDER_ID, "nimbusBorder");
|
||||
assignSystemColorFromLafId(BG_VIEW_ID, "nimbusLightBackground");
|
||||
assignSystemColorFromLafId(FG_VIEW_ID, "controlText");
|
||||
|
||||
// the following are the same as the base class (we can't just call super because
|
||||
// it will report errors for missing lafIds such as "window"
|
||||
|
||||
assignSystemColorFromLafId(BG_VIEW_SELECTED_ID, "textHighlight");
|
||||
assignSystemColorFromLafId(FG_VIEW_SELECTED_ID, "textHighlightText");
|
||||
assignSystemColorFromLafId(FG_DISABLED_ID, "textInactiveText");
|
||||
assignSystemColorFromLafId(BG_TOOLTIP_ID, "info");
|
||||
assignSystemColorFromLafId(FG_TOOLTIP_ID, "infoText");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected GThemeValueMap extractColorFontAndIconValuesFromDefaults() {
|
||||
// Nimbus always uses "info" to paint its tooltip and it appears they forgot to update
|
||||
// that value to the value they assigned to the "ToolTip.background. So we fix it here
|
||||
// before extracting the values from the UIDefaults
|
||||
defaults.put("info", defaults.getColor("ToolTip.background"));
|
||||
return super.extractColorFontAndIconValuesFromDefaults();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installGColorsIntoUIDefaults() {
|
||||
super.installGColorsIntoUIDefaults();
|
||||
|
||||
// The Nimbus selected text field color is not honored if the value is a ColorUIResource.
|
||||
// We install GColorUIResources by default. Thus, our setting for this particular
|
||||
// attribute was being ignored. We set it here to be a GColor, which causes Nimbus
|
||||
// to honor the value. We may need to add more entries here as they are discovered.
|
||||
|
||||
defaults.put("TextField.selectionForeground",
|
||||
new GColor(SystemThemeIds.FG_VIEW_SELECTED_ID));
|
||||
}
|
||||
|
||||
}
|
|
@ -1,452 +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.*;
|
||||
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.plaf.basic.BasicLookAndFeel;
|
||||
|
||||
import generic.theme.*;
|
||||
|
||||
/**
|
||||
* Organizes UIDefaults color and font properties into groups so that every property doesn't
|
||||
* have its own direct value. The idea is that users can affect many properties that have the
|
||||
* same value by just changing the value for the group. For colors, the {@link LookAndFeel}s
|
||||
* organize the properties internally and this class attempts to restore that organization
|
||||
* as much as possible by using the values defined in the {@link BasicLookAndFeel} such as
|
||||
* "control", "window", "controlShadlow", etc. The fonts don't appear to have any such internal
|
||||
* organization, so we created our own groups and used a lookAndFeel property to initialize each
|
||||
* group source value. Then whenever the font matched a group source value, the font is replace
|
||||
* with an indirect reference to the group source font value.
|
||||
* <p>
|
||||
* This class is sometimes sub-classed for a particular {@link LookAndFeel}. The subclass can
|
||||
* create new groups and mappings that are unique to that LookAndFeel.
|
||||
*
|
||||
* Often, many of the various group source ids have the same color value. To try to group
|
||||
* properties as defined in BasicLookAndFeel, the preferred source ids are
|
||||
* defined for each group. These will be tried first, but if a match isn't found among the
|
||||
* preferred sources, then all the sources will be searched for a match
|
||||
*/
|
||||
public class ThemeGrouper {
|
||||
private static String DEFAULT_FONT_GROUP_ID = "font.default";
|
||||
private static String BUTTON_FONT_GROUP_ID = "font.button";
|
||||
private static String TEXT_FONT_GROUP_ID = "font.text";
|
||||
private static String WIDGET_FONT_GROUP_ID = "font.widget";
|
||||
private static String COMPONENT_FONT_GROUP_ID = "font.component";
|
||||
private static String MENU_FONT_GROUP_ID = "font.menu";
|
||||
private static String MENU_ACCELERATOR_FONT_GROUP_ID = "font.menu.accelerator";
|
||||
|
||||
static List<String> DEFAULT_FONT_SOURCE_PROPERTIES = List.of(
|
||||
DEFAULT_FONT_GROUP_ID,
|
||||
COMPONENT_FONT_GROUP_ID,
|
||||
WIDGET_FONT_GROUP_ID,
|
||||
TEXT_FONT_GROUP_ID,
|
||||
BUTTON_FONT_GROUP_ID,
|
||||
MENU_FONT_GROUP_ID,
|
||||
MENU_ACCELERATOR_FONT_GROUP_ID);
|
||||
|
||||
// The list of color properties (defined in BasicLookAndFeel) that are used to populate
|
||||
// other component specific colors.
|
||||
// The order is important. If any have the same color value, the one higher in the list is used.
|
||||
// Individual groups (buttons, menus, etc.) may define a different order that is more specific
|
||||
// to that group
|
||||
public static List<String> DEFAULT_COLOR_SOURCE_PROPERTIES = List.of(
|
||||
"control",
|
||||
"window",
|
||||
"activeCaption",
|
||||
"activeCaptionBorder",
|
||||
"activeCaptionText",
|
||||
"controlDkShadow",
|
||||
"controlHighlight",
|
||||
"controlLtHighlight",
|
||||
"controlShadow",
|
||||
"controlText",
|
||||
"desktp",
|
||||
"inactiveCaption",
|
||||
"inactiveCaptionBorder",
|
||||
"inactiveCaptionText",
|
||||
"info",
|
||||
"infoText",
|
||||
"menu",
|
||||
"menuText",
|
||||
"scrollbar",
|
||||
"scrollBarTrack",
|
||||
"text",
|
||||
"textHighlight",
|
||||
"textHighlightText",
|
||||
"textInactiveText",
|
||||
"textText",
|
||||
"windowBorder",
|
||||
"windowText");
|
||||
|
||||
private static final String[] BUTTON_GROUP = {
|
||||
"Button",
|
||||
"ToggleButton",
|
||||
"RadioButton",
|
||||
"CheckBox"
|
||||
};
|
||||
private static final String[] MENU_GROUP = {
|
||||
"Menu",
|
||||
"MenuBar",
|
||||
"MenuItem",
|
||||
"PopupMenu",
|
||||
"RadioButtonMenuItem",
|
||||
"CheckBoxMenuItem"
|
||||
};
|
||||
private static final String[] TEXT_GROUP = {
|
||||
"TextField",
|
||||
"FormattedTextField",
|
||||
"PasswordField",
|
||||
"TextArea",
|
||||
"TextPane",
|
||||
"EditorPane"
|
||||
};
|
||||
private static final String[] WIDGET_GROUP = {
|
||||
"FileChooser",
|
||||
"ColorChooser",
|
||||
"ComboBox",
|
||||
"List",
|
||||
"Table",
|
||||
"Tree"
|
||||
};
|
||||
private static final String[] COMPONENT_GROUP = {
|
||||
"Desktop",
|
||||
"Panel",
|
||||
"InternalFrame",
|
||||
"Label",
|
||||
"OptionPane",
|
||||
"ProgressBar",
|
||||
"Separator",
|
||||
"ScrollBar",
|
||||
"ScrollPane",
|
||||
"Viewport",
|
||||
"Slider",
|
||||
"Spinner",
|
||||
"SplitPane",
|
||||
"TabbedPane",
|
||||
"TableHeader",
|
||||
"TitledBorder",
|
||||
"ToolBar",
|
||||
"ToolTip"
|
||||
};
|
||||
|
||||
private static final String[] BUTTON_PREFERRED_SOURCES = {
|
||||
"control",
|
||||
"controlText",
|
||||
"controlShadow",
|
||||
"controlDkShadow",
|
||||
"controlHighlight",
|
||||
"controlLtHighlight"
|
||||
};
|
||||
private static final String[] MENU_PREFERRED_SOURCES = {
|
||||
"menu",
|
||||
"menuText",
|
||||
"textHighlightText",
|
||||
"textHighlight",
|
||||
"controlShadow",
|
||||
"controlDkShadow",
|
||||
"controlHighlight",
|
||||
"controlLtHighlight"
|
||||
};
|
||||
private static final String[] TEXT_PREFERRED_SOURCES = {
|
||||
"window",
|
||||
"text",
|
||||
"textText",
|
||||
"textInactiveText",
|
||||
"textHighlight",
|
||||
"textHighlightText",
|
||||
"controlShadow",
|
||||
"controlDkShadow",
|
||||
"controlHighlight",
|
||||
"controlLtHighlight"
|
||||
};
|
||||
private static final String[] WIDGET_PREFERRED_SOURCES = {
|
||||
"window",
|
||||
"textText",
|
||||
"textHighlight",
|
||||
"textHighlightText",
|
||||
"control",
|
||||
"controlShadow",
|
||||
"controlDkShadow",
|
||||
"controlHighlight",
|
||||
"controlLtHighlight"
|
||||
};
|
||||
private static final String[] COMPONENT_PREFERRED_SOURCES = {
|
||||
"control",
|
||||
"controlText",
|
||||
"controlShadow",
|
||||
"controlDkShadow",
|
||||
"controlHighlight",
|
||||
"controlLtHighlight",
|
||||
"textText",
|
||||
"textHighlight"
|
||||
};
|
||||
|
||||
protected List<String> colorSourceProperties;
|
||||
protected List<String> fontSourceProperties;
|
||||
protected Set<PropertyGroup> groups;
|
||||
protected PropertyGroup buttonGroup = new PropertyGroup(BUTTON_GROUP, BUTTON_PREFERRED_SOURCES);
|
||||
protected PropertyGroup menuGroup = new PropertyGroup(MENU_GROUP, MENU_PREFERRED_SOURCES);
|
||||
protected PropertyGroup widgetGroup = new PropertyGroup(WIDGET_GROUP, WIDGET_PREFERRED_SOURCES);
|
||||
protected PropertyGroup textGroup = new PropertyGroup(TEXT_GROUP, TEXT_PREFERRED_SOURCES);
|
||||
protected PropertyGroup componentGroup =
|
||||
new PropertyGroup(COMPONENT_GROUP, COMPONENT_PREFERRED_SOURCES);
|
||||
|
||||
public ThemeGrouper() {
|
||||
colorSourceProperties = new ArrayList<>(DEFAULT_COLOR_SOURCE_PROPERTIES);
|
||||
fontSourceProperties = new ArrayList<>(DEFAULT_FONT_SOURCE_PROPERTIES);
|
||||
groups = getPropertyGroups();
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces direct property values in the given GThemeValueMap with indirect references
|
||||
* using the values from match source ids.
|
||||
* @param values the values to search and replace source matches
|
||||
*/
|
||||
public void group(GThemeValueMap values) {
|
||||
initialize(values);
|
||||
Map<String, PropertyGroup> groupMap = buildGroupMap(values);
|
||||
groupColors(values, groupMap);
|
||||
groupFonts(values, groupMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a new color id that will be used as the reference value for any specific color ids that
|
||||
* have the same color value. This will allow all those specific colors to be changed at once.
|
||||
* @param customGroupColorName name of a higher level group color id that will be used as the
|
||||
* value for more specific color ids defined by the lookAndFeel.
|
||||
* @param lookAndFeelSourceId the lookAndFeel color id whose value will be used as the value
|
||||
* for the new custom group color id
|
||||
* @param values the map where we store the default theme value mappings
|
||||
*/
|
||||
protected void defineCustomColorGroup(String customGroupColorName, String lookAndFeelSourceId,
|
||||
GThemeValueMap values) {
|
||||
|
||||
colorSourceProperties.add(customGroupColorName);
|
||||
ColorValue colorValue = values.getColor(lookAndFeelSourceId);
|
||||
if (colorValue != null) {
|
||||
Color color = colorValue.get(values);
|
||||
values.addColor(new ColorValue(customGroupColorName, color));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a new font id that will be used as the reference value for any specific font ids that
|
||||
* have the same font value. This will allow all those specific fonts to be changed at once.
|
||||
* @param customGroupFontName name of a higher level group font id that will be used as the
|
||||
* value of more specific font ids defined by the lookAndFeel.
|
||||
* @param lookAndFeelSourceId the lookAndFeel font id whose value will be used as the value
|
||||
* for the new custom group font id
|
||||
* @param values the map where we store the default theme value mappings
|
||||
*/
|
||||
protected void defineCustomFontGroup(String customGroupFontName, String lookAndFeelSourceId,
|
||||
GThemeValueMap values) {
|
||||
fontSourceProperties.add(customGroupFontName);
|
||||
FontValue fontValue = values.getFont(lookAndFeelSourceId);
|
||||
if (fontValue != null) {
|
||||
Font font = fontValue.get(values);
|
||||
values.addFont(new FontValue(customGroupFontName, font));
|
||||
}
|
||||
}
|
||||
|
||||
private void groupColors(GThemeValueMap values, Map<String, PropertyGroup> groupMap) {
|
||||
Set<String> skip = new HashSet<>(colorSourceProperties); // we don't want to map sources
|
||||
Map<Integer, String> defaultColorMapping = buildColorToSourceMap(values);
|
||||
// try to map each color property to a source property (e.g., Button.background -> control)
|
||||
for (ColorValue colorValue : values.getColors()) {
|
||||
String id = colorValue.getId();
|
||||
if (colorValue.isIndirect() || skip.contains(id)) {
|
||||
continue;
|
||||
}
|
||||
PropertyGroup group = groupMap.get(getComponentName(id));
|
||||
int rgb = colorValue.getRawValue().getRGB();
|
||||
String sourceProperty = group == null ? null : group.getSourceProperty(rgb);
|
||||
if (sourceProperty == null) {
|
||||
sourceProperty = defaultColorMapping.get(rgb);
|
||||
}
|
||||
|
||||
if (sourceProperty != null) {
|
||||
values.addColor(new ColorValue(id, sourceProperty));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void groupFonts(GThemeValueMap values, Map<String, PropertyGroup> groupMap) {
|
||||
Set<String> skip = new HashSet<>(fontSourceProperties); // we don't want to map sources
|
||||
Map<Font, String> defaultFontMapping = buildFontToSourceMap(values);
|
||||
|
||||
// try to map each color property to a source property (e.g., Button.background -> control)
|
||||
for (FontValue fontValue : values.getFonts()) {
|
||||
String id = fontValue.getId();
|
||||
if (fontValue.isIndirect() || skip.contains(id)) {
|
||||
continue;
|
||||
}
|
||||
Font font = fontValue.getRawValue();
|
||||
PropertyGroup group = groupMap.get(getComponentName(id));
|
||||
String sourceProperty = group == null ? null : group.getSourceProperty(font);
|
||||
if (sourceProperty == null) {
|
||||
sourceProperty = defaultFontMapping.get(font);
|
||||
}
|
||||
if (sourceProperty != null) {
|
||||
values.addFont(new FontValue(id, sourceProperty));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initialize(GThemeValueMap values) {
|
||||
// initialized default font to the Panel's font
|
||||
FontValue defaultFontValue = values.getFont("Panel.font");
|
||||
if (defaultFontValue != null) {
|
||||
values.addFont(new FontValue(DEFAULT_FONT_GROUP_ID, defaultFontValue.get(values)));
|
||||
}
|
||||
|
||||
// initialize the default group fonts to a font from an exemplar property in that group
|
||||
initializeFontGroup(buttonGroup, BUTTON_FONT_GROUP_ID, "Button.font", values);
|
||||
initializeFontGroup(textGroup, TEXT_FONT_GROUP_ID, "TextField.font", values);
|
||||
initializeFontGroup(widgetGroup, WIDGET_FONT_GROUP_ID, "Table.font", values);
|
||||
initializeFontGroup(componentGroup, COMPONENT_FONT_GROUP_ID, "Panel.font", values);
|
||||
initializeFontGroup(menuGroup, MENU_FONT_GROUP_ID, "Menu.font", values);
|
||||
initializeFontGroup(menuGroup, MENU_ACCELERATOR_FONT_GROUP_ID, "Menu.acceleratorFont",
|
||||
values);
|
||||
}
|
||||
|
||||
private void initializeFontGroup(PropertyGroup group, String fontGroupId, String exemplarId,
|
||||
GThemeValueMap values) {
|
||||
FontValue fontValue = values.getFont(exemplarId);
|
||||
if (fontValue != null) {
|
||||
Font font = fontValue.getRawValue();
|
||||
values.addFont(new FontValue(fontGroupId, font));
|
||||
group.addFontMapping(font, fontGroupId);
|
||||
}
|
||||
}
|
||||
|
||||
private Set<PropertyGroup> getPropertyGroups() {
|
||||
Set<PropertyGroup> set = new HashSet<>();
|
||||
set.add(buttonGroup);
|
||||
set.add(menuGroup);
|
||||
set.add(textGroup);
|
||||
set.add(widgetGroup);
|
||||
set.add(componentGroup);
|
||||
return set;
|
||||
}
|
||||
|
||||
private Map<String, PropertyGroup> buildGroupMap(GThemeValueMap values) {
|
||||
Map<String, PropertyGroup> map = new HashMap<>();
|
||||
for (PropertyGroup group : groups) {
|
||||
group.initialize(values);
|
||||
group.populateGroupMap(map);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private String getComponentName(String id) {
|
||||
int dotIndex = id.indexOf(".");
|
||||
if (dotIndex < 0) {
|
||||
return id;
|
||||
}
|
||||
return id.substring(0, dotIndex);
|
||||
}
|
||||
|
||||
private Map<Integer, String> buildColorToSourceMap(GThemeValueMap values) {
|
||||
Map<Integer, String> colorMapping = new HashMap<>();
|
||||
ArrayList<String> reversed = new ArrayList<>(colorSourceProperties);
|
||||
Collections.reverse(reversed);
|
||||
// go through in reverse order so that values at the top of the list have precedence
|
||||
// if multiple propertyBases have the save value.
|
||||
for (String propertyBase : reversed) {
|
||||
ColorValue colorValue = values.getColor(propertyBase);
|
||||
if (colorValue != null) {
|
||||
Color color = colorValue.get(values);
|
||||
colorMapping.put(color.getRGB(), propertyBase);
|
||||
}
|
||||
}
|
||||
return colorMapping;
|
||||
}
|
||||
|
||||
private Map<Font, String> buildFontToSourceMap(GThemeValueMap values) {
|
||||
Map<Font, String> fontMapping = new HashMap<>();
|
||||
ArrayList<String> reversed = new ArrayList<>(fontSourceProperties);
|
||||
Collections.reverse(reversed);
|
||||
// go through in reverse order so that values at the top of the list have precedence
|
||||
// if multiple propertyBases have the save value.
|
||||
for (String propertyBase : reversed) {
|
||||
FontValue fontValue = values.getFont(propertyBase);
|
||||
if (fontValue != null) {
|
||||
Font font = fontValue.get(values);
|
||||
fontMapping.put(font, propertyBase);
|
||||
}
|
||||
}
|
||||
return fontMapping;
|
||||
}
|
||||
|
||||
static class PropertyGroup {
|
||||
private Set<String> groupComponents = new HashSet<>();
|
||||
private List<String> preferredPropertyColorSources = new ArrayList<>();
|
||||
private Map<Integer, String> colorMapping;
|
||||
private Map<Font, String> fontMapping = new HashMap<>();
|
||||
|
||||
PropertyGroup(String[] components, String[] perferredSources) {
|
||||
addComponents(components);
|
||||
addPreferredColorSources(perferredSources);
|
||||
}
|
||||
|
||||
String getSourceProperty(int rgb) {
|
||||
return colorMapping.get(rgb);
|
||||
}
|
||||
|
||||
String getSourceProperty(Font font) {
|
||||
return fontMapping.get(font);
|
||||
}
|
||||
|
||||
void populateGroupMap(Map<String, PropertyGroup> groupMap) {
|
||||
for (String component : groupComponents) {
|
||||
groupMap.put(component, this);
|
||||
}
|
||||
}
|
||||
|
||||
void addPreferredColorSources(String... preferedColorSources) {
|
||||
this.preferredPropertyColorSources.addAll(Arrays.asList(preferedColorSources));
|
||||
}
|
||||
|
||||
void addComponents(String... properties) {
|
||||
groupComponents.addAll(Arrays.asList(properties));
|
||||
}
|
||||
|
||||
void addFontMapping(Font font, String sourceId) {
|
||||
fontMapping.put(font, sourceId);
|
||||
}
|
||||
|
||||
private Map<Integer, String> initialize(GThemeValueMap values) {
|
||||
colorMapping = new HashMap<>();
|
||||
ArrayList<String> reversed = new ArrayList<>(preferredPropertyColorSources);
|
||||
Collections.reverse(reversed);
|
||||
// go through in reverse order so that values at the top of the list have precedence
|
||||
// if multiple propertyBases have the save value.
|
||||
for (String propertyBase : reversed) {
|
||||
ColorValue colorValue = values.getColor(propertyBase);
|
||||
if (colorValue != null) {
|
||||
Color color = colorValue.get(values);
|
||||
colorMapping.put(color.getRGB(), propertyBase);
|
||||
}
|
||||
}
|
||||
return colorMapping;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,716 @@
|
|||
/* ###
|
||||
* 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 java.awt.Font;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.plaf.FontUIResource;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.plaf.basic.BasicLookAndFeel;
|
||||
|
||||
import org.apache.commons.collections4.IteratorUtils;
|
||||
|
||||
import generic.theme.*;
|
||||
import ghidra.util.Msg;
|
||||
|
||||
/**
|
||||
* The purpose of this class is to introduce multiple levels of indirection into the Java
|
||||
* {@code LookAndFeel} (LaF), which allows the user to change these values. Further, when
|
||||
* introducing this indirection we combine the Java settings into user-friendly system ids to make
|
||||
* changing these values easier.
|
||||
* <P>
|
||||
* This class defines these user-friendly groups. The default system assignments are based on the
|
||||
* {@link BasicLookAndFeel} values.
|
||||
* <P>
|
||||
* Subclasses can override the mapping of these standard system values for particular LaFs that have
|
||||
* different keys or color assignments.
|
||||
* <P>
|
||||
* Some basic concepts:
|
||||
* <UL>
|
||||
* <LI>UI Defaults - key-value pairs defined by the Java LaF; there are 2 key types, widget
|
||||
* keys and Java group/reusable keys (e.g., Button.background; control)
|
||||
* <LI>UI Indirection - UI Defaults values are changed to point to custom terms we created to
|
||||
* allow for indirection (e.g., Button.background -> laf.color.Button.background)
|
||||
* <LI>Normalized Keys - keys we created to facilitate the UI Indirection, based upon the Java
|
||||
* keys (e.g., laf.color.Button.background)
|
||||
* <LI>System Color/Font Keys - user facing terms for common color or font concepts into an
|
||||
* easy-to-change setting (e.g., system.color.fg.text)
|
||||
* <LI>Palette Keys - dynamically generated color palette keys based on the LaF for any colors
|
||||
* and fonts that were not mapped into an system color or font (e.g.,
|
||||
* laf.palette.color.01)
|
||||
* </UL>
|
||||
*
|
||||
* <P>
|
||||
* The mapper performs the following operations:
|
||||
* <OL>
|
||||
* <LI>Extracts all color, font, and icon values from the UI Defaults.</LI>
|
||||
* <LI>Use the current LaF values to populate the pre-defined system colors and fonts.</LI>
|
||||
* <LI>Any UI Defaults values not assigned in the previous step will be assigned to a dynamic shared
|
||||
* palette color or font.
|
||||
* <LI>Update Java UI Defaults to use our indirection and system values.</LI>
|
||||
* </OL>
|
||||
*
|
||||
*/
|
||||
public class UiDefaultsMapper {
|
||||
public static final String LAF_COLOR_ID_PREFIX = "laf.color.";
|
||||
public static final String LAF_FONT_ID_PREFIX = "laf.font.";
|
||||
public static final String LAF_ICON_ID_PREFIX = "laf.icon.";
|
||||
private static final String LAF_COLOR_PALETTE_PREFIX = "laf.palette.color.";
|
||||
private static final String LAF_FONT_PALETTE_PREFIX = "laf.palette.font.";
|
||||
|
||||
private static final String[] MENU_COMPONENTS =
|
||||
{ "Menu", "MenuBar", "MenuItem", "PopupMenu", "RadioButtonMenuItem", "CheckBoxMenuItem" };
|
||||
private static final String[] VIEW_COMPONENTS =
|
||||
{ "FileChooser", "ColorChooser", "ComboBox", "List", "Table", "Tree", "TextField",
|
||||
"FormattedTextField", "PasswordField", "TextArea", "TextPane", "EditorPane" };
|
||||
private static final String[] TOOLTIP_COMPONENTS = { "ToolTip" };
|
||||
|
||||
protected UIDefaults defaults;
|
||||
private GThemeValueMap extractedValues;
|
||||
private GThemeValueMap normalizedValues = new GThemeValueMap();
|
||||
|
||||
private Map<String, String> lafIdToNormalizedIdMap = new HashMap<>();
|
||||
protected Set<String> ignoredLafIds = new HashSet<>();
|
||||
|
||||
private Map<String, ColorMatcher> componentToColorMatcherMap = new HashMap<>();
|
||||
private Map<String, FontMatcher> componentToFontMatcherMap = new HashMap<>();
|
||||
|
||||
// @formatter:off
|
||||
protected ColorMatcher viewColorMatcher = new ColorMatcher(BG_VIEW_ID,
|
||||
FG_VIEW_ID,
|
||||
BG_VIEW_SELECTED_ID,
|
||||
FG_VIEW_SELECTED_ID);
|
||||
protected ColorMatcher tooltipColorMatcher = new ColorMatcher(BG_TOOLTIP_ID,
|
||||
FG_TOOLTIP_ID);
|
||||
protected ColorMatcher defaultColorMatcher = new ColorMatcher(BG_CONTROL_ID,
|
||||
FG_CONTROL_ID,
|
||||
BG_VIEW_ID,
|
||||
FG_VIEW_ID,
|
||||
FG_DISABLED_ID,
|
||||
BG_VIEW_SELECTED_ID,
|
||||
FG_VIEW_SELECTED_ID,
|
||||
BG_TOOLTIP_ID,
|
||||
BG_BORDER_ID);
|
||||
|
||||
protected FontMatcher menuFontMatcher = new FontMatcher(FONT_MENU_ID);
|
||||
protected FontMatcher viewFontMatcher = new FontMatcher(FONT_VIEW_ID);
|
||||
protected FontMatcher defaultFontMatcher = new FontMatcher(FONT_CONTROL_ID,
|
||||
FONT_VIEW_ID,
|
||||
FONT_MENU_ID);
|
||||
|
||||
//@formatter:on
|
||||
|
||||
private Map<Color, String> lafColorPaletteMap = new HashMap<>();
|
||||
private Map<Font, String> lafFontPaletteMap = new HashMap<>();
|
||||
private int nextColorPaletteId;
|
||||
private int nextFontPaletteId;
|
||||
|
||||
protected UiDefaultsMapper(UIDefaults defaults) {
|
||||
this.defaults = defaults;
|
||||
this.extractedValues = extractColorFontAndIconValuesFromDefaults();
|
||||
|
||||
assignSystemColorValues();
|
||||
assignSystemFontValues();
|
||||
|
||||
registerIgnoredLafIds();
|
||||
|
||||
assignColorMatchersToComponentIds();
|
||||
assignFontMatchersToComponentIds();
|
||||
|
||||
assignNormalizedColorValues();
|
||||
assignNormalizedFontValues();
|
||||
assignNormalizedIconValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the normalized id to value map that will be installed into the
|
||||
* ApplicationThemeManager to be the user changeable values for affecting the Java
|
||||
* LookAndFeel colors, fonts, and icons
|
||||
* @return a map of changeable values that affect java LookAndFeel values
|
||||
*/
|
||||
public GThemeValueMap getJavaDefaults() {
|
||||
return normalizedValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the UIDefaults file with indirect colors (GColors) and any overridden font or icon
|
||||
* values as defined in theme.properites files
|
||||
* @param overrides a Map that contains possible LookAndFeel value overridess
|
||||
*/
|
||||
public void installValuesIntoUIDefaults(GThemeValueMap overrides) {
|
||||
//
|
||||
// In the UI Defaults, colors use indirect values and fonts and icons use direct values.
|
||||
// Here we install our GColors for the indirect colors. Then we set any font and icon
|
||||
// values that are different than the defaults.
|
||||
//
|
||||
installGColorsIntoUIDefaults();
|
||||
installOverriddenFontsIntoUIDefaults(overrides);
|
||||
installOverriddenIconsIntoUIDefaults(overrides);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mapping of normalized LaF Ids so that when fonts and icons get changed using the
|
||||
* normalized ids that are presented to the user, we know which LaF ids need to be updated in
|
||||
* the UiDefaults so that the LookAndFeel will pick up and use the changes.
|
||||
* @return a mapping of normalized LaF ids to original LaF ids.
|
||||
*/
|
||||
public Map<String, String> getNormalizedIdToLafIdMap() {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
for (Entry<String, String> entry : lafIdToNormalizedIdMap.entrySet()) {
|
||||
String lafId = entry.getKey();
|
||||
String standardId = entry.getValue();
|
||||
map.put(standardId, lafId);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers any {@link LookAndFeel} ids that are not used directly (e.g. "control", "text",
|
||||
* etc.) so that these values won't get mapped to any normalized id. There is no need for these
|
||||
* values to show up in the theme values, since changing them will have no effect. They are
|
||||
* used to seed the values for the system color and fonts. Subclasses should
|
||||
* override this method to add additional ids so they won't show up in the theme values.
|
||||
*/
|
||||
protected void registerIgnoredLafIds() {
|
||||
|
||||
ignoredLafIds.add("desktop");
|
||||
ignoredLafIds.add("activeCaption");
|
||||
ignoredLafIds.add("activeCaptionText");
|
||||
ignoredLafIds.add("activeCaptionBorder");
|
||||
ignoredLafIds.add("inactiveCaption");
|
||||
ignoredLafIds.add("inactiveCaptionText");
|
||||
ignoredLafIds.add("inactiveCaptionBorder");
|
||||
ignoredLafIds.add("window");
|
||||
ignoredLafIds.add("windowBorder");
|
||||
ignoredLafIds.add("windowText");
|
||||
ignoredLafIds.add("menu");
|
||||
ignoredLafIds.add("menuText");
|
||||
ignoredLafIds.add("text");
|
||||
ignoredLafIds.add("textText");
|
||||
ignoredLafIds.add("textHighlight");
|
||||
ignoredLafIds.add("textHighightText");
|
||||
ignoredLafIds.add("textInactiveText");
|
||||
ignoredLafIds.add("control");
|
||||
ignoredLafIds.add("controlText");
|
||||
ignoredLafIds.add("controlHighlight");
|
||||
ignoredLafIds.add("controlLtHighlight");
|
||||
ignoredLafIds.add("controlShadow");
|
||||
ignoredLafIds.add("controlDkShadow");
|
||||
ignoredLafIds.add("info");
|
||||
ignoredLafIds.add("infoText");
|
||||
ignoredLafIds.add("scrollbar");
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the values to assign to all the system color ids based on the system ids
|
||||
* defined in the {@link BasicLookAndFeel}
|
||||
*/
|
||||
protected void assignSystemColorValues() {
|
||||
|
||||
assignSystemColorFromLafId(BG_CONTROL_ID, "control");
|
||||
assignSystemColorFromLafId(FG_CONTROL_ID, "controlText");
|
||||
assignSystemColorFromLafId(BG_BORDER_ID, "controlShadow");
|
||||
|
||||
assignSystemColorFromLafId(BG_VIEW_ID, "window");
|
||||
assignSystemColorFromLafId(FG_VIEW_ID, "windowText");
|
||||
assignSystemColorFromLafId(BG_VIEW_SELECTED_ID, "textHighlight");
|
||||
assignSystemColorFromLafId(FG_VIEW_SELECTED_ID, "textHighlightText");
|
||||
|
||||
assignSystemColorFromLafId(FG_DISABLED_ID, "textInactiveText");
|
||||
|
||||
assignSystemColorFromLafId(BG_TOOLTIP_ID, "info");
|
||||
assignSystemColorFromLafId(FG_TOOLTIP_ID, "infoText");
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the system color id to a color value from the UiDefaults map.
|
||||
* @param systemColorId the system color id to get a value for
|
||||
* @param lafId the LaF key to use to retrieve a color from the UiDefaults
|
||||
*/
|
||||
protected void assignSystemColorFromLafId(String systemColorId, String lafId) {
|
||||
Color lafColor = defaults.getColor(lafId);
|
||||
if (lafColor == null) {
|
||||
Msg.debug(this, "Missing value for system color: \"" + systemColorId +
|
||||
"\". No value for laf id: \"" + lafId + "\".");
|
||||
return;
|
||||
}
|
||||
normalizedValues.addColor(new ColorValue(systemColorId, lafColor));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the system color id to a directly specified color and does not use the LaF to populate
|
||||
* the system color.
|
||||
* @param systemColorId the system color id to assign the given color
|
||||
* @param color the color to be assigned to the system color id
|
||||
*/
|
||||
protected void assignSystemColorDirect(String systemColorId, Color color) {
|
||||
normalizedValues.addColor(new ColorValue(systemColorId, color));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the system font id a directly specified font and does not use the LaF to populate
|
||||
* the system font.
|
||||
* @param systemFontId the system font id to assign the given font
|
||||
* @param font the font to be assigned to the system font id
|
||||
*/
|
||||
protected void assignSystemFontDirect(String systemFontId, Font font) {
|
||||
normalizedValues.addFont(new FontValue(systemFontId, font));
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the values to use for the system fonts.
|
||||
*/
|
||||
protected void assignSystemFontValues() {
|
||||
assignSystemFontFromLafId(FONT_CONTROL_ID, "Button.font");
|
||||
assignSystemFontFromLafId(FONT_VIEW_ID, "Table.font");
|
||||
assignSystemFontFromLafId(FONT_MENU_ID, "Menu.font");
|
||||
}
|
||||
|
||||
private void assignSystemFontFromLafId(String systemFontId, String lafId) {
|
||||
|
||||
Font lafFont = extractedValues.getResolvedFont(lafId);
|
||||
if (lafFont == null) {
|
||||
Msg.debug(this, "Missing value for system font: \"" + systemFontId +
|
||||
"\". No value for laf id: \"" + lafId + "\".");
|
||||
return;
|
||||
}
|
||||
normalizedValues.addFont(new FontValue(systemFontId, fromUiResource(lafFont)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the appropriate font matcher to each component in the related component group
|
||||
*/
|
||||
protected void assignFontMatchersToComponentIds() {
|
||||
defineComponentFontMatcher(MENU_COMPONENTS, menuFontMatcher);
|
||||
defineComponentFontMatcher(VIEW_COMPONENTS, viewFontMatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the appropriate color matcher to each component in the related component group
|
||||
*/
|
||||
protected void assignColorMatchersToComponentIds() {
|
||||
defineComponentColorMatcher(VIEW_COMPONENTS, viewColorMatcher);
|
||||
defineComponentColorMatcher(TOOLTIP_COMPONENTS, tooltipColorMatcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns every component name in the component group to the given ColorValueMatcher
|
||||
* @param componentGroups a list of component names
|
||||
* @param matcher the ColorMatcher that will provide the precedence of system ids to
|
||||
* search when replacing LaF component specific values
|
||||
*/
|
||||
private void defineComponentColorMatcher(String[] componentGroups, ColorMatcher matcher) {
|
||||
for (String componentGroup : componentGroups) {
|
||||
componentToColorMatcherMap.put(componentGroup, matcher);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns every component name in a component group to the given FontValueMapper
|
||||
* @param componentGroups a list of component names
|
||||
* @param matcher the FontValueMatcher that will provide the precedence of ststem font ids to
|
||||
* search when replacing LaF component specific fonts with a system Font
|
||||
*/
|
||||
private void defineComponentFontMatcher(String[] componentGroups, FontMatcher matcher) {
|
||||
for (String componentGroup : componentGroups) {
|
||||
componentToFontMatcherMap.put(componentGroup, matcher);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the GThemeValueMap with normalized font ids. For example
|
||||
* it will assign "laf.font.Button.font" to "system.font.control".
|
||||
*/
|
||||
private void assignNormalizedFontValues() {
|
||||
List<String> list = new ArrayList<>(extractedValues.getFontIds());
|
||||
Collections.sort(list);
|
||||
for (String lafId : list) {
|
||||
// we don't want to create java defaults for laf system ids since changing them would
|
||||
// have no effect
|
||||
if (ignoredLafIds.contains(lafId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String createdId = LAF_FONT_ID_PREFIX + lafId;
|
||||
lafIdToNormalizedIdMap.put(lafId, createdId);
|
||||
|
||||
Font lafFont = extractedValues.getResolvedFont(lafId);
|
||||
FontValue fontValue = getFontValue(createdId, lafId, lafFont);
|
||||
normalizedValues.addFont(fontValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the GThemeValueMap with normalized icon ids. For example
|
||||
* it will assign "laf.font.CheckBox.icon" to a direct icon that was mined from the UiDefaults
|
||||
* using the id "CheckBox.icon"
|
||||
*/
|
||||
private void assignNormalizedIconValues() {
|
||||
for (String lafId : extractedValues.getIconIds()) {
|
||||
String createdId = LAF_ICON_ID_PREFIX + lafId;
|
||||
Icon icon = extractedValues.getResolvedIcon(lafId);
|
||||
if (icon != null) {
|
||||
normalizedValues.addIcon(new IconValue(createdId, icon));
|
||||
lafIdToNormalizedIdMap.put(lafId, createdId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the GThemeValueMap with normalized color ids. For example
|
||||
* it will assign "laf.color.Button.background" to "system.color.bg.control".
|
||||
*/
|
||||
protected void assignNormalizedColorValues() {
|
||||
List<String> list = new ArrayList<>(extractedValues.getColorIds());
|
||||
Collections.sort(list);
|
||||
for (String lafId : list) {
|
||||
if (ignoredLafIds.contains(lafId)) {
|
||||
continue;
|
||||
}
|
||||
String createdId = LAF_COLOR_ID_PREFIX + lafId;
|
||||
lafIdToNormalizedIdMap.put(lafId, createdId);
|
||||
|
||||
Color lafColor = extractedValues.getResolvedColor(lafId);
|
||||
ColorValue colorValue = getColorValue(createdId, lafId, lafColor);
|
||||
normalizedValues.addColor(colorValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link ColorValue} for the given id. It either finds a system color id that matches
|
||||
* the given color, or a shared palette color if no system color found.
|
||||
* @param id the id to get a color value for
|
||||
* @param lafId the lafId that we are creating a standard id/color value for
|
||||
* @param lafColor the color as defined in the UiDefaults for the lafId
|
||||
* @return a {@link ColorValue} for the given id. It either finds a system color id that matches
|
||||
* the given color, or a shared palette color if no system color found.
|
||||
*/
|
||||
private ColorValue getColorValue(String id, String lafId, Color lafColor) {
|
||||
String systemId = findSystemColorId(lafId, lafColor);
|
||||
|
||||
if (systemId == null) {
|
||||
systemId = getColorPaletteId(lafColor);
|
||||
}
|
||||
|
||||
return new ColorValue(id, systemId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link FontValue} for the given id. It either finds a system font id that matches
|
||||
* the given Font, or a shared palette Font if no system font found.
|
||||
* @param id the id to get a Font value for
|
||||
* @param lafId the lafId that we are creating a standard id/Font value for
|
||||
* @param lafFont the Font as defined in the UiDefaults for the lafId
|
||||
* @return a {@link FontValue} for the given id. It either finds a system font id that matches
|
||||
* the given Font, or a shared palette Font if no group Font found.
|
||||
*/
|
||||
private FontValue getFontValue(String id, String lafId, Font lafFont) {
|
||||
String systemFontId = findSystemFontId(lafId, lafFont);
|
||||
if (systemFontId == null) {
|
||||
systemFontId = getFontPaletteId(lafFont);
|
||||
}
|
||||
return new FontValue(id, systemFontId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a matching color palette id or creates a new one
|
||||
* @param lafColor the color to find a matching palette color for
|
||||
* @return a matching color palette id or creates a new one
|
||||
*/
|
||||
private String getColorPaletteId(Color lafColor) {
|
||||
String paletteId = lafColorPaletteMap.get(lafColor);
|
||||
if (paletteId == null) {
|
||||
nextColorPaletteId++;
|
||||
// laf.palette.color01
|
||||
paletteId = String.format("%s%02d", LAF_COLOR_PALETTE_PREFIX, nextColorPaletteId);
|
||||
lafColorPaletteMap.put(lafColor, paletteId);
|
||||
normalizedValues.addColor(new ColorValue(paletteId, lafColor));
|
||||
}
|
||||
return paletteId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a matching font palette id or creates a new one
|
||||
* @param lafFont the font to find a matching palette font for
|
||||
* @return a matching font palette id or creates a new one
|
||||
*/
|
||||
private String getFontPaletteId(Font lafFont) {
|
||||
String paletteId = lafFontPaletteMap.get(lafFont);
|
||||
if (paletteId == null) {
|
||||
nextFontPaletteId++;
|
||||
|
||||
// laf.palette.font01
|
||||
paletteId = String.format("%s%02d", LAF_FONT_PALETTE_PREFIX, nextFontPaletteId);
|
||||
lafFontPaletteMap.put(lafFont, paletteId);
|
||||
normalizedValues.addFont(new FontValue(paletteId, lafFont));
|
||||
}
|
||||
return paletteId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to find a system color id that matches the given color. The order system ids are
|
||||
* searched depends on the component (Button, Menu, etc.) which is derived from the given
|
||||
* lafId.
|
||||
* @param lafId the lafId we are attempting to get a system color for
|
||||
* @param lafColor the color we are trying to match to a system color
|
||||
* @return a system color id that matches the given lafColor or null if one can't be found
|
||||
*/
|
||||
private String findSystemColorId(String lafId, Color lafColor) {
|
||||
String componentName = getComponentName(lafId);
|
||||
ColorMatcher colorMatcher = componentToColorMatcherMap.get(componentName);
|
||||
// check in widget specific group first
|
||||
if (colorMatcher != null) {
|
||||
String systemId = colorMatcher.getSystemId(lafColor);
|
||||
if (systemId != null) {
|
||||
return systemId;
|
||||
}
|
||||
}
|
||||
// not found in widget specific group, check general component groups
|
||||
return defaultColorMatcher.getSystemId(lafColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to find a system font id that matches the given font. The order system fonts are
|
||||
* searched depends on the component (Button, Menu, etc.) which is derived from the given
|
||||
* lafId.
|
||||
* @param lafId the lafId we are attempting to get a system font for
|
||||
* @param lafFont the font we are trying to match to a system font
|
||||
* @return a system font id that matches the given lafFont or null if one can't be found
|
||||
*/
|
||||
private String findSystemFontId(String lafId, Font lafFont) {
|
||||
String componentName = getComponentName(lafId);
|
||||
FontMatcher fontMatcher = componentToFontMatcherMap.get(componentName);
|
||||
// check in widget specific group first
|
||||
if (fontMatcher != null) {
|
||||
String systemId = fontMatcher.getSystemId(lafFont);
|
||||
if (systemId != null) {
|
||||
return systemId;
|
||||
}
|
||||
}
|
||||
// not found in widget specific group, check general component groups
|
||||
return defaultFontMatcher.getSystemId(lafFont);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the component name from the given lafId.
|
||||
* @param lafId the lafId that starts with a component name
|
||||
* @return the component name from the given lafId.
|
||||
*/
|
||||
private String getComponentName(String lafId) {
|
||||
int dotIndex = lafId.indexOf(".");
|
||||
if (dotIndex < 0) {
|
||||
return lafId;
|
||||
}
|
||||
return lafId.substring(0, dotIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces UiDefaults values with {@link GColorUIResource} values the provide the theme
|
||||
* indirection.
|
||||
*/
|
||||
protected void installGColorsIntoUIDefaults() {
|
||||
Map<String, GColorUIResource> cachedColors = new HashMap<>();
|
||||
|
||||
for (String lafId : extractedValues.getColorIds()) {
|
||||
String standardColorId = lafIdToNormalizedIdMap.get(lafId);
|
||||
if (standardColorId != null) {
|
||||
GColorUIResource sharedGColor = getSharedGColor(cachedColors, standardColorId);
|
||||
defaults.put(lafId, sharedGColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces any theme overridden icons into the UiDefaults.
|
||||
* @param overrides the theme values that potentially override a laf icon value
|
||||
*/
|
||||
private void installOverriddenIconsIntoUIDefaults(GThemeValueMap overrides) {
|
||||
for (String lafId : extractedValues.getIconIds()) {
|
||||
String standardId = lafIdToNormalizedIdMap.get(lafId);
|
||||
if (overrides.containsIcon(standardId)) {
|
||||
defaults.put(lafId, overrides.getResolvedIcon(standardId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces any theme overridden fonts into the UiDefaults.
|
||||
* @param overrides the theme values that potentially override a laf font value
|
||||
*/
|
||||
private void installOverriddenFontsIntoUIDefaults(GThemeValueMap overrides) {
|
||||
for (String lafId : extractedValues.getFontIds()) {
|
||||
String standardId = lafIdToNormalizedIdMap.get(lafId);
|
||||
if (overrides.containsFont(standardId)) {
|
||||
defaults.put(lafId, new FontUIResource(overrides.getResolvedFont(standardId)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When putting {@link GColorUIResource} values into the UiDefaults, we need to make sure
|
||||
* we use the same instance for the same color. Some LookAndFeels do "==" checks on colors
|
||||
* when updating UI values.
|
||||
* @param cache the cache of shared {@link GColorUIResource}s
|
||||
* @param id the id we are creating a shared GColorUIResource for
|
||||
* @return a GColorUIResource such that only one instance for a given id exists.
|
||||
*/
|
||||
private GColorUIResource getSharedGColor(Map<String, GColorUIResource> cache, String id) {
|
||||
GColorUIResource gColor = cache.get(id);
|
||||
if (gColor == null) {
|
||||
gColor = new GColorUIResource(id);
|
||||
cache.put(id, gColor);
|
||||
}
|
||||
return gColor;
|
||||
}
|
||||
|
||||
protected void overrideColor(String lafId, String sytemId) {
|
||||
String normalizedId = lafIdToNormalizedIdMap.get(lafId);
|
||||
if (normalizedId == null) {
|
||||
Msg.debug(this, "Missing value for laf id: \"" + lafId);
|
||||
return;
|
||||
}
|
||||
normalizedValues.addColor(new ColorValue(normalizedId, sytemId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Mines the UiDefaults for all color values.
|
||||
* @return a map of id to values for UIDefaults Colors.
|
||||
*/
|
||||
protected GThemeValueMap extractColorFontAndIconValuesFromDefaults() {
|
||||
GThemeValueMap values = new GThemeValueMap();
|
||||
|
||||
List<String> ids = getLookAndFeelIdsForType(Color.class);
|
||||
for (String id : ids) {
|
||||
values.addColor(new ColorValue(id, defaults.getColor(id)));
|
||||
}
|
||||
|
||||
ids = getLookAndFeelIdsForType(Font.class);
|
||||
for (String id : ids) {
|
||||
values.addFont(new FontValue(id, defaults.getFont(id)));
|
||||
}
|
||||
|
||||
ids = getLookAndFeelIdsForType(Icon.class);
|
||||
for (String id : ids) {
|
||||
Icon icon = defaults.getIcon(id);
|
||||
values.addIcon(new IconValue(id, icon));
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
private Font fromUiResource(Font font) {
|
||||
if (font instanceof UIResource) {
|
||||
return new FontNonUiResource(font);
|
||||
}
|
||||
return font;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all ids in the UIDefaults for a specific type (Color, Font, Icon)
|
||||
* @param clazz the class of the type to mine for
|
||||
* @return a list of all ids that have the given value type
|
||||
*/
|
||||
private List<String> getLookAndFeelIdsForType(Class<?> clazz) {
|
||||
List<String> colorKeys = new ArrayList<>();
|
||||
List<Object> keyList = IteratorUtils.toList(defaults.keys().asIterator());
|
||||
for (Object key : keyList) {
|
||||
if (key instanceof String) {
|
||||
Object value = defaults.get(key);
|
||||
if (clazz.isInstance(value)) {
|
||||
colorKeys.add((String) key);
|
||||
}
|
||||
}
|
||||
}
|
||||
return colorKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to match values (Colors or Fonts) into appropriate system ids. System ids are searched
|
||||
* in the order the system ids are given in the constructor.
|
||||
* @param <T> The theme value type (Color or Font)
|
||||
*/
|
||||
private abstract class ValueMatcher<T> {
|
||||
private Map<T, String> map = new HashMap<>();
|
||||
private List<String> systemIdList;
|
||||
private boolean initialized;
|
||||
|
||||
ValueMatcher(String... systemIds) {
|
||||
systemIdList = new ArrayList<>(Arrays.asList(systemIds));
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
initialized = true;
|
||||
|
||||
// process in reverse order so that earlier items in the list can overwrite later
|
||||
// items if they have the same font
|
||||
for (int i = systemIdList.size() - 1; i >= 0; i--) {
|
||||
String systemId = systemIdList.get(i);
|
||||
T value = getValueFromJavaDefaults(systemId);
|
||||
if (value != null) {
|
||||
map.put(value, systemId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract T getValueFromJavaDefaults(String systemId);
|
||||
|
||||
String getSystemId(T value) {
|
||||
if (!initialized) {
|
||||
initialize();
|
||||
}
|
||||
return map.get(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches through all the system color ids registered for this matcher to find a system color
|
||||
* id that matches a given color. The order that color system ids are added is important and is
|
||||
* the precedence order if more than one system color id has the same color.
|
||||
*/
|
||||
private class ColorMatcher extends ValueMatcher<Color> {
|
||||
|
||||
ColorMatcher(String... systemIds) {
|
||||
super(systemIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Color getValueFromJavaDefaults(String systemId) {
|
||||
return normalizedValues.getResolvedColor(systemId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches through all the system font ids registered for this matcher to find a system font id
|
||||
* that matches a given font. The order that system font ids are added is important and is
|
||||
* the precedence order if more than one system id has the same font.
|
||||
*/
|
||||
private class FontMatcher extends ValueMatcher<Font> {
|
||||
FontMatcher(String... systemIds) {
|
||||
super(systemIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Font getValueFromJavaDefaults(String systemId) {
|
||||
return normalizedValues.getResolvedFont(systemId);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 WindowsClassicLookAndFeelManager extends LookAndFeelManager {
|
|||
public WindowsClassicLookAndFeelManager(ApplicationThemeManager themeManager) {
|
||||
super(LafType.WINDOWS_CLASSIC, themeManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UiDefaultsMapper getUiDefaultsMapper(UIDefaults defaults) {
|
||||
return new WindowsClassicUiDefaultsMapper(defaults);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/* ###
|
||||
* 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 WindowsClassicUiDefaultsMapper extends UiDefaultsMapper {
|
||||
|
||||
protected WindowsClassicUiDefaultsMapper(UIDefaults defaults) {
|
||||
super(defaults);
|
||||
}
|
||||
|
||||
}
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package generic.theme.laf;
|
||||
|
||||
import javax.swing.UIDefaults;
|
||||
|
||||
import generic.theme.ApplicationThemeManager;
|
||||
import generic.theme.LafType;
|
||||
|
||||
|
@ -24,4 +26,9 @@ public class WindowsLookAndFeelManager extends LookAndFeelManager {
|
|||
super(LafType.WINDOWS, themeManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UiDefaultsMapper getUiDefaultsMapper(UIDefaults defaults) {
|
||||
return new WindowsUiDefaultsMapper(defaults);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/* ###
|
||||
* 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 WindowsUiDefaultsMapper extends UiDefaultsMapper {
|
||||
|
||||
protected WindowsUiDefaultsMapper(UIDefaults defaults) {
|
||||
super(defaults);
|
||||
}
|
||||
|
||||
}
|
|
@ -23,12 +23,10 @@ import java.awt.Font;
|
|||
import java.net.URL;
|
||||
import java.util.*;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.*;
|
||||
import javax.swing.plaf.UIResource;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.*;
|
||||
|
||||
import generic.theme.builtin.*;
|
||||
import resources.ResourceManager;
|
||||
|
@ -73,6 +71,12 @@ public class ApplicationThemeManagerTest {
|
|||
themeManager = new DummyApplicationThemeManager();
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanupUIDefaults() {
|
||||
UIDefaults defaults = UIManager.getDefaults();
|
||||
defaults.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDarkThemeColorOverride() {
|
||||
GColor gColor = new GColor("color.test.bg");
|
||||
|
@ -348,21 +352,21 @@ public class ApplicationThemeManagerTest {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected ThemeDefaultsProvider getThemeDefaultsProvider() {
|
||||
return new ThemeDefaultsProvider() {
|
||||
protected ApplicationThemeDefaults getApplicationDefaults() {
|
||||
return new ApplicationThemeDefaults() {
|
||||
|
||||
@Override
|
||||
public GThemeValueMap getDefaults() {
|
||||
public GThemeValueMap getLightValues() {
|
||||
return defaultValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GThemeValueMap getDarkDefaults() {
|
||||
public GThemeValueMap getDarkValues() {
|
||||
return darkDefaultValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GThemeValueMap getLookAndFeelDefaults(LafType lafType) {
|
||||
public GThemeValueMap getLookAndFeelValues(LafType lafType) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,104 +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 static ghidra.util.WebColors.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import generic.theme.*;
|
||||
|
||||
public class ThemeGrouperTest {
|
||||
private static Font FONT1 = new Font("Dialog", Font.PLAIN, 12);
|
||||
private static Font FONT2 = new Font("Dialog", Font.BOLD, 16);
|
||||
|
||||
private ThemeGrouper grouper;
|
||||
private GThemeValueMap values;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
grouper = new ThemeGrouper();
|
||||
values = new GThemeValueMap();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGroupColorUsingPreferredSources() {
|
||||
initColor("control", RED);
|
||||
initColor("menu", RED);
|
||||
initColor("Menu.background", RED);
|
||||
grouper.group(values);
|
||||
|
||||
ColorValue colorValue = values.getColor("Menu.background");
|
||||
assertEquals("menu", colorValue.getReferenceId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGroupColorUsingNonPreferredSourceWhenPreferredDoesntMatch() {
|
||||
initColor("control", RED);
|
||||
initColor("menu", BLUE);
|
||||
initColor("Menu.background", RED);
|
||||
grouper.group(values);
|
||||
|
||||
ColorValue colorValue = values.getColor("Menu.background");
|
||||
assertEquals("control", colorValue.getReferenceId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGroupFontUsingPreferredSources() {
|
||||
initFont("Button.font", FONT1);
|
||||
initFont("RadioButton.font", FONT1);
|
||||
initFont("Menu.font", FONT1);
|
||||
initFont("MenuItem.font", FONT1);
|
||||
grouper.group(values);
|
||||
|
||||
assertEquals(FONT1, values.getFont("font.button").getRawValue());
|
||||
assertEquals(FONT1, values.getFont("font.menu").getRawValue());
|
||||
assertEquals("font.button", values.getFont("Button.font").getReferenceId());
|
||||
assertEquals("font.button", values.getFont("RadioButton.font").getReferenceId());
|
||||
assertEquals("font.menu", values.getFont("Menu.font").getReferenceId());
|
||||
assertEquals("font.menu", values.getFont("MenuItem.font").getReferenceId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGroupFontUsingNonPreferredSourceWhenPreferredDoesntMatch() {
|
||||
initFont("Button.font", FONT1);
|
||||
initFont("RadioButton.font", FONT1);
|
||||
initFont("Menu.font", FONT2);
|
||||
initFont("MenuItem.font", FONT1);
|
||||
grouper.group(values);
|
||||
|
||||
assertEquals(FONT1, values.getFont("font.button").getRawValue());
|
||||
assertEquals(FONT2, values.getFont("font.menu").getRawValue());
|
||||
assertEquals("font.button", values.getFont("Button.font").getReferenceId());
|
||||
assertEquals("font.button", values.getFont("RadioButton.font").getReferenceId());
|
||||
assertEquals("font.menu", values.getFont("Menu.font").getReferenceId());
|
||||
assertEquals("font.button", values.getFont("MenuItem.font").getReferenceId());
|
||||
}
|
||||
|
||||
private void initColor(String id, Color color) {
|
||||
values.addColor(new ColorValue(id, color));
|
||||
}
|
||||
|
||||
private void initFont(String id, Font font) {
|
||||
values.addFont(new FontValue(id, font));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
/* ###
|
||||
* 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 org.junit.Assert.*;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.UIDefaults;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import generic.theme.*;
|
||||
import resources.ResourceManager;
|
||||
|
||||
public class UIDefaultsMapperTest {
|
||||
|
||||
private Icon ICON = ResourceManager.loadImage("images/exec.png");
|
||||
private Font SMALL_FONT = new Font("Dialog", Font.PLAIN, 4);
|
||||
private Font FONT = new Font("Dialog", Font.PLAIN, 13);
|
||||
private UIDefaults defaults;
|
||||
private UiDefaultsMapper mapper;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
defaults = createDefaults();
|
||||
defaults.put("control", Color.RED);
|
||||
defaults.put("Button.background", Color.RED);
|
||||
defaults.put("Button.font", FONT);
|
||||
defaults.put("CheckBox.icon", ICON);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetJavaDefaults() {
|
||||
mapper = new UiDefaultsMapper(defaults);
|
||||
GThemeValueMap javaDefaults = mapper.getJavaDefaults();
|
||||
|
||||
assertEquals(Color.RED, javaDefaults.getResolvedColor("system.color.bg.control"));
|
||||
assertEquals(Color.RED, javaDefaults.getResolvedColor("laf.color.Button.background"));
|
||||
|
||||
assertEquals(FONT, javaDefaults.getResolvedFont("laf.font.Button.font"));
|
||||
assertEquals(ICON, javaDefaults.getResolvedIcon("laf.icon.CheckBox.icon"));
|
||||
|
||||
assertIndirectColor(javaDefaults, "laf.color.Button.background", "system.color.bg.control");
|
||||
assertIndirectFont(javaDefaults, "laf.font.Button.font", "system.font.control");
|
||||
assertDirectIcon(javaDefaults, "laf.icon.CheckBox.icon", ICON);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetJavaDefaultsNoGroupCreatesPaletteColors() {
|
||||
defaults.put("CheckBox.background", Color.GREEN); // Green not defined in a color group
|
||||
defaults.put("ToggleButton.background", Color.GREEN); // Green not defined in a color group
|
||||
defaults.put("RadioButton.background", Color.BLUE); // Blue not defined in a color group
|
||||
mapper = new UiDefaultsMapper(defaults);
|
||||
|
||||
GThemeValueMap javaDefaults = mapper.getJavaDefaults();
|
||||
|
||||
// expecting two palette groups to be created
|
||||
String greenPalette = findPaletteColor(javaDefaults, Color.GREEN);
|
||||
String bluePalette = findPaletteColor(javaDefaults, Color.BLUE);
|
||||
|
||||
assertIndirectColor(javaDefaults, "laf.color.Button.background", "system.color.bg.control");
|
||||
assertIndirectColor(javaDefaults, "laf.color.CheckBox.background", greenPalette);
|
||||
assertIndirectColor(javaDefaults, "laf.color.ToggleButton.background", greenPalette);
|
||||
assertIndirectColor(javaDefaults, "laf.color.RadioButton.background", bluePalette);
|
||||
assertDirectColor(javaDefaults, "system.color.bg.control", Color.RED);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetJavaDefaultsNoGroupCreatesPaletteFonts() {
|
||||
defaults.put("CheckBox.font", SMALL_FONT); // SMALL_FONT not defined in a font group
|
||||
defaults.put("ToggleButton.font", SMALL_FONT); // Green not defined in a color group
|
||||
mapper = new UiDefaultsMapper(defaults);
|
||||
|
||||
GThemeValueMap javaDefaults = mapper.getJavaDefaults();
|
||||
|
||||
assertDirectFont(javaDefaults, "laf.palette.font.01", SMALL_FONT);
|
||||
assertIndirectFont(javaDefaults, "laf.font.ToggleButton.font", "laf.palette.font.01");
|
||||
assertIndirectFont(javaDefaults, "laf.font.CheckBox.font", "laf.palette.font.01");
|
||||
assertIndirectFont(javaDefaults, "laf.font.Button.font", "system.font.control");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstallValuesIntoUiDefaults() {
|
||||
mapper = new UiDefaultsMapper(defaults);
|
||||
mapper.installValuesIntoUIDefaults(new GThemeValueMap());
|
||||
|
||||
assertEquals(new GColorUIResource("laf.color.Button.background"),
|
||||
defaults.getColor("Button.background"));
|
||||
assertEquals(FONT, defaults.getFont("Button.font"));
|
||||
assertEquals(ICON, defaults.getIcon("CheckBox.icon"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetNormalizedIdToLafidMap() {
|
||||
mapper = new UiDefaultsMapper(defaults);
|
||||
Map<String, String> map = mapper.getNormalizedIdToLafIdMap();
|
||||
assertEquals("Button.background", map.get("laf.color.Button.background"));
|
||||
assertEquals("Button.font", map.get("laf.font.Button.font"));
|
||||
assertEquals("CheckBox.icon", map.get("laf.icon.CheckBox.icon"));
|
||||
}
|
||||
|
||||
private void assertDirectColor(GThemeValueMap javaDefaults, String id, Color color) {
|
||||
ColorValue colorValue = javaDefaults.getColor(id);
|
||||
assertEquals(color, colorValue.getRawValue());
|
||||
}
|
||||
|
||||
private void assertDirectFont(GThemeValueMap javaDefaults, String id, Font font) {
|
||||
FontValue fontValue = javaDefaults.getFont(id);
|
||||
assertEquals(font, fontValue.getRawValue());
|
||||
}
|
||||
|
||||
private void assertIndirectColor(GThemeValueMap javaDefaults, String id, String indirectId) {
|
||||
ColorValue colorValue = javaDefaults.getColor(id);
|
||||
assertEquals(indirectId, colorValue.getReferenceId());
|
||||
}
|
||||
|
||||
private void assertIndirectFont(GThemeValueMap javaDefaults, String id, String indirectId) {
|
||||
FontValue fontValue = javaDefaults.getFont(id);
|
||||
assertEquals(indirectId, fontValue.getReferenceId());
|
||||
}
|
||||
|
||||
private void assertDirectIcon(GThemeValueMap javaDefaults, String id, Icon icon) {
|
||||
IconValue iconValue = javaDefaults.getIcon(id);
|
||||
assertEquals(icon, iconValue.getRawValue());
|
||||
}
|
||||
|
||||
private String findPaletteColor(GThemeValueMap javaDefaults, Color color) {
|
||||
for (ColorValue colorValue : javaDefaults.getColors()) {
|
||||
if (colorValue.getId().contains("palette.color") &&
|
||||
colorValue.getRawValue().equals(color)) {
|
||||
return colorValue.getId();
|
||||
}
|
||||
}
|
||||
fail("Could not find pallete color for " + color);
|
||||
return null;
|
||||
}
|
||||
|
||||
private UIDefaults createDefaults() {
|
||||
// populate defaults with standard laf group values, to avoid warning messages complaining
|
||||
// about them being undefined
|
||||
UIDefaults uiDefaults = new UIDefaults();
|
||||
uiDefaults.put("control", Color.BLACK); // for laf.group.control.color.bg
|
||||
uiDefaults.put("controlText", Color.BLACK); // for laf.group.control.color.fg
|
||||
uiDefaults.put("controlShadow", Color.BLACK); // for laf.group.control.color.border
|
||||
uiDefaults.put("window", Color.BLACK); // for laf.group.view.color.bg
|
||||
uiDefaults.put("windowText", Color.BLACK); // for laf.group.view.color.fg
|
||||
uiDefaults.put("textHighlight", Color.BLACK); // for laf.group.view.color.bg.selected and laf.group.text.color.bg.selected
|
||||
uiDefaults.put("textHighlightText", Color.BLACK); // for laf.group.view.color.fg.selected and laf.group.text.color.fg.selected
|
||||
|
||||
uiDefaults.put("textText", Color.BLACK); // for laf.group.text.color.fg
|
||||
uiDefaults.put("text", Color.BLACK); // for laf.group.text.color.bg
|
||||
uiDefaults.put("textInactiveText", Color.BLACK); // for laf.group.text.color.fg.disabled
|
||||
uiDefaults.put("info", Color.BLACK); // for laf.group.tooltip.color.bg
|
||||
uiDefaults.put("infoText", Color.BLACK); // for laf.group.tooltip.color.fg
|
||||
|
||||
uiDefaults.put("Panel.font", FONT); // for laf.group.control.font
|
||||
uiDefaults.put("TextField.font", FONT); // for laf.group.text.font
|
||||
uiDefaults.put("Table.font", FONT); // for laf.group.view.font
|
||||
uiDefaults.put("Menu.font", FONT); // for laf.group.menu.font
|
||||
|
||||
return uiDefaults;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue