mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-06-02 21:57:06 +08:00
GP-1981 - Checkpoint - Help System Fixes; fixed loading order bug
This commit is contained in:
@@ -37,6 +37,11 @@ color.bg.markerservice = color.bg
|
|||||||
color.bg.search.highlight = rgb(255,255,200)
|
color.bg.search.highlight = rgb(255,255,200)
|
||||||
color.bg.search.current-line.highlight = yellow
|
color.bg.search.current-line.highlight = yellow
|
||||||
|
|
||||||
|
color.bg.tree.renderer.icon.fill = #9F9FFF
|
||||||
|
color.bg.tree.renderer.icon.line = #8282FF
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[Dark Defaults]
|
[Dark Defaults]
|
||||||
|
|
||||||
color.bg = rgb(40, 42, 46) // TODO this should be in a more generic module
|
color.bg = rgb(40, 42, 46) // TODO this should be in a more generic module
|
||||||
|
|||||||
+9
-4
@@ -19,10 +19,15 @@ import java.awt.*;
|
|||||||
|
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
|
|
||||||
|
import docking.theme.GColor;
|
||||||
|
import docking.theme.GThemeDefaults.Colors.Palette;
|
||||||
|
|
||||||
class BackgroundIcon implements Icon {
|
class BackgroundIcon implements Icon {
|
||||||
|
|
||||||
private static Color VERSION_ICON_COLOR_DARK = new Color(0x82, 0x82, 0xff);
|
private static Color VERSION_ICON_COLOR_LINE = new GColor("color.bg.tree.renderer.icon.line");
|
||||||
private static Color VERSION_ICON_COLOR_LIGHT = new Color(0x9f, 0x9f, 0xff);
|
private static Color VERSION_ICON_COLOR_LIGHT = new GColor("color.bg.tree.renderer.icon.fill");
|
||||||
|
|
||||||
|
private static Color ALPHA = Palette.NO_COLOR;
|
||||||
|
|
||||||
private int width;
|
private int width;
|
||||||
private int height;
|
private int height;
|
||||||
@@ -49,14 +54,14 @@ class BackgroundIcon implements Icon {
|
|||||||
if (isVersioned) {
|
if (isVersioned) {
|
||||||
g.setColor(VERSION_ICON_COLOR_LIGHT);
|
g.setColor(VERSION_ICON_COLOR_LIGHT);
|
||||||
g.fillRect(x + 1, y + 1, width - 2, height - 2);
|
g.fillRect(x + 1, y + 1, width - 2, height - 2);
|
||||||
g.setColor(VERSION_ICON_COLOR_DARK);
|
g.setColor(VERSION_ICON_COLOR_LINE);
|
||||||
g.drawLine(x + 1, y, x + width - 2, y);
|
g.drawLine(x + 1, y, x + width - 2, y);
|
||||||
g.drawLine(x + width - 1, y + 1, x + width - 1, y + height - 2);
|
g.drawLine(x + width - 1, y + 1, x + width - 1, y + height - 2);
|
||||||
g.drawLine(x + 1, y + height - 1, x + width - 2, y + height - 1);
|
g.drawLine(x + 1, y + height - 1, x + width - 2, y + height - 1);
|
||||||
g.drawLine(x, y + 1, x, y + height - 2);
|
g.drawLine(x, y + 1, x, y + height - 2);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
g.setColor(c.getBackground());
|
g.setColor(ALPHA);
|
||||||
g.fillRect(x, y, width, height);
|
g.fillRect(x, y, width, height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -335,7 +335,7 @@ public class DataTypeArchiveGTree extends GTree {
|
|||||||
// work around an issue on some platforms where the label is painting a color that
|
// work around an issue on some platforms where the label is painting a color that
|
||||||
// does not match the tree
|
// does not match the tree
|
||||||
label.setBackground(
|
label.setBackground(
|
||||||
isSelected ? getBackgroundSelectionColor() : tree.getBackground());
|
isSelected ? getBackgroundSelectionColor() : getBackgroundNonSelectionColor());
|
||||||
}
|
}
|
||||||
|
|
||||||
MultiIcon multiIcon = new MultiIcon(
|
MultiIcon multiIcon = new MultiIcon(
|
||||||
@@ -362,7 +362,6 @@ public class DataTypeArchiveGTree extends GTree {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setIcon(multiIcon);
|
setIcon(multiIcon);
|
||||||
|
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,23 +15,15 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.gui;
|
package ghidra.app.plugin.gui;
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import docking.action.builder.ActionBuilder;
|
import docking.action.builder.ActionBuilder;
|
||||||
import docking.options.editor.StringWithChoicesEditor;
|
import docking.theme.gui.ThemeDialog;
|
||||||
import docking.theme.GTheme;
|
|
||||||
import docking.theme.Gui;
|
|
||||||
import docking.theme.gui.GThemeDialog;
|
|
||||||
import docking.tool.ToolConstants;
|
|
||||||
import ghidra.app.CorePluginPackage;
|
import ghidra.app.CorePluginPackage;
|
||||||
import ghidra.app.plugin.PluginCategoryNames;
|
import ghidra.app.plugin.PluginCategoryNames;
|
||||||
import ghidra.framework.main.FrontEndOnly;
|
import ghidra.framework.main.FrontEndOnly;
|
||||||
import ghidra.framework.main.FrontEndTool;
|
import ghidra.framework.main.FrontEndTool;
|
||||||
import ghidra.framework.options.*;
|
|
||||||
import ghidra.framework.plugintool.*;
|
import ghidra.framework.plugintool.*;
|
||||||
import ghidra.framework.plugintool.util.PluginStatus;
|
import ghidra.framework.plugintool.util.PluginStatus;
|
||||||
import ghidra.util.*;
|
import ghidra.util.SystemUtilities;
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
@PluginInfo(
|
@PluginInfo(
|
||||||
@@ -43,93 +35,26 @@ import ghidra.util.*;
|
|||||||
"This plugin is available only in the Ghidra Project Window."
|
"This plugin is available only in the Ghidra Project Window."
|
||||||
)
|
)
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
public class ThemeManagerPlugin extends Plugin implements FrontEndOnly, OptionsChangeListener {
|
public class ThemeManagerPlugin extends Plugin implements FrontEndOnly {
|
||||||
|
|
||||||
public final static String THEME_OPTIONS_NAME = "Theme";
|
|
||||||
private final static String OPTIONS_TITLE = ToolConstants.TOOL_OPTIONS;
|
|
||||||
|
|
||||||
private boolean issuedRestartNotification;
|
|
||||||
// private static boolean issuedPreferredDarkThemeLafNotification;
|
|
||||||
|
|
||||||
public ThemeManagerPlugin(PluginTool tool) {
|
public ThemeManagerPlugin(PluginTool tool) {
|
||||||
super(tool);
|
super(tool);
|
||||||
|
|
||||||
SystemUtilities.assertTrue(tool instanceof FrontEndTool,
|
SystemUtilities.assertTrue(tool instanceof FrontEndTool,
|
||||||
"Plugin added to the wrong type of tool");
|
"Plugin added to the wrong type of tool");
|
||||||
initThemeOptions();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void init() {
|
protected void init() {
|
||||||
|
|
||||||
new ActionBuilder("Show Properties", getName()).menuPath("Edit", "Theme Properties")
|
new ActionBuilder("", getName()).menuPath("Edit", "Theme")
|
||||||
.onAction(e -> showThemeProperties())
|
.onAction(e -> showThemeProperties())
|
||||||
.buildAndInstall(tool);
|
.buildAndInstall(tool);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showThemeProperties() {
|
private void showThemeProperties() {
|
||||||
GThemeDialog dialog = new GThemeDialog();
|
ThemeDialog.editTheme();
|
||||||
tool.showDialog(dialog);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initThemeOptions() {
|
|
||||||
|
|
||||||
ToolOptions opt = tool.getOptions(OPTIONS_TITLE);
|
|
||||||
|
|
||||||
GTheme activeTheme = Gui.getActiveTheme();
|
|
||||||
Set<GTheme> themes = Gui.getSupportedThemes();
|
|
||||||
List<String> themeNames =
|
|
||||||
themes.stream().map(t -> t.getName()).collect(Collectors.toList());
|
|
||||||
Collections.sort(themeNames);
|
|
||||||
|
|
||||||
opt.registerOption(THEME_OPTIONS_NAME, OptionType.STRING_TYPE, activeTheme.getName(),
|
|
||||||
new HelpLocation(ToolConstants.TOOL_HELP_TOPIC, "Look_And_Feel"),
|
|
||||||
"Set the look and feel for Ghidra. After you change the " +
|
|
||||||
"look and feel, you will have to restart Ghidra to see the effect.",
|
|
||||||
new StringWithChoicesEditor(themeNames));
|
|
||||||
|
|
||||||
opt.addOptionsChangeListener(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
|
|
||||||
Object newValue) {
|
|
||||||
|
|
||||||
if (optionName.equals(THEME_OPTIONS_NAME)) {
|
|
||||||
String newThemeName = (String) newValue;
|
|
||||||
if (!newThemeName.equals(Gui.getActiveTheme().getName())) {
|
|
||||||
issueRestartNeededMessage();
|
|
||||||
}
|
|
||||||
|
|
||||||
saveLookAndFeel((String) newValue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveLookAndFeel(String themeName) {
|
|
||||||
Set<GTheme> allThemes = Gui.getAllThemes();
|
|
||||||
for (GTheme theme : allThemes) {
|
|
||||||
if (theme.getName().equals(themeName)) {
|
|
||||||
Gui.saveThemeToPreferneces(theme);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void issueRestartNeededMessage() {
|
|
||||||
if (issuedRestartNotification) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
issuedRestartNotification = true;
|
|
||||||
Msg.showInfo(getClass(), null, "Look And Feel Updated",
|
|
||||||
"The new Look and Feel will take effect \nafter you exit and restart Ghidra.");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void dispose() {
|
|
||||||
ToolOptions opt = tool.getOptions(OPTIONS_TITLE);
|
|
||||||
opt.removeOptionsChangeListener(this);
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
+11
-10
@@ -26,6 +26,7 @@ import org.junit.*;
|
|||||||
|
|
||||||
import docking.ActionContext;
|
import docking.ActionContext;
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
|
import docking.theme.GThemeDefaults.Colors.Palette;
|
||||||
import edu.uci.ics.jung.graph.Graph;
|
import edu.uci.ics.jung.graph.Graph;
|
||||||
import ghidra.app.plugin.core.clear.ClearPlugin;
|
import ghidra.app.plugin.core.clear.ClearPlugin;
|
||||||
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
|
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
|
||||||
@@ -485,7 +486,7 @@ public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
|
|||||||
FGVertex v2 = vertex("01002d0f");
|
FGVertex v2 = vertex("01002d0f");
|
||||||
|
|
||||||
// color just one of the vertices
|
// color just one of the vertices
|
||||||
Color newColor = Color.RED;
|
Color newColor = Palette.RED;
|
||||||
color(v1, newColor);
|
color(v1, newColor);
|
||||||
|
|
||||||
GroupedFunctionGraphVertex group = group("A", v1, v2);
|
GroupedFunctionGraphVertex group = group("A", v1, v2);
|
||||||
@@ -527,7 +528,7 @@ public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
|
|||||||
FGVertex v2 = vertex("01002d0f");
|
FGVertex v2 = vertex("01002d0f");
|
||||||
|
|
||||||
// color just one of the vertices
|
// color just one of the vertices
|
||||||
Color newColor = Color.RED;
|
Color newColor = Palette.RED;
|
||||||
color(v1, newColor);
|
color(v1, newColor);
|
||||||
color(v2, newColor);
|
color(v2, newColor);
|
||||||
|
|
||||||
@@ -564,7 +565,7 @@ public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
|
|||||||
//
|
//
|
||||||
// Change the group color
|
// Change the group color
|
||||||
//
|
//
|
||||||
Color newGroupColor = Color.CYAN;
|
Color newGroupColor = Palette.CYAN;
|
||||||
color(group, newGroupColor);
|
color(group, newGroupColor);
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -591,7 +592,7 @@ public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
|
|||||||
FGVertex v2 = vertex("01002d0f");
|
FGVertex v2 = vertex("01002d0f");
|
||||||
|
|
||||||
// color just one of the vertices
|
// color just one of the vertices
|
||||||
Color newColor = Color.RED;
|
Color newColor = Palette.RED;
|
||||||
color(v1, newColor);
|
color(v1, newColor);
|
||||||
|
|
||||||
GroupedFunctionGraphVertex group = group("A", v1, v2);
|
GroupedFunctionGraphVertex group = group("A", v1, v2);
|
||||||
@@ -599,7 +600,7 @@ public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
|
|||||||
//
|
//
|
||||||
// Change the group color
|
// Change the group color
|
||||||
//
|
//
|
||||||
Color newGroupColor = Color.CYAN;
|
Color newGroupColor = Palette.CYAN;
|
||||||
color(group, newGroupColor);
|
color(group, newGroupColor);
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -625,7 +626,7 @@ public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
|
|||||||
FGVertex v2 = vertex("01002d0f");
|
FGVertex v2 = vertex("01002d0f");
|
||||||
|
|
||||||
// color just one of the vertices
|
// color just one of the vertices
|
||||||
Color newColor = Color.RED;
|
Color newColor = Palette.RED;
|
||||||
color(v1, newColor);
|
color(v1, newColor);
|
||||||
color(v2, newColor);
|
color(v2, newColor);
|
||||||
|
|
||||||
@@ -634,7 +635,7 @@ public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
|
|||||||
//
|
//
|
||||||
// Change the group color
|
// Change the group color
|
||||||
//
|
//
|
||||||
Color newGroupColor = Color.CYAN;
|
Color newGroupColor = Palette.CYAN;
|
||||||
color(group, newGroupColor);
|
color(group, newGroupColor);
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -663,7 +664,7 @@ public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
|
|||||||
//
|
//
|
||||||
// Change the group color
|
// Change the group color
|
||||||
//
|
//
|
||||||
Color newGroupColor = Color.CYAN;
|
Color newGroupColor = Palette.CYAN;
|
||||||
color(group, newGroupColor);
|
color(group, newGroupColor);
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -738,7 +739,7 @@ public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
|
|||||||
//
|
//
|
||||||
// Color just one of the vertices
|
// Color just one of the vertices
|
||||||
//
|
//
|
||||||
Color newColor = Color.RED;
|
Color newColor = Palette.RED;
|
||||||
color(v1, newColor);
|
color(v1, newColor);
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -782,7 +783,7 @@ public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
|
|||||||
//
|
//
|
||||||
// Color just one of the vertices
|
// Color just one of the vertices
|
||||||
//
|
//
|
||||||
Color newColor = Color.RED;
|
Color newColor = Palette.RED;
|
||||||
color(v1, newColor);
|
color(v1, newColor);
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|||||||
+2
-1
@@ -32,6 +32,7 @@ import docking.ActionContext;
|
|||||||
import docking.ComponentProvider;
|
import docking.ComponentProvider;
|
||||||
import docking.action.DockingAction;
|
import docking.action.DockingAction;
|
||||||
import docking.dnd.GClipboard;
|
import docking.dnd.GClipboard;
|
||||||
|
import docking.theme.GThemeDefaults.Colors.Palette;
|
||||||
import edu.uci.ics.jung.algorithms.layout.Layout;
|
import edu.uci.ics.jung.algorithms.layout.Layout;
|
||||||
import edu.uci.ics.jung.visualization.VisualizationModel;
|
import edu.uci.ics.jung.visualization.VisualizationModel;
|
||||||
import edu.uci.ics.jung.visualization.VisualizationViewer;
|
import edu.uci.ics.jung.visualization.VisualizationViewer;
|
||||||
@@ -619,7 +620,7 @@ public class FunctionGraphPlugin1Test extends AbstractFunctionGraphTest {
|
|||||||
Color appliedBackgroundColor =
|
Color appliedBackgroundColor =
|
||||||
colorizingService.getBackgroundColor(focusedVertex.getVertexAddress());
|
colorizingService.getBackgroundColor(focusedVertex.getVertexAddress());
|
||||||
|
|
||||||
Color testColor = Color.RED;
|
Color testColor = Palette.RED;
|
||||||
assertTrue("Unexpected start color--must change the test!",
|
assertTrue("Unexpected start color--must change the test!",
|
||||||
!testColor.equals(appliedBackgroundColor));
|
!testColor.equals(appliedBackgroundColor));
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -15,8 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.functiongraph;
|
package ghidra.app.plugin.core.functiongraph;
|
||||||
|
|
||||||
import static ghidra.graph.viewer.GraphViewerUtils.getGraphScale;
|
import static ghidra.graph.viewer.GraphViewerUtils.*;
|
||||||
import static ghidra.graph.viewer.GraphViewerUtils.getPointInViewSpaceForVertex;
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
@@ -28,6 +27,7 @@ import javax.swing.JComponent;
|
|||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
|
import docking.theme.GThemeDefaults.Colors.Palette;
|
||||||
import edu.uci.ics.jung.graph.Graph;
|
import edu.uci.ics.jung.graph.Graph;
|
||||||
import generic.test.TestUtils;
|
import generic.test.TestUtils;
|
||||||
import ghidra.app.cmd.label.AddLabelCmd;
|
import ghidra.app.cmd.label.AddLabelCmd;
|
||||||
@@ -251,7 +251,7 @@ public class FunctionGraphPlugin2Test extends AbstractFunctionGraphTest {
|
|||||||
ListingPanel listingPanel =
|
ListingPanel listingPanel =
|
||||||
(ListingPanel) TestUtils.getInstanceField("listingPanel", panel);
|
(ListingPanel) TestUtils.getInstanceField("listingPanel", panel);
|
||||||
Color startBackgrond = listingPanel.getTextBackgroundColor();
|
Color startBackgrond = listingPanel.getTextBackgroundColor();
|
||||||
Color testColor = Color.RED;
|
Color testColor = Palette.RED;
|
||||||
assertTrue("Unexpected start color--must change the test!",
|
assertTrue("Unexpected start color--must change the test!",
|
||||||
!testColor.equals(startBackgrond));
|
!testColor.equals(startBackgrond));
|
||||||
|
|
||||||
@@ -277,7 +277,7 @@ public class FunctionGraphPlugin2Test extends AbstractFunctionGraphTest {
|
|||||||
Color appliedBackgroundColor =
|
Color appliedBackgroundColor =
|
||||||
colorizingService.getBackgroundColor(vertex.getVertexAddress());
|
colorizingService.getBackgroundColor(vertex.getVertexAddress());
|
||||||
|
|
||||||
Color testColor = Color.RED;
|
Color testColor = Palette.RED;
|
||||||
assertTrue("Unexpected start color--must change the test!",
|
assertTrue("Unexpected start color--must change the test!",
|
||||||
!testColor.equals(appliedBackgroundColor));
|
!testColor.equals(appliedBackgroundColor));
|
||||||
|
|
||||||
|
|||||||
-1000
File diff suppressed because it is too large
Load Diff
-980
File diff suppressed because it is too large
Load Diff
-841
File diff suppressed because it is too large
Load Diff
@@ -21,6 +21,7 @@ src/main/help/help/shared/tip.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (
|
|||||||
src/main/help/help/shared/undo.png||GHIDRA||||END|
|
src/main/help/help/shared/undo.png||GHIDRA||||END|
|
||||||
src/main/help/help/shared/warning.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
|
src/main/help/help/shared/warning.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
|
||||||
src/main/help/help/topics/PlacheholderTopic/Placeholder.htm||GHIDRA||||END|
|
src/main/help/help/topics/PlacheholderTopic/Placeholder.htm||GHIDRA||||END|
|
||||||
|
data/docking.palette.material.theme.properties||GHIDRA||||END|
|
||||||
data/docking.palette.theme.properties||GHIDRA||||END|
|
data/docking.palette.theme.properties||GHIDRA||||END|
|
||||||
data/docking.theme.properties||GHIDRA||||END|
|
data/docking.theme.properties||GHIDRA||||END|
|
||||||
src/main/java/docking/dnd/package.html||GHIDRA||reviewed||END|
|
src/main/java/docking/dnd/package.html||GHIDRA||reviewed||END|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// TODO using this now as a placeholder for a palette/swatch
|
||||||
|
|
||||||
|
[Defaults]
|
||||||
|
|
||||||
|
|
||||||
|
color.palette.material.primary = #6200EE
|
||||||
|
color.palette.material.secondary = #03DAC6
|
||||||
|
color.palette.material.secondary.variant = #018786
|
||||||
|
|
||||||
|
[Dark Defaults]
|
||||||
|
|
||||||
|
color.palette.material.primary = #BB86FC
|
||||||
|
color.palette.material.secondary = #03DAC6
|
||||||
|
color.palette.material.secondary.variant = #018786
|
||||||
@@ -8,6 +8,7 @@ color.palette.crimson = crimson
|
|||||||
color.palette.cyan = cyan
|
color.palette.cyan = cyan
|
||||||
color.palette.darkblue = DarkBlue
|
color.palette.darkblue = DarkBlue
|
||||||
color.palette.darkkhaki = DarkKhaki
|
color.palette.darkkhaki = DarkKhaki
|
||||||
|
color.palette.darkred = DarkRed
|
||||||
color.palette.dodgerblue = DodgerBlue
|
color.palette.dodgerblue = DodgerBlue
|
||||||
color.palette.gold = gold
|
color.palette.gold = gold
|
||||||
color.palette.gray = gray
|
color.palette.gray = gray
|
||||||
|
|||||||
@@ -0,0 +1,118 @@
|
|||||||
|
/* ###
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
import javax.swing.JButton;
|
||||||
|
|
||||||
|
import docking.help.HelpDescriptor;
|
||||||
|
import docking.help.HelpService;
|
||||||
|
import ghidra.util.HelpLocation;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
|
public class DefaultHelpService implements HelpService {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showHelp(Object helpObj, boolean infoOnly, Component parent) {
|
||||||
|
if (infoOnly) {
|
||||||
|
displayHelpInfo(helpObj);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showHelp(java.net.URL url) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showHelp(HelpLocation location) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void excludeFromHelp(Object helpObject) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isExcludedFromHelp(Object helpObject) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearHelp(Object helpObject) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerHelp(Object helpObj, HelpLocation helpLocation) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public HelpLocation getHelpLocation(Object object) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean helpExists() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reload() {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
private void displayHelpInfo(Object helpObj) {
|
||||||
|
String msg = getHelpInfo(helpObj);
|
||||||
|
Msg.showInfo(this, null, "Help Info", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getHelpInfo(Object helpObj) {
|
||||||
|
if (helpObj == null) {
|
||||||
|
return "Help Object is null";
|
||||||
|
}
|
||||||
|
StringBuilder buffy = new StringBuilder();
|
||||||
|
buffy.append("HELP OBJECT: " + helpObj.getClass().getName());
|
||||||
|
buffy.append("\n");
|
||||||
|
if (helpObj instanceof HelpDescriptor) {
|
||||||
|
HelpDescriptor helpDescriptor = (HelpDescriptor) helpObj;
|
||||||
|
buffy.append(helpDescriptor.getHelpInfo());
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (helpObj instanceof JButton) {
|
||||||
|
JButton button = (JButton) helpObj;
|
||||||
|
buffy.append(" BUTTON: " + button.getText());
|
||||||
|
buffy.append("\n");
|
||||||
|
Component c = button;
|
||||||
|
while (c != null && !(c instanceof Window)) {
|
||||||
|
c = c.getParent();
|
||||||
|
}
|
||||||
|
if (c instanceof Dialog) {
|
||||||
|
buffy.append(" DIALOG: " + ((Dialog) c).getTitle());
|
||||||
|
buffy.append("\n");
|
||||||
|
}
|
||||||
|
if (c instanceof Frame) {
|
||||||
|
buffy.append(" FRAME: " + ((Frame) c).getTitle());
|
||||||
|
buffy.append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buffy.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-4
@@ -16,7 +16,6 @@
|
|||||||
package docking.action;
|
package docking.action;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.KeyEvent;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -28,15 +27,16 @@ import javax.swing.tree.TreePath;
|
|||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import docking.*;
|
import docking.ActionContext;
|
||||||
|
import docking.DockingWindowManager;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
import ghidra.util.ReservedKeyBindings;
|
||||||
|
|
||||||
public class ComponentThemeInspectorAction extends DockingAction {
|
public class ComponentThemeInspectorAction extends DockingAction {
|
||||||
|
|
||||||
public ComponentThemeInspectorAction() {
|
public ComponentThemeInspectorAction() {
|
||||||
super("Component Theme Inspector", DockingWindowManager.DOCKING_WINDOWS_OWNER, false);
|
super("Component Theme Inspector", DockingWindowManager.DOCKING_WINDOWS_OWNER, false);
|
||||||
createReservedKeyBinding(
|
createReservedKeyBinding(ReservedKeyBindings.COMPONENT_THEME_INFO_KEY);
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_F9, DockingUtils.CONTROL_KEY_MODIFIER_MASK));
|
|
||||||
|
|
||||||
// System action; no help needed
|
// System action; no help needed
|
||||||
DockingWindowManager.getHelpService().excludeFromHelp(this);
|
DockingWindowManager.getHelpService().excludeFromHelp(this);
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ public class ShowFocusInfoAction extends DockingAction {
|
|||||||
Object mouseOverObject = DockingWindowManager.getMouseOverObject();
|
Object mouseOverObject = DockingWindowManager.getMouseOverObject();
|
||||||
if (mouseOverObject instanceof Component) {
|
if (mouseOverObject instanceof Component) {
|
||||||
log.info("Mouse-over Object: " + printComp((Component) mouseOverObject));
|
log.info("Mouse-over Object: " + printComp((Component) mouseOverObject));
|
||||||
|
log.info("Focusable?: " + ((Component) mouseOverObject).isFocusable());
|
||||||
}
|
}
|
||||||
log.info("");
|
log.info("");
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -28,11 +28,9 @@ import java.util.Map.Entry;
|
|||||||
import javax.help.*;
|
import javax.help.*;
|
||||||
import javax.help.Map.ID;
|
import javax.help.Map.ID;
|
||||||
import javax.swing.JButton;
|
import javax.swing.JButton;
|
||||||
import javax.swing.UIManager;
|
|
||||||
|
|
||||||
import docking.ComponentProvider;
|
import docking.ComponentProvider;
|
||||||
import docking.action.DockingActionIf;
|
import docking.action.DockingActionIf;
|
||||||
import docking.theme.GColor;
|
|
||||||
import generic.concurrent.GThreadPool;
|
import generic.concurrent.GThreadPool;
|
||||||
import generic.util.WindowUtilities;
|
import generic.util.WindowUtilities;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
@@ -89,8 +87,6 @@ public class HelpManager implements HelpService {
|
|||||||
mainHB = mainHS.createHelpBroker();
|
mainHB = mainHS.createHelpBroker();
|
||||||
mainHS.setTitle(GHIDRA_HELP_TITLE);
|
mainHS.setTitle(GHIDRA_HELP_TITLE);
|
||||||
|
|
||||||
setColorResources();
|
|
||||||
|
|
||||||
isValidHelp = isValidHelp();
|
isValidHelp = isValidHelp();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,6 +192,18 @@ public class HelpManager implements HelpService {
|
|||||||
return mainHS;
|
return mainHS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reload() {
|
||||||
|
|
||||||
|
if (!(mainHB instanceof GHelpBroker)) {
|
||||||
|
// not our broker installed; can't force a reload
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GHelpBroker gHelpBroker = (GHelpBroker) mainHB;
|
||||||
|
gHelpBroker.reload();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void showHelp(URL url) {
|
public void showHelp(URL url) {
|
||||||
if (!isValidHelp) {
|
if (!isValidHelp) {
|
||||||
@@ -693,15 +701,6 @@ public class HelpManager implements HelpService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the color resources on the JEditorPane for selection so that
|
|
||||||
* you can see the highlights when you do a search in the JavaHelp.
|
|
||||||
*/
|
|
||||||
private void setColorResources() {
|
|
||||||
UIManager.put("EditorPane.selectionBackground", new GColor("color.bg.selection.help"));
|
|
||||||
UIManager.put("EditorPane.selectionForeground", UIManager.get("EditorPane.foreground"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void displayHelpInfo(Object helpObj, HelpLocation loc, Window parent) {
|
private void displayHelpInfo(Object helpObj, HelpLocation loc, Window parent) {
|
||||||
String msg = getHelpInfo(helpObj, loc);
|
String msg = getHelpInfo(helpObj, loc);
|
||||||
Msg.showInfo(this, parent, "Help Info", msg);
|
Msg.showInfo(this, parent, "Help Info", msg);
|
||||||
|
|||||||
@@ -0,0 +1,121 @@
|
|||||||
|
/* ###
|
||||||
|
* 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.help;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <code>HelpService</code> defines a service for displaying Help content by an ID or URL.
|
||||||
|
*/
|
||||||
|
public interface HelpService {
|
||||||
|
|
||||||
|
public static final String DUMMY_HELP_SET_NAME = "Dummy_HelpSet.hs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the Help content identified by the help object.
|
||||||
|
*
|
||||||
|
* @param helpObject the object to which help was previously registered
|
||||||
|
* @param infoOnly display {@link HelpLocation} information only, not the help UI
|
||||||
|
* @param parent requesting component
|
||||||
|
*
|
||||||
|
* @see #registerHelp(Object, HelpLocation)
|
||||||
|
*/
|
||||||
|
public void showHelp(Object helpObject, boolean infoOnly, Component parent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the help page for the given URL. This is a specialty method for displaying
|
||||||
|
* help when a specific file is desired, like an introduction page. Showing help for
|
||||||
|
* objects within the system is accomplished by calling
|
||||||
|
* {@link #showHelp(Object, boolean, Component)}.
|
||||||
|
*
|
||||||
|
* @param url the URL to display
|
||||||
|
* @see #showHelp(Object, boolean, Component)
|
||||||
|
*/
|
||||||
|
public void showHelp(URL url);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the help page for the given help location.
|
||||||
|
*
|
||||||
|
* @param location the location to display.
|
||||||
|
* @see #showHelp(Object, boolean, Component)
|
||||||
|
*/
|
||||||
|
public void showHelp(HelpLocation location);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signals to the help system to ignore the given object when searching for and validating
|
||||||
|
* help. Once this method has been called, no help can be registered for the given object.
|
||||||
|
*
|
||||||
|
* @param helpObject the object to exclude from the help system.
|
||||||
|
*/
|
||||||
|
public void excludeFromHelp(Object helpObject);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the given object is meant to be ignored by the help system
|
||||||
|
*
|
||||||
|
* @param helpObject the object to check
|
||||||
|
* @return true if ignored
|
||||||
|
* @see #excludeFromHelp(Object)
|
||||||
|
*/
|
||||||
|
public boolean isExcludedFromHelp(Object helpObject);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register help for a specific object.
|
||||||
|
*
|
||||||
|
* <P>Do not call this method will a <code>null</code> help location. Instead, to signal that
|
||||||
|
* an item has no help, call {@link #excludeFromHelp(Object)}.
|
||||||
|
*
|
||||||
|
* @param helpObject the object to associate the specified help location with
|
||||||
|
* @param helpLocation help content location
|
||||||
|
*/
|
||||||
|
public void registerHelp(Object helpObject, HelpLocation helpLocation);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes this object from the help system. This method is useful, for example,
|
||||||
|
* when a single Java {@link Component} will have different help locations
|
||||||
|
* assigned over its lifecycle.
|
||||||
|
*
|
||||||
|
* @param helpObject the object for which to clear help
|
||||||
|
*/
|
||||||
|
public void clearHelp(Object helpObject);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the registered (via {@link #registerHelp(Object, HelpLocation)} help
|
||||||
|
* location for the given object; null if there is no registered
|
||||||
|
* help.
|
||||||
|
*
|
||||||
|
* @param object The object for which to find a registered HelpLocation.
|
||||||
|
* @return the registered HelpLocation
|
||||||
|
* @see #registerHelp(Object, HelpLocation)
|
||||||
|
*/
|
||||||
|
public HelpLocation getHelpLocation(Object object);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the help system has been initialized properly; false if help does not
|
||||||
|
* exist or is not working.
|
||||||
|
*
|
||||||
|
* @return true if the help system has found the applications help content and has finished
|
||||||
|
* initializing
|
||||||
|
*/
|
||||||
|
public boolean helpExists();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a major system even happens, such as changing the system theme.
|
||||||
|
*/
|
||||||
|
public void reload();
|
||||||
|
}
|
||||||
@@ -18,6 +18,6 @@ package docking.theme;
|
|||||||
public class DefaultTheme extends DiscoverableGTheme {
|
public class DefaultTheme extends DiscoverableGTheme {
|
||||||
|
|
||||||
public DefaultTheme() {
|
public DefaultTheme() {
|
||||||
super("Default", LookAndFeelType.SYSTEM);
|
super("Default", LafType.SYSTEM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,12 +20,8 @@ import ghidra.util.classfinder.ExtensionPoint;
|
|||||||
public abstract class DiscoverableGTheme extends GTheme implements ExtensionPoint {
|
public abstract class DiscoverableGTheme extends GTheme implements ExtensionPoint {
|
||||||
static final String CLASS_PREFIX = "Class:";
|
static final String CLASS_PREFIX = "Class:";
|
||||||
|
|
||||||
protected DiscoverableGTheme(String name, LookAndFeelType lookAndFeel) {
|
protected DiscoverableGTheme(String name, LafType lookAndFeel) {
|
||||||
super(name, lookAndFeel, false);
|
super(name, lookAndFeel);
|
||||||
}
|
|
||||||
|
|
||||||
protected DiscoverableGTheme(String name, LookAndFeelType lookAndFeel, boolean isDark) {
|
|
||||||
super(name, lookAndFeel, isDark);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -15,8 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
package docking.theme;
|
package docking.theme;
|
||||||
|
|
||||||
import java.io.File;
|
import java.awt.Color;
|
||||||
import java.io.IOException;
|
import java.awt.Font;
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ghidra.util.WebColors;
|
||||||
|
|
||||||
public class FileGTheme extends GTheme {
|
public class FileGTheme extends GTheme {
|
||||||
public static final String FILE_PREFIX = "File:";
|
public static final String FILE_PREFIX = "File:";
|
||||||
@@ -26,8 +31,13 @@ public class FileGTheme extends GTheme {
|
|||||||
this(file, new ThemeReader(file));
|
this(file, new ThemeReader(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FileGTheme(File file, String name, LafType laf) {
|
||||||
|
super(name, laf);
|
||||||
|
this.file = file;
|
||||||
|
}
|
||||||
|
|
||||||
FileGTheme(File file, ThemeReader reader) {
|
FileGTheme(File file, ThemeReader reader) {
|
||||||
super(reader.getThemeName(), reader.getLookAndFeelType(), reader.isDark());
|
super(reader.getThemeName(), reader.getLookAndFeelType());
|
||||||
this.file = file;
|
this.file = file;
|
||||||
reader.loadValues(this);
|
reader.loadValues(this);
|
||||||
}
|
}
|
||||||
@@ -37,4 +47,93 @@ public class FileGTheme extends GTheme {
|
|||||||
return FILE_PREFIX + file.getAbsolutePath();
|
return FILE_PREFIX + file.getAbsolutePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean canSave() {
|
||||||
|
return file.canWrite();
|
||||||
|
}
|
||||||
|
|
||||||
|
public File getFile() {
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void save() throws IOException {
|
||||||
|
try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
|
||||||
|
List<ColorValue> colors = getColors();
|
||||||
|
Collections.sort(colors);
|
||||||
|
|
||||||
|
List<FontValue> fonts = getFonts();
|
||||||
|
Collections.sort(fonts);
|
||||||
|
|
||||||
|
List<IconValue> icons = getIcons();
|
||||||
|
Collections.sort(icons);
|
||||||
|
|
||||||
|
writer.write(THEME_NAME_KEY + " = " + getName());
|
||||||
|
writer.newLine();
|
||||||
|
|
||||||
|
writer.write(THEME_LOOK_AND_FEEL_KEY + " = " + getLookAndFeelType().getName());
|
||||||
|
writer.newLine();
|
||||||
|
|
||||||
|
for (ColorValue colorValue : colors) {
|
||||||
|
String outputId = colorValue.toExternalId(colorValue.getId());
|
||||||
|
writer.write(outputId + " = " + getValueOutput(colorValue));
|
||||||
|
writer.newLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (FontValue fontValue : fonts) {
|
||||||
|
String outputId = fontValue.toExternalId(fontValue.getId());
|
||||||
|
writer.write(outputId + " = " + getValueOutput(fontValue));
|
||||||
|
writer.newLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (IconValue iconValue : icons) {
|
||||||
|
String outputId = iconValue.toExternalId(iconValue.getId());
|
||||||
|
writer.write(outputId + " = " + getValueOutput(iconValue));
|
||||||
|
writer.newLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getValueOutput(ColorValue colorValue) {
|
||||||
|
if (colorValue.getReferenceId() != null) {
|
||||||
|
return colorValue.toExternalId(colorValue.getReferenceId());
|
||||||
|
}
|
||||||
|
Color color = colorValue.getRawValue();
|
||||||
|
String outputString = WebColors.toString(color, false);
|
||||||
|
String colorName = WebColors.toWebColorName(color);
|
||||||
|
if (colorName != null) {
|
||||||
|
outputString += " // " + colorName;
|
||||||
|
}
|
||||||
|
return outputString;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getValueOutput(IconValue iconValue) {
|
||||||
|
if (iconValue.getReferenceId() != null) {
|
||||||
|
return iconValue.toExternalId(iconValue.getReferenceId());
|
||||||
|
}
|
||||||
|
return iconValue.getRawValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getValueOutput(FontValue fontValue) {
|
||||||
|
if (fontValue.getReferenceId() != null) {
|
||||||
|
return fontValue.toExternalId(fontValue.getReferenceId());
|
||||||
|
}
|
||||||
|
Font font = fontValue.getRawValue();
|
||||||
|
return String.format("%s-%s-%s", font.getName(), getStyleString(font), font.getSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getStyleString(Font font) {
|
||||||
|
boolean bold = font.isBold();
|
||||||
|
boolean italic = font.isItalic();
|
||||||
|
if (bold && italic) {
|
||||||
|
return "BOLDITALIC";
|
||||||
|
}
|
||||||
|
if (bold) {
|
||||||
|
return "BOLD";
|
||||||
|
}
|
||||||
|
if (italic) {
|
||||||
|
return "ITALIC";
|
||||||
|
}
|
||||||
|
return "PLAIN";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,26 +17,25 @@ package docking.theme;
|
|||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
import java.io.*;
|
import java.io.File;
|
||||||
import java.util.*;
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
import ghidra.util.WebColors;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class to store all the configurable appearance properties (Colors, Fonts, Icons, Look and Feel)
|
* Class to store all the configurable appearance properties (Colors, Fonts, Icons, Look and Feel)
|
||||||
* in an application.
|
* in an application.
|
||||||
*/
|
*/
|
||||||
public class GTheme extends GThemeValueMap {
|
public class GTheme extends GThemeValueMap {
|
||||||
|
public static String FILE_EXTENSION = ".theme";
|
||||||
|
|
||||||
static final String THEME_NAME_KEY = "name";
|
static final String THEME_NAME_KEY = "name";
|
||||||
static final String THEME_LOOK_AND_FEEL_KEY = "lookAndFeel";
|
static final String THEME_LOOK_AND_FEEL_KEY = "lookAndFeel";
|
||||||
static final String THEME_IS_DARK_KEY = "dark";
|
|
||||||
|
|
||||||
private final String name;
|
private final String name;
|
||||||
private final LookAndFeelType lookAndFeel;
|
private final LafType lookAndFeel;
|
||||||
private final boolean isDark;
|
|
||||||
|
|
||||||
public GTheme(String name) {
|
public GTheme(String name) {
|
||||||
this(name, LookAndFeelType.SYSTEM, false);
|
this(name, LafType.SYSTEM);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,13 +43,10 @@ public class GTheme extends GThemeValueMap {
|
|||||||
* Creates a new empty GTheme with the given name
|
* Creates a new empty GTheme with the given name
|
||||||
* @param name the name for the new GTheme
|
* @param name the name for the new GTheme
|
||||||
* @param lookAndFeel the look and feel type used by this theme
|
* @param lookAndFeel the look and feel type used by this theme
|
||||||
* @param isDark true if this theme uses dark backgrounds instead of the standard
|
|
||||||
* light backgrounds
|
|
||||||
*/
|
*/
|
||||||
protected GTheme(String name, LookAndFeelType lookAndFeel, boolean isDark) {
|
protected GTheme(String name, LafType lookAndFeel) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.lookAndFeel = lookAndFeel;
|
this.lookAndFeel = lookAndFeel;
|
||||||
this.isDark = isDark;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,7 +61,7 @@ public class GTheme extends GThemeValueMap {
|
|||||||
* Returns the name of the LookAndFeel associated with this GTheme
|
* Returns the name of the LookAndFeel associated with this GTheme
|
||||||
* @return the name of the LookAndFeel associated with this GTheme
|
* @return the name of the LookAndFeel associated with this GTheme
|
||||||
*/
|
*/
|
||||||
public LookAndFeelType getLookAndFeelType() {
|
public LafType getLookAndFeelType() {
|
||||||
return lookAndFeel;
|
return lookAndFeel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +70,7 @@ public class GTheme extends GThemeValueMap {
|
|||||||
* @return true if this theme should use dark defaults
|
* @return true if this theme should use dark defaults
|
||||||
*/
|
*/
|
||||||
public boolean isDark() {
|
public boolean isDark() {
|
||||||
return isDark;
|
return lookAndFeel.isDark();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -161,123 +157,21 @@ public class GTheme extends GThemeValueMap {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
GTheme other = (GTheme) obj;
|
GTheme other = (GTheme) obj;
|
||||||
return Objects.equals(name, other.name) && Objects.equals(lookAndFeel, other.lookAndFeel) &&
|
return Objects.equals(name, other.name) && Objects.equals(lookAndFeel, other.lookAndFeel);
|
||||||
Objects.equals(isDark, other.isDark);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new file based GTheme with the same values as this GTheme
|
|
||||||
* @param saveToFile file to associate and save this GTheme to
|
|
||||||
* @return the new theme
|
|
||||||
* @throws IOException if a general I/O exception occurs
|
|
||||||
*/
|
|
||||||
public GTheme saveToFile(File saveToFile) throws IOException {
|
|
||||||
return doSaveToFile(saveToFile, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new file based GTheme with the same values as this GTheme and includes default
|
|
||||||
* values not modified by this theme.
|
|
||||||
* @param saveToFile file to associate and save this GTheme to
|
|
||||||
* @param defaults the collection of default values to include in the output file
|
|
||||||
* @return the new theme
|
|
||||||
* @throws IOException if a general I/O exception occurs
|
|
||||||
*/
|
|
||||||
public GTheme saveToFile(File saveToFile, GThemeValueMap defaults) throws IOException {
|
|
||||||
GThemeValueMap combined = new GThemeValueMap();
|
|
||||||
combined.load(defaults);
|
|
||||||
combined.load(this);
|
|
||||||
return doSaveToFile(saveToFile, combined);
|
|
||||||
}
|
|
||||||
|
|
||||||
private GTheme doSaveToFile(File saveToFile, GThemeValueMap values) throws IOException {
|
|
||||||
try (BufferedWriter writer = new BufferedWriter(new FileWriter(saveToFile))) {
|
|
||||||
List<ColorValue> colors = values.getColors();
|
|
||||||
Collections.sort(colors);
|
|
||||||
|
|
||||||
List<FontValue> fonts = values.getFonts();
|
|
||||||
Collections.sort(fonts);
|
|
||||||
|
|
||||||
List<IconValue> icons = values.getIcons();
|
|
||||||
Collections.sort(icons);
|
|
||||||
|
|
||||||
writer.write(THEME_NAME_KEY + " = " + name);
|
|
||||||
writer.newLine();
|
|
||||||
|
|
||||||
writer.write(THEME_LOOK_AND_FEEL_KEY + " = " + lookAndFeel.getName());
|
|
||||||
writer.newLine();
|
|
||||||
|
|
||||||
if (isDark()) {
|
|
||||||
writer.write(THEME_IS_DARK_KEY + " = true");
|
|
||||||
writer.newLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ColorValue colorValue : colors) {
|
|
||||||
String outputId = colorValue.toExternalId(colorValue.getId());
|
|
||||||
writer.write(outputId + " = " + getValueOutput(colorValue));
|
|
||||||
writer.newLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (FontValue fontValue : fonts) {
|
|
||||||
String outputId = fontValue.toExternalId(fontValue.getId());
|
|
||||||
writer.write(outputId + " = " + getValueOutput(fontValue));
|
|
||||||
writer.newLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (IconValue iconValue : icons) {
|
|
||||||
String outputId = iconValue.toExternalId(iconValue.getId());
|
|
||||||
writer.write(outputId + " = " + getValueOutput(iconValue));
|
|
||||||
writer.newLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return new FileGTheme(saveToFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getValueOutput(IconValue iconValue) {
|
|
||||||
if (iconValue.getReferenceId() != null) {
|
|
||||||
return iconValue.toExternalId(iconValue.getReferenceId());
|
|
||||||
}
|
|
||||||
return iconValue.getRawValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getValueOutput(FontValue fontValue) {
|
|
||||||
if (fontValue.getReferenceId() != null) {
|
|
||||||
return fontValue.toExternalId(fontValue.getReferenceId());
|
|
||||||
}
|
|
||||||
Font font = fontValue.getRawValue();
|
|
||||||
return String.format("%s-%s-%s", font.getName(), getStyleString(font), font.getSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getStyleString(Font font) {
|
|
||||||
boolean bold = font.isBold();
|
|
||||||
boolean italic = font.isItalic();
|
|
||||||
if (bold && italic) {
|
|
||||||
return "BOLDITALIC";
|
|
||||||
}
|
|
||||||
if (bold) {
|
|
||||||
return "BOLD";
|
|
||||||
}
|
|
||||||
if (italic) {
|
|
||||||
return "ITALIC";
|
|
||||||
}
|
|
||||||
return "PLAIN";
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getValueOutput(ColorValue colorValue) {
|
|
||||||
if (colorValue.getReferenceId() != null) {
|
|
||||||
return colorValue.toExternalId(colorValue.getReferenceId());
|
|
||||||
}
|
|
||||||
Color color = colorValue.getRawValue();
|
|
||||||
String outputString = WebColors.toString(color, false);
|
|
||||||
String colorName = WebColors.toWebColorName(color);
|
|
||||||
if (colorName != null) {
|
|
||||||
outputString += " // " + colorName;
|
|
||||||
}
|
|
||||||
return outputString;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasSupportedLookAndFeel() {
|
public boolean hasSupportedLookAndFeel() {
|
||||||
return lookAndFeel.isSupported();
|
return lookAndFeel.isSupported();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FileGTheme saveToFile(File file, boolean includeDefaults) throws IOException {
|
||||||
|
FileGTheme fileTheme = new FileGTheme(file, name, lookAndFeel);
|
||||||
|
if (includeDefaults) {
|
||||||
|
fileTheme.load(Gui.getDefaults());
|
||||||
|
}
|
||||||
|
fileTheme.load(this);
|
||||||
|
fileTheme.save();
|
||||||
|
return fileTheme;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ public class GThemeDefaults {
|
|||||||
public static final GColor GOLD = new GColor("color.palette.gold");
|
public static final GColor GOLD = new GColor("color.palette.gold");
|
||||||
public static final GColor GRAY = new GColor("color.palette.gray");
|
public static final GColor GRAY = new GColor("color.palette.gray");
|
||||||
public static final GColor GREEN = new GColor("color.palette.green");
|
public static final GColor GREEN = new GColor("color.palette.green");
|
||||||
|
public static final GColor LIGHT_GRAY = new GColor("color.palette.lightgray");
|
||||||
public static final GColor LIME = new GColor("color.palette.lime");
|
public static final GColor LIME = new GColor("color.palette.lime");
|
||||||
public static final GColor ORANGE = new GColor("color.palette.orange");
|
public static final GColor ORANGE = new GColor("color.palette.orange");
|
||||||
public static final GColor PINK = new GColor("color.palette.pink");
|
public static final GColor PINK = new GColor("color.palette.pink");
|
||||||
|
|||||||
@@ -99,4 +99,32 @@ public class GThemeValueMap {
|
|||||||
fontMap.clear();
|
fontMap.clear();
|
||||||
iconMap.clear();
|
iconMap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return colorMap.isEmpty() && fontMap.isEmpty() && iconMap.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeColor(String id) {
|
||||||
|
colorMap.remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GThemeValueMap removeSameValues(GThemeValueMap defaults) {
|
||||||
|
GThemeValueMap map = new GThemeValueMap();
|
||||||
|
for (ColorValue color : colorMap.values()) {
|
||||||
|
if (!color.equals(defaults.getColor(color.getId()))) {
|
||||||
|
map.addColor(color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (FontValue font : fontMap.values()) {
|
||||||
|
if (!font.equals(defaults.getFont(font.getId()))) {
|
||||||
|
map.addFont(font);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (IconValue icon : iconMap.values()) {
|
||||||
|
if (!icon.equals(defaults.getIcon(icon.getId()))) {
|
||||||
|
map.addIconPath(icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,11 @@ import java.util.List;
|
|||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.plaf.UIResource;
|
import javax.swing.plaf.UIResource;
|
||||||
|
|
||||||
|
import com.formdev.flatlaf.*;
|
||||||
|
|
||||||
import docking.framework.ApplicationInformationDisplayFactory;
|
import docking.framework.ApplicationInformationDisplayFactory;
|
||||||
|
import docking.help.Help;
|
||||||
|
import docking.theme.builtin.JavaColorMapping;
|
||||||
import ghidra.framework.Application;
|
import ghidra.framework.Application;
|
||||||
import ghidra.framework.preferences.Preferences;
|
import ghidra.framework.preferences.Preferences;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
@@ -41,13 +45,11 @@ public class Gui {
|
|||||||
private static GTheme activeTheme = new DefaultTheme();
|
private static GTheme activeTheme = new DefaultTheme();
|
||||||
private static Set<GTheme> allThemes;
|
private static Set<GTheme> allThemes;
|
||||||
|
|
||||||
private static GThemeValueMap ghidraCoreDefaults = new GThemeValueMap();
|
private static GThemeValueMap ghidraLightDefaults = new GThemeValueMap();
|
||||||
private static GThemeValueMap originalJavaDefaults;
|
private static GThemeValueMap ghidraDarkDefaults = new GThemeValueMap();
|
||||||
// private static GThemeValueMap convertedJavaDefaults;
|
private static GThemeValueMap javaDefaults = new GThemeValueMap();
|
||||||
private static GThemeValueMap currentValues = new GThemeValueMap();
|
private static GThemeValueMap currentValues = new GThemeValueMap();
|
||||||
|
|
||||||
private static GThemeValueMap darkDefaults = new GThemeValueMap();
|
|
||||||
|
|
||||||
private static ThemePropertiesLoader themePropertiesLoader = new ThemePropertiesLoader();
|
private static ThemePropertiesLoader themePropertiesLoader = new ThemePropertiesLoader();
|
||||||
|
|
||||||
private static Map<String, GColorUIResource> gColorMap = new HashMap<>();
|
private static Map<String, GColorUIResource> gColorMap = new HashMap<>();
|
||||||
@@ -63,91 +65,75 @@ public class Gui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void initialize() {
|
public static void initialize() {
|
||||||
loadThemeDefaults();
|
installFlatLookAndFeels();
|
||||||
|
loadGhidraDefaults();
|
||||||
setTheme(getThemeFromPreferences());
|
setTheme(getThemeFromPreferences());
|
||||||
// LookAndFeelUtils.installGlobalOverrides();
|
// LookAndFeelUtils.installGlobalOverrides();
|
||||||
platformSpecificFixups();
|
platformSpecificFixups();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void loadThemeDefaults() {
|
private static void installFlatLookAndFeels() {
|
||||||
themePropertiesLoader.load();
|
UIManager.installLookAndFeel(LafType.FLAT_LIGHT.getName(), FlatLightLaf.class.getName());
|
||||||
ghidraCoreDefaults = themePropertiesLoader.getDefaults();
|
UIManager.installLookAndFeel(LafType.FLAT_DARK.getName(), FlatDarkLaf.class.getName());
|
||||||
darkDefaults = themePropertiesLoader.getDarkDefaults();
|
UIManager.installLookAndFeel(LafType.FLAT_DARCULA.getName(),
|
||||||
|
FlatDarculaLaf.class.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void reloadThemeDefaults() {
|
private static void loadGhidraDefaults() {
|
||||||
loadThemeDefaults();
|
themePropertiesLoader.load();
|
||||||
currentValues = buildCurrentValues(activeTheme);
|
ghidraLightDefaults = themePropertiesLoader.getDefaults();
|
||||||
refresh();
|
ghidraDarkDefaults = themePropertiesLoader.getDarkDefaults();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void reloadGhidraDefaults() {
|
||||||
|
loadGhidraDefaults();
|
||||||
|
buildCurrentValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void restoreThemeValues() {
|
||||||
|
buildCurrentValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setTheme(GTheme theme) {
|
public static void setTheme(GTheme theme) {
|
||||||
if (theme.hasSupportedLookAndFeel()) {
|
if (theme.hasSupportedLookAndFeel()) {
|
||||||
activeTheme = theme;
|
activeTheme = theme;
|
||||||
LookAndFeelType lookAndFeel = theme.getLookAndFeelType();
|
LafType lookAndFeel = theme.getLookAndFeelType();
|
||||||
try {
|
try {
|
||||||
lookAndFeel.install();
|
lookAndFeel.install();
|
||||||
|
saveThemeToPreferences(theme);
|
||||||
|
fixupJavaDefaults();
|
||||||
|
// The help may produce errors when switching the theme, such as if there is an
|
||||||
|
// active search in the help. We have added this call to allow the help system
|
||||||
|
// to cleanup some internal state.
|
||||||
|
Help.getHelpService().reload();
|
||||||
|
buildCurrentValues();
|
||||||
|
updateUIs();
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
Msg.error(Gui.class, "Error setting LookAndFeel: " + lookAndFeel.getName());
|
Msg.error(Gui.class, "Error setting LookAndFeel: " + lookAndFeel.getName(), e);
|
||||||
}
|
}
|
||||||
refresh();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void refresh() {
|
public static void addTheme(GTheme newTheme) {
|
||||||
GColor.refreshAll();
|
allThemes.remove(newTheme);
|
||||||
|
allThemes.add(newTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void updateUIs() {
|
||||||
for (Window window : Window.getWindows()) {
|
for (Window window : Window.getWindows()) {
|
||||||
SwingUtilities.updateComponentTreeUI(window);
|
SwingUtilities.updateComponentTreeUI(window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// private static GThemeValueMap convertJavaDefaults(GThemeValueMap input) {
|
|
||||||
// GThemeValueMap converted = new GThemeValueMap();
|
|
||||||
// for (ColorValue colorValue : input.getColors()) {
|
|
||||||
// converted.addColor(fromUiResource(colorValue));
|
|
||||||
// }
|
|
||||||
// for (FontValue fontValue : input.getFonts()) {
|
|
||||||
// converted.addFont(fromUiResource(fontValue));
|
|
||||||
// }
|
|
||||||
// // java icons are not currently supported
|
|
||||||
// return converted;
|
|
||||||
// }
|
|
||||||
|
|
||||||
private static FontValue fromUiResource(FontValue fontValue) {
|
|
||||||
Font font = fontValue.getRawValue();
|
|
||||||
if (font instanceof UIResource) {
|
|
||||||
return new FontValue(fontValue.getId(), font.deriveFont(font.getStyle()));
|
|
||||||
}
|
|
||||||
return fontValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ColorValue fromUiResource(ColorValue colorValue) {
|
|
||||||
Color color = colorValue.getRawValue();
|
|
||||||
if (color instanceof UIResource) {
|
|
||||||
return new ColorValue(colorValue.getId(), new Color(color.getRGB(), true));
|
|
||||||
}
|
|
||||||
return colorValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isJavaDefinedColor(String id) {
|
public static boolean isJavaDefinedColor(String id) {
|
||||||
return originalJavaDefaults.containsColor(id);
|
return javaDefaults.containsColor(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GThemeValueMap getAllValues() {
|
public static GThemeValueMap getAllValues() {
|
||||||
return new GThemeValueMap(currentValues);
|
return new GThemeValueMap(currentValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GThemeValueMap getAllDefaultValues() {
|
|
||||||
GThemeValueMap currentDefaults = new GThemeValueMap();
|
|
||||||
currentDefaults.load(originalJavaDefaults);
|
|
||||||
currentDefaults.load(ghidraCoreDefaults);
|
|
||||||
if (activeTheme.isDark()) {
|
|
||||||
currentDefaults.load(darkDefaults);
|
|
||||||
}
|
|
||||||
return currentDefaults;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Set<GTheme> getAllThemes() {
|
public static Set<GTheme> getAllThemes() {
|
||||||
if (allThemes == null) {
|
if (allThemes == null) {
|
||||||
allThemes = findThemes();
|
allThemes = findThemes();
|
||||||
@@ -196,7 +182,7 @@ public class Gui {
|
|||||||
return new GIcon(id);
|
return new GIcon(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void saveThemeToPreferneces(GTheme theme) {
|
public static void saveThemeToPreferences(GTheme theme) {
|
||||||
Preferences.setProperty(THEME_PREFFERENCE_KEY, theme.getThemeLocater());
|
Preferences.setProperty(THEME_PREFFERENCE_KEY, theme.getThemeLocater());
|
||||||
Preferences.store();
|
Preferences.store();
|
||||||
}
|
}
|
||||||
@@ -205,7 +191,7 @@ public class Gui {
|
|||||||
return activeTheme;
|
return activeTheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LookAndFeelType getLookAndFeelType() {
|
public static LafType getLookAndFeelType() {
|
||||||
return activeTheme.getLookAndFeelType();
|
return activeTheme.getLookAndFeelType();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,16 +255,18 @@ public class Gui {
|
|||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static GThemeValueMap buildCurrentValues(GTheme theme) {
|
private static void buildCurrentValues() {
|
||||||
GThemeValueMap map = new GThemeValueMap();
|
GThemeValueMap map = new GThemeValueMap();
|
||||||
|
|
||||||
map.load(originalJavaDefaults);
|
map.load(javaDefaults);
|
||||||
map.load(ghidraCoreDefaults);
|
map.load(ghidraLightDefaults);
|
||||||
if (theme.isDark()) {
|
if (activeTheme.isDark()) {
|
||||||
map.load(darkDefaults);
|
map.load(ghidraDarkDefaults);
|
||||||
}
|
}
|
||||||
map.load(theme);
|
map.load(activeTheme);
|
||||||
return map;
|
currentValues = map;
|
||||||
|
GColor.refreshAll();
|
||||||
|
repaintAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Color getUIColor(String id) {
|
private static Color getUIColor(String id) {
|
||||||
@@ -306,7 +294,7 @@ public class Gui {
|
|||||||
List<File> fileList = new ArrayList<>();
|
List<File> fileList = new ArrayList<>();
|
||||||
|
|
||||||
File dir = Application.getUserSettingsDirectory();
|
File dir = Application.getUserSettingsDirectory();
|
||||||
FileFilter themeFileFilter = file -> file.getName().endsWith(".theme");
|
FileFilter themeFileFilter = file -> file.getName().endsWith(GTheme.FILE_EXTENSION);
|
||||||
fileList.addAll(Arrays.asList(dir.listFiles(themeFileFilter)));
|
fileList.addAll(Arrays.asList(dir.listFiles(themeFileFilter)));
|
||||||
|
|
||||||
List<GTheme> list = new ArrayList<>();
|
List<GTheme> list = new ArrayList<>();
|
||||||
@@ -359,29 +347,19 @@ public class Gui {
|
|||||||
return new DefaultTheme();
|
return new DefaultTheme();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GThemeValueMap getCoreDefaults() {
|
|
||||||
GThemeValueMap map = new GThemeValueMap(ghidraCoreDefaults);
|
|
||||||
map.load(originalJavaDefaults);
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GThemeValueMap getDarkDefaults() {
|
|
||||||
GThemeValueMap map = new GThemeValueMap(ghidraCoreDefaults);
|
|
||||||
map.load(darkDefaults);
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setColor(String id, Color color) {
|
public static void setColor(String id, Color color) {
|
||||||
setColor(new ColorValue(id, color));
|
setColor(new ColorValue(id, color));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setColor(ColorValue colorValue) {
|
public static void setColor(ColorValue colorValue) {
|
||||||
currentValues.addColor(colorValue);
|
currentValues.addColor(colorValue);
|
||||||
System.out.println("Change color: " + colorValue);
|
|
||||||
GColor.refreshAll();
|
GColor.refreshAll();
|
||||||
|
repaintAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void repaintAll() {
|
||||||
for (Window window : Window.getWindows()) {
|
for (Window window : Window.getWindows()) {
|
||||||
window.repaint();
|
window.repaint();
|
||||||
// SynthLookAndFeel.updateStyles(window);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -394,13 +372,45 @@ public class Gui {
|
|||||||
return gColor;
|
return gColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setJavaDefaults(GThemeValueMap javaDefaults) {
|
public static void setJavaDefaults(GThemeValueMap map) {
|
||||||
originalJavaDefaults = javaDefaults;
|
javaDefaults = map;
|
||||||
currentValues = buildCurrentValues(activeTheme);
|
buildCurrentValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void fixupJavaDefaults() {
|
||||||
|
List<ColorValue> colors = javaDefaults.getColors();
|
||||||
|
JavaColorMapping mapping = new JavaColorMapping();
|
||||||
|
for (ColorValue value : colors) {
|
||||||
|
ColorValue mapped = mapping.map(javaDefaults, value);
|
||||||
|
if (mapped != null) {
|
||||||
|
javaDefaults.addColor(mapped);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GThemeValueMap getJavaDefaults() {
|
public static GThemeValueMap getJavaDefaults() {
|
||||||
return originalJavaDefaults;
|
GThemeValueMap map = new GThemeValueMap();
|
||||||
|
map.load(javaDefaults);
|
||||||
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static GThemeValueMap getGhidraDarkDefaults() {
|
||||||
|
GThemeValueMap map = new GThemeValueMap(ghidraLightDefaults);
|
||||||
|
map.load(ghidraDarkDefaults);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GThemeValueMap getGhidraLightDefaults() {
|
||||||
|
GThemeValueMap map = new GThemeValueMap(ghidraLightDefaults);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static GThemeValueMap getDefaults() {
|
||||||
|
GThemeValueMap currentDefaults = new GThemeValueMap(javaDefaults);
|
||||||
|
currentDefaults.load(ghidraLightDefaults);
|
||||||
|
if (activeTheme.isDark()) {
|
||||||
|
currentDefaults.load(ghidraDarkDefaults);
|
||||||
|
}
|
||||||
|
return currentDefaults;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,123 @@
|
|||||||
|
/* ###
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.UIManager.LookAndFeelInfo;
|
||||||
|
|
||||||
|
import docking.theme.laf.*;
|
||||||
|
import ghidra.framework.OperatingSystem;
|
||||||
|
import ghidra.framework.Platform;
|
||||||
|
import ghidra.util.exception.AssertException;
|
||||||
|
|
||||||
|
public enum LafType {
|
||||||
|
METAL("Metal", false),
|
||||||
|
NIMBUS("Nimbus", false),
|
||||||
|
GTK("GTK+", false),
|
||||||
|
MOTIF("CDE/Motif", false),
|
||||||
|
FLAT_LIGHT("Flat Light", false),
|
||||||
|
FLAT_DARK("Flat Dark", true),
|
||||||
|
FLAT_DARCULA("Flat Darcula", true),
|
||||||
|
WINDOWS("Windows", false),
|
||||||
|
WINDOWS_CLASSIC("Windows Classic", false),
|
||||||
|
MAC("Mac OS X", false),
|
||||||
|
SYSTEM("System", false);
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private boolean isDark;
|
||||||
|
|
||||||
|
private LafType(String name, boolean isDark) {
|
||||||
|
this.name = name;
|
||||||
|
this.isDark = isDark;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDark() {
|
||||||
|
return isDark;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LafType fromName(String name) {
|
||||||
|
for (LafType type : values()) {
|
||||||
|
if (type.getName().equals(name)) {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LookAndFeelInstaller getSystemLookAndFeelInstaller() {
|
||||||
|
OperatingSystem OS = Platform.CURRENT_PLATFORM.getOperatingSystem();
|
||||||
|
if (OS == OperatingSystem.LINUX) {
|
||||||
|
return getInstaller(NIMBUS);
|
||||||
|
}
|
||||||
|
else if (OS == OperatingSystem.MAC_OS_X) {
|
||||||
|
return getInstaller(MAC);
|
||||||
|
}
|
||||||
|
else if (OS == OperatingSystem.WINDOWS) {
|
||||||
|
return getInstaller(WINDOWS);
|
||||||
|
}
|
||||||
|
return getInstaller(NIMBUS);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSupported() {
|
||||||
|
if (this == SYSTEM) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
LookAndFeelInfo[] installedLookAndFeels = UIManager.getInstalledLookAndFeels();
|
||||||
|
for (LookAndFeelInfo info : installedLookAndFeels) {
|
||||||
|
if (name.equals(info.getName())) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void install() throws Exception {
|
||||||
|
getInstaller(this).install();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LookAndFeelInstaller getInstaller(LafType lookAndFeel) {
|
||||||
|
switch (lookAndFeel) {
|
||||||
|
case FLAT_DARCULA:
|
||||||
|
return new FlatLookAndFeelInstaller(FLAT_DARCULA);
|
||||||
|
case FLAT_DARK:
|
||||||
|
return new FlatLookAndFeelInstaller(FLAT_DARK);
|
||||||
|
case FLAT_LIGHT:
|
||||||
|
return new FlatLookAndFeelInstaller(FLAT_LIGHT);
|
||||||
|
case GTK:
|
||||||
|
return new GTKLookAndFeelInstaller();
|
||||||
|
case MAC:
|
||||||
|
return new LookAndFeelInstaller(MAC);
|
||||||
|
case METAL:
|
||||||
|
return new LookAndFeelInstaller(METAL);
|
||||||
|
case MOTIF:
|
||||||
|
return new MotifLookAndFeelInstaller(); // Motif has some specific ui fix ups
|
||||||
|
case NIMBUS:
|
||||||
|
return new NimbusLookAndFeelInstaller(); // Nimbus installs a special way
|
||||||
|
case SYSTEM:
|
||||||
|
return getSystemLookAndFeelInstaller();
|
||||||
|
case WINDOWS:
|
||||||
|
return new LookAndFeelInstaller(WINDOWS);
|
||||||
|
case WINDOWS_CLASSIC:
|
||||||
|
return new LookAndFeelInstaller(WINDOWS_CLASSIC);
|
||||||
|
default:
|
||||||
|
throw new AssertException("No lookAndFeelInstaller defined for " + lookAndFeel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,80 +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 docking.theme;
|
|
||||||
|
|
||||||
import com.formdev.flatlaf.*;
|
|
||||||
|
|
||||||
import docking.theme.laf.*;
|
|
||||||
import ghidra.framework.OperatingSystem;
|
|
||||||
import ghidra.framework.Platform;
|
|
||||||
|
|
||||||
public enum LookAndFeelType {
|
|
||||||
METAL("Metal", new MetalLookAndFeelInstaller()),
|
|
||||||
NIMBUS("Nimbus", new NimbusLookAndFeelInstaller()),
|
|
||||||
GTK("GTK+", new GTKLookAndFeelInstaller()),
|
|
||||||
MOTIF("CDE/Motif", new MotifLookAndFeelInstaller()),
|
|
||||||
FLAT_LIGHT("Flat Light", new FlatLookAndFeelInstaller(new FlatLightLaf())),
|
|
||||||
FLAT_DARK("Flat Dark", new FlatLookAndFeelInstaller(new FlatDarkLaf())),
|
|
||||||
FLAT_DARCULA("Flat Light", new FlatLookAndFeelInstaller(new FlatDarculaLaf())),
|
|
||||||
WINDOWS("Windows", new WindowsLookAndFeelInstaller()),
|
|
||||||
WINDOWS_CLASSIC("Windows Classic", new WindowsClassicLookAndFeelInstaller()),
|
|
||||||
MAC("Mac OS X", new MacLookAndFeelInstaller()),
|
|
||||||
SYSTEM("System", getSystemLookAndFeelInstaller());
|
|
||||||
|
|
||||||
private String name;
|
|
||||||
private LookAndFeelInstaller installer;
|
|
||||||
|
|
||||||
private LookAndFeelType(String name, LookAndFeelInstaller installer) {
|
|
||||||
this.name = name;
|
|
||||||
this.installer = installer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LookAndFeelType fromName(String name) {
|
|
||||||
for (LookAndFeelType type : values()) {
|
|
||||||
if (type.getName().equals(name)) {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static LookAndFeelInstaller getSystemLookAndFeelInstaller() {
|
|
||||||
OperatingSystem OS = Platform.CURRENT_PLATFORM.getOperatingSystem();
|
|
||||||
if (OS == OperatingSystem.LINUX) {
|
|
||||||
return NIMBUS.installer;
|
|
||||||
}
|
|
||||||
else if (OS == OperatingSystem.MAC_OS_X) {
|
|
||||||
return MAC.installer;
|
|
||||||
}
|
|
||||||
else if (OS == OperatingSystem.WINDOWS) {
|
|
||||||
return WINDOWS.installer;
|
|
||||||
}
|
|
||||||
return NIMBUS.installer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isSupported() {
|
|
||||||
return installer.isSupportedForCurrentPlatform();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void install() throws Exception {
|
|
||||||
installer.install();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -22,8 +22,7 @@ public class ThemeReader extends ThemePropertyFileReader {
|
|||||||
|
|
||||||
private Section themeSection;
|
private Section themeSection;
|
||||||
private String themeName;
|
private String themeName;
|
||||||
private LookAndFeelType lookAndFeel;
|
private LafType lookAndFeel;
|
||||||
private boolean isDark;
|
|
||||||
|
|
||||||
public ThemeReader(File file) throws IOException {
|
public ThemeReader(File file) throws IOException {
|
||||||
super(file);
|
super(file);
|
||||||
@@ -37,12 +36,11 @@ public class ThemeReader extends ThemePropertyFileReader {
|
|||||||
throw new IOException("Missing theme name!");
|
throw new IOException("Missing theme name!");
|
||||||
}
|
}
|
||||||
String lookAndFeelName = section.getValue(GTheme.THEME_LOOK_AND_FEEL_KEY);
|
String lookAndFeelName = section.getValue(GTheme.THEME_LOOK_AND_FEEL_KEY);
|
||||||
lookAndFeel = LookAndFeelType.fromName(lookAndFeelName);
|
lookAndFeel = LafType.fromName(lookAndFeelName);
|
||||||
if (lookAndFeel == null) {
|
if (lookAndFeel == null) {
|
||||||
throw new IOException(
|
throw new IOException(
|
||||||
"Invalid or missing lookAndFeel name: \"" + lookAndFeelName + "\"");
|
"Invalid or missing lookAndFeel name: \"" + lookAndFeelName + "\"");
|
||||||
}
|
}
|
||||||
isDark = Boolean.parseBoolean(section.getValue(GTheme.THEME_IS_DARK_KEY));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadValues(GTheme theme) {
|
void loadValues(GTheme theme) {
|
||||||
@@ -50,7 +48,6 @@ public class ThemeReader extends ThemePropertyFileReader {
|
|||||||
// processValues expects only colors, fonts, and icons
|
// processValues expects only colors, fonts, and icons
|
||||||
themeSection.remove(GTheme.THEME_NAME_KEY);
|
themeSection.remove(GTheme.THEME_NAME_KEY);
|
||||||
themeSection.remove(GTheme.THEME_LOOK_AND_FEEL_KEY);
|
themeSection.remove(GTheme.THEME_LOOK_AND_FEEL_KEY);
|
||||||
themeSection.remove(GTheme.THEME_IS_DARK_KEY);
|
|
||||||
|
|
||||||
processValues(theme, themeSection);
|
processValues(theme, themeSection);
|
||||||
}
|
}
|
||||||
@@ -59,11 +56,7 @@ public class ThemeReader extends ThemePropertyFileReader {
|
|||||||
return themeName;
|
return themeName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDark() {
|
public LafType getLookAndFeelType() {
|
||||||
return isDark;
|
|
||||||
}
|
|
||||||
|
|
||||||
public LookAndFeelType getLookAndFeelType() {
|
|
||||||
return lookAndFeel;
|
return lookAndFeel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,12 +16,12 @@
|
|||||||
package docking.theme.builtin;
|
package docking.theme.builtin;
|
||||||
|
|
||||||
import docking.theme.DiscoverableGTheme;
|
import docking.theme.DiscoverableGTheme;
|
||||||
import docking.theme.LookAndFeelType;
|
import docking.theme.LafType;
|
||||||
|
|
||||||
public class CDEMotifTheme extends DiscoverableGTheme {
|
public class CDEMotifTheme extends DiscoverableGTheme {
|
||||||
|
|
||||||
public CDEMotifTheme() {
|
public CDEMotifTheme() {
|
||||||
super("Motif", LookAndFeelType.MOTIF);
|
super("Motif", LafType.MOTIF);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,10 +16,10 @@
|
|||||||
package docking.theme.builtin;
|
package docking.theme.builtin;
|
||||||
|
|
||||||
import docking.theme.DiscoverableGTheme;
|
import docking.theme.DiscoverableGTheme;
|
||||||
import docking.theme.LookAndFeelType;
|
import docking.theme.LafType;
|
||||||
|
|
||||||
public class FlatDarculaTheme extends DiscoverableGTheme {
|
public class FlatDarculaTheme extends DiscoverableGTheme {
|
||||||
public FlatDarculaTheme() {
|
public FlatDarculaTheme() {
|
||||||
super("Flat Darcula", LookAndFeelType.FLAT_DARCULA, true);
|
super("Flat Darcula", LafType.FLAT_DARCULA);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,10 +16,10 @@
|
|||||||
package docking.theme.builtin;
|
package docking.theme.builtin;
|
||||||
|
|
||||||
import docking.theme.DiscoverableGTheme;
|
import docking.theme.DiscoverableGTheme;
|
||||||
import docking.theme.LookAndFeelType;
|
import docking.theme.LafType;
|
||||||
|
|
||||||
public class FlatDarkTheme extends DiscoverableGTheme {
|
public class FlatDarkTheme extends DiscoverableGTheme {
|
||||||
public FlatDarkTheme() {
|
public FlatDarkTheme() {
|
||||||
super("Flat Dark", LookAndFeelType.FLAT_DARK, true);
|
super("Flat Dark", LafType.FLAT_DARK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,12 @@
|
|||||||
package docking.theme.builtin;
|
package docking.theme.builtin;
|
||||||
|
|
||||||
import docking.theme.DiscoverableGTheme;
|
import docking.theme.DiscoverableGTheme;
|
||||||
import docking.theme.LookAndFeelType;
|
import docking.theme.LafType;
|
||||||
|
|
||||||
public class FlatLightTheme extends DiscoverableGTheme {
|
public class FlatLightTheme extends DiscoverableGTheme {
|
||||||
|
|
||||||
public FlatLightTheme() {
|
public FlatLightTheme() {
|
||||||
super("Flat Light", LookAndFeelType.FLAT_LIGHT);
|
super("Flat Light", LafType.FLAT_LIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,12 @@
|
|||||||
package docking.theme.builtin;
|
package docking.theme.builtin;
|
||||||
|
|
||||||
import docking.theme.DiscoverableGTheme;
|
import docking.theme.DiscoverableGTheme;
|
||||||
import docking.theme.LookAndFeelType;
|
import docking.theme.LafType;
|
||||||
|
|
||||||
public class GTKTheme extends DiscoverableGTheme {
|
public class GTKTheme extends DiscoverableGTheme {
|
||||||
|
|
||||||
public GTKTheme() {
|
public GTKTheme() {
|
||||||
super("GDK+", LookAndFeelType.GTK);
|
super("GTK+", LafType.GTK);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,246 @@
|
|||||||
|
/* ###
|
||||||
|
* 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.builtin;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import docking.theme.ColorValue;
|
||||||
|
import docking.theme.GThemeValueMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps Java UIDefaults color ids to parent color ids
|
||||||
|
*/
|
||||||
|
public class JavaColorMapping {
|
||||||
|
private Map<String, String> map = new HashMap<>();
|
||||||
|
|
||||||
|
public JavaColorMapping() {
|
||||||
|
// color relationships mined from BasicLookAndFeel
|
||||||
|
map.put("Button.background", "control");
|
||||||
|
map.put("Button.foreground", "controlText");
|
||||||
|
map.put("Button.shadow", "controlShadow");
|
||||||
|
map.put("Button.darkShadow", "controlDkShadow");
|
||||||
|
map.put("Button.light", "controlHighlight");
|
||||||
|
map.put("Button.highlight", "controlLtHighlight");
|
||||||
|
map.put("ToggleButton.background", "control");
|
||||||
|
map.put("ToggleButton.foreground", "controlText");
|
||||||
|
map.put("ToggleButton.shadow", "controlShadow");
|
||||||
|
map.put("ToggleButton.darkShadow", "controlDkShadow");
|
||||||
|
map.put("ToggleButton.light", "controlHighlight");
|
||||||
|
map.put("ToggleButton.highlight", "controlLtHighlight");
|
||||||
|
map.put("RadioButton.background", "control");
|
||||||
|
map.put("RadioButton.foreground", "controlText");
|
||||||
|
map.put("RadioButton.shadow", "controlShadow");
|
||||||
|
map.put("RadioButton.darkShadow", "controlDkShadow");
|
||||||
|
map.put("RadioButton.light", "controlHighlight");
|
||||||
|
map.put("RadioButton.highlight", "controlLtHighlight");
|
||||||
|
map.put("CheckBox.background", "control");
|
||||||
|
map.put("CheckBox.foreground", "controlText");
|
||||||
|
map.put("ColorChooser.background", "control");
|
||||||
|
map.put("ColorChooser.foreground", "controlText");
|
||||||
|
map.put("ColorChooser.swatchesDefaultRecentColor", "control");
|
||||||
|
map.put("ComboBox.background", "window");
|
||||||
|
map.put("ComboBox.foreground", "textText");
|
||||||
|
map.put("ComboBox.buttonBackground", "control");
|
||||||
|
map.put("ComboBox.buttonShadow", "controlShadow");
|
||||||
|
map.put("ComboBox.buttonDarkShadow", "controlDkShadow");
|
||||||
|
map.put("ComboBox.buttonHighlight", "controlLtHighlight");
|
||||||
|
map.put("ComboBox.selectionBackground", "textHighlight");
|
||||||
|
map.put("ComboBox.selectionForeground", "textHighlightText");
|
||||||
|
map.put("ComboBox.disabledBackground", "control");
|
||||||
|
map.put("ComboBox.disabledForeground", "textHInactiveText");
|
||||||
|
map.put("InternalFrame.borderColor", "control");
|
||||||
|
map.put("InternalFrame.borderShadow", "controlShadow");
|
||||||
|
map.put("InternalFrame.borderDarkShadow", "controlDkShadow");
|
||||||
|
map.put("InternalFrame.borderHighlight", "controlLtHighlight");
|
||||||
|
map.put("InternalFrame.borderLight", "controlHighlight");
|
||||||
|
map.put("InternalFrame.activeTitleBackground", "activeCaption");
|
||||||
|
map.put("InternalFrame.activeTitleForeground", "activeCaptionText");
|
||||||
|
map.put("InternalFrame.inactiveTitleBackground", "inactiveCaption");
|
||||||
|
map.put("InternalFrame.inactiveTitleForeground", "inactiveCaptionText");
|
||||||
|
map.put("Label.background", "control");
|
||||||
|
map.put("Label.foreground", "controlText");
|
||||||
|
map.put("Label.disabledShadow", "controlShadow");
|
||||||
|
map.put("List.background", "window");
|
||||||
|
map.put("List.foreground", "textText");
|
||||||
|
map.put("List.selectionBackground", "textHighlight");
|
||||||
|
map.put("List.selectionForeground", "textHighlightText");
|
||||||
|
map.put("List.dropLineColor", "controlShadow");
|
||||||
|
map.put("MenuBar.background", "menu");
|
||||||
|
map.put("MenuBar.foreground", "menuText");
|
||||||
|
map.put("MenuBar.shadow", "controlShadow");
|
||||||
|
map.put("MenuBar.highlight", "controlLtHighlight");
|
||||||
|
map.put("MenuItem.background", "menu");
|
||||||
|
map.put("MenuItem.foreground", "menuText");
|
||||||
|
map.put("MenuItem.selectionForeground", "textHighlightText");
|
||||||
|
map.put("MenuItem.selectionBackground", "textHighlight");
|
||||||
|
map.put("MenuItem.acceleratorForeground", "menuText");
|
||||||
|
map.put("MenuItem.acceleratorSelectionForeground", "textHighlightText");
|
||||||
|
map.put("RadioButtonMenuItem.background", "menu");
|
||||||
|
map.put("RadioButtonMenuItem.foreground", "menuText");
|
||||||
|
map.put("RadioButtonMenuItem.selectionForeground", "textHighlightText");
|
||||||
|
map.put("RadioButtonMenuItem.selectionBackground", "textHighlight");
|
||||||
|
map.put("RadioButtonMenuItem.acceleratorForeground", "menuText");
|
||||||
|
map.put("RadioButtonMenuItem.acceleratorSelectionForeground", "textHighlightText");
|
||||||
|
map.put("CheckBoxMenuItem.background", "menu");
|
||||||
|
map.put("CheckBoxMenuItem.foreground", "menuText");
|
||||||
|
map.put("CheckBoxMenuItem.selectionForeground", "textHighlightText");
|
||||||
|
map.put("CheckBoxMenuItem.selectionBackground", "textHighlight");
|
||||||
|
map.put("CheckBoxMenuItem.acceleratorForeground", "menuText");
|
||||||
|
map.put("CheckBoxMenuItem.acceleratorSelectionForeground", "textHighlightText");
|
||||||
|
map.put("Menu.background", "menu");
|
||||||
|
map.put("Menu.foreground", "menuText");
|
||||||
|
map.put("Menu.selectionForeground", "textHighlightText");
|
||||||
|
map.put("Menu.selectionBackground", "textHighlight");
|
||||||
|
map.put("Menu.acceleratorForeground", "menuText");
|
||||||
|
map.put("Menu.acceleratorSelectionForeground", "textHighlightText");
|
||||||
|
map.put("PopupMenu.background", "menu");
|
||||||
|
map.put("PopupMenu.foreground", "menuText");
|
||||||
|
map.put("OptionPane.background", "control");
|
||||||
|
map.put("OptionPane.foreground", "controlText");
|
||||||
|
map.put("OptionPane.messageForeground", "controlText");
|
||||||
|
map.put("Panel.background", "control");
|
||||||
|
map.put("Panel.foreground", "textText");
|
||||||
|
map.put("ProgressBar.foreground", "textHighlight");
|
||||||
|
map.put("ProgressBar.background", "control");
|
||||||
|
map.put("ProgressBar.selectionForeground", "control");
|
||||||
|
map.put("ProgressBar.selectionBackground", "textHighlight");
|
||||||
|
map.put("Separator.background", "controlLtHighlight");
|
||||||
|
map.put("Separator.foreground", "controlShadow");
|
||||||
|
map.put("ScrollBar.foreground", "control");
|
||||||
|
map.put("ScrollBar.track", "scrollbar");
|
||||||
|
map.put("ScrollBar.trackHighlight", "controlDkShadow");
|
||||||
|
map.put("ScrollBar.thumb", "control");
|
||||||
|
map.put("ScrollBar.thumbHighlight", "controlLtHighlight");
|
||||||
|
map.put("ScrollBar.thumbDarkShadow", "controlDkShadow");
|
||||||
|
map.put("ScrollBar.thumbShadow", "controlShadow");
|
||||||
|
map.put("ScrollPane.background", "control");
|
||||||
|
map.put("ScrollPane.foreground", "controlText");
|
||||||
|
map.put("Viewport.background", "control");
|
||||||
|
map.put("Viewport.foreground", "textText");
|
||||||
|
map.put("Slider.foreground", "control");
|
||||||
|
map.put("Slider.background", "control");
|
||||||
|
map.put("Slider.highlight", "controlLtHighlight");
|
||||||
|
map.put("Slider.shadow", "controlShadow");
|
||||||
|
map.put("Slider.focus", "controlDkShadow");
|
||||||
|
map.put("Spinner.background", "control");
|
||||||
|
map.put("Spinner.foreground", "control");
|
||||||
|
map.put("SplitPane.background", "control");
|
||||||
|
map.put("SplitPane.highlight", "controlLtHighlight");
|
||||||
|
map.put("SplitPane.shadow", "controlShadow");
|
||||||
|
map.put("SplitPane.darkShadow", "controlDkShadow");
|
||||||
|
map.put("TabbedPane.background", "control");
|
||||||
|
map.put("TabbedPane.foreground", "controlText");
|
||||||
|
map.put("TabbedPane.highlight", "controlLtHighlight");
|
||||||
|
map.put("TabbedPane.light", "controlHighlight");
|
||||||
|
map.put("TabbedPane.shadow", "controlShadow");
|
||||||
|
map.put("TabbedPane.darkShadow", "controlDkShadow");
|
||||||
|
map.put("TabbedPane.focus", "controlText");
|
||||||
|
map.put("Table.foreground", "controlText");
|
||||||
|
map.put("Table.background", "window");
|
||||||
|
map.put("Table.selectionForeground", "textHighlightText");
|
||||||
|
map.put("Table.selectionBackground", "textHighlight");
|
||||||
|
map.put("Table.dropLineColor", "controlShadow");
|
||||||
|
map.put("Table.focusCellBackground", "window");
|
||||||
|
map.put("Table.focusCellForeground", "controlText");
|
||||||
|
map.put("TableHeader.foreground", "controlText");
|
||||||
|
map.put("TableHeader.background", "control");
|
||||||
|
map.put("TableHeader.focusCellBackground", "text");
|
||||||
|
map.put("TextField.background", "window");
|
||||||
|
map.put("TextField.foreground", "textText");
|
||||||
|
map.put("TextField.shadow", "controlShadow");
|
||||||
|
map.put("TextField.darkShadow", "controlDkShadow");
|
||||||
|
map.put("TextField.light", "controlHighlight");
|
||||||
|
map.put("TextField.highlight", "controlLtHighlight");
|
||||||
|
map.put("TextField.inactiveForeground", "textHInactiveText");
|
||||||
|
map.put("TextField.inactiveBackground", "control");
|
||||||
|
map.put("TextField.selectionBackground", "textHighlight");
|
||||||
|
map.put("TextField.selectionForeground", "textHighlightText");
|
||||||
|
map.put("TextField.caretForeground", "textText");
|
||||||
|
map.put("FormattedTextField.background", "window");
|
||||||
|
map.put("FormattedTextField.foreground", "textText");
|
||||||
|
map.put("FormattedTextField.inactiveForeground", "textHInactiveText");
|
||||||
|
map.put("FormattedTextField.inactiveBackground", "control");
|
||||||
|
map.put("FormattedTextField.selectionBackground", "textHighlight");
|
||||||
|
map.put("FormattedTextField.selectionForeground", "textHighlightText");
|
||||||
|
map.put("FormattedTextField.caretForeground", "textText");
|
||||||
|
map.put("PasswordField.background", "window");
|
||||||
|
map.put("PasswordField.foreground", "textText");
|
||||||
|
map.put("PasswordField.inactiveForeground", "textHInactiveText");
|
||||||
|
map.put("PasswordField.inactiveBackground", "control");
|
||||||
|
map.put("PasswordField.selectionBackground", "textHighlight");
|
||||||
|
map.put("PasswordField.selectionForeground", "textHighlightText");
|
||||||
|
map.put("PasswordField.caretForeground", "textText");
|
||||||
|
map.put("TextArea.background", "window");
|
||||||
|
map.put("TextArea.foreground", "textText");
|
||||||
|
map.put("TextArea.inactiveForeground", "textHInactiveText");
|
||||||
|
map.put("TextArea.selectionBackground", "textHighlight");
|
||||||
|
map.put("TextArea.selectionForeground", "textHighlightText");
|
||||||
|
map.put("TextArea.caretForeground", "textText");
|
||||||
|
map.put("TextPane.foreground", "textText");
|
||||||
|
map.put("TextPane.selectionBackground", "textHighlight");
|
||||||
|
map.put("TextPane.selectionForeground", "textHighlightText");
|
||||||
|
map.put("TextPane.caretForeground", "textText");
|
||||||
|
map.put("TextPane.inactiveForeground", "textHInactiveText");
|
||||||
|
map.put("EditorPane.foreground", "textText");
|
||||||
|
map.put("EditorPane.selectionBackground", "textHighlight");
|
||||||
|
map.put("EditorPane.selectionForeground", "textHighlightText");
|
||||||
|
map.put("EditorPane.caretForeground", "textText");
|
||||||
|
map.put("EditorPane.inactiveForeground", "textHInactiveText");
|
||||||
|
map.put("TitledBorder.titleColor", "controlText");
|
||||||
|
map.put("ToolBar.background", "control");
|
||||||
|
map.put("ToolBar.foreground", "controlText");
|
||||||
|
map.put("ToolBar.shadow", "controlShadow");
|
||||||
|
map.put("ToolBar.darkShadow", "controlDkShadow");
|
||||||
|
map.put("ToolBar.light", "controlHighlight");
|
||||||
|
map.put("ToolBar.highlight", "controlLtHighlight");
|
||||||
|
map.put("ToolBar.dockingBackground", "control");
|
||||||
|
map.put("ToolBar.floatingBackground", "control");
|
||||||
|
map.put("ToolTip.background", "info");
|
||||||
|
map.put("ToolTip.foreground", "infoText");
|
||||||
|
map.put("Tree.background", "window");
|
||||||
|
map.put("Tree.foreground", "textText");
|
||||||
|
map.put("Tree.textForeground", "textText");
|
||||||
|
map.put("Tree.textBackground", "text");
|
||||||
|
map.put("Tree.selectionForeground", "textHighlightText");
|
||||||
|
map.put("Tree.selectionBackground", "textHighlight");
|
||||||
|
map.put("Tree.dropLineColor", "controlShadow");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public ColorValue map(GThemeValueMap values, ColorValue value) {
|
||||||
|
String id = value.getId();
|
||||||
|
String refId = map.get(id);
|
||||||
|
if (refId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
ColorValue refValue = values.getColor(refId);
|
||||||
|
if (refValue == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Color originalColor = value.get(values);
|
||||||
|
Color refColor = refValue.get(values);
|
||||||
|
if (originalColor == null || refColor == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (originalColor.getRGB() == refColor.getRGB()) {
|
||||||
|
return new ColorValue(id, refId);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -16,11 +16,11 @@
|
|||||||
package docking.theme.builtin;
|
package docking.theme.builtin;
|
||||||
|
|
||||||
import docking.theme.DiscoverableGTheme;
|
import docking.theme.DiscoverableGTheme;
|
||||||
import docking.theme.LookAndFeelType;
|
import docking.theme.LafType;
|
||||||
|
|
||||||
public class MacTheme extends DiscoverableGTheme {
|
public class MacTheme extends DiscoverableGTheme {
|
||||||
|
|
||||||
public MacTheme() {
|
public MacTheme() {
|
||||||
super("Mac OS X", LookAndFeelType.MAC);
|
super("Mac OS X", LafType.MAC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,12 @@
|
|||||||
package docking.theme.builtin;
|
package docking.theme.builtin;
|
||||||
|
|
||||||
import docking.theme.DiscoverableGTheme;
|
import docking.theme.DiscoverableGTheme;
|
||||||
import docking.theme.LookAndFeelType;
|
import docking.theme.LafType;
|
||||||
|
|
||||||
public class MetalTheme extends DiscoverableGTheme {
|
public class MetalTheme extends DiscoverableGTheme {
|
||||||
|
|
||||||
public MetalTheme() {
|
public MetalTheme() {
|
||||||
super("Metal", LookAndFeelType.METAL);
|
super("Metal", LafType.METAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,12 +16,12 @@
|
|||||||
package docking.theme.builtin;
|
package docking.theme.builtin;
|
||||||
|
|
||||||
import docking.theme.DiscoverableGTheme;
|
import docking.theme.DiscoverableGTheme;
|
||||||
import docking.theme.LookAndFeelType;
|
import docking.theme.LafType;
|
||||||
|
|
||||||
public class NimbusTheme extends DiscoverableGTheme {
|
public class NimbusTheme extends DiscoverableGTheme {
|
||||||
|
|
||||||
public NimbusTheme() {
|
public NimbusTheme() {
|
||||||
super("Nimbus", LookAndFeelType.NIMBUS);
|
super("Nimbus", LafType.NIMBUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -16,11 +16,11 @@
|
|||||||
package docking.theme.builtin;
|
package docking.theme.builtin;
|
||||||
|
|
||||||
import docking.theme.DiscoverableGTheme;
|
import docking.theme.DiscoverableGTheme;
|
||||||
import docking.theme.LookAndFeelType;
|
import docking.theme.LafType;
|
||||||
|
|
||||||
public class WindowsClassicTheme extends DiscoverableGTheme {
|
public class WindowsClassicTheme extends DiscoverableGTheme {
|
||||||
|
|
||||||
public WindowsClassicTheme() {
|
public WindowsClassicTheme() {
|
||||||
super("Windows Classic", LookAndFeelType.WINDOWS_CLASSIC);
|
super("Windows Classic", LafType.WINDOWS_CLASSIC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,11 +16,11 @@
|
|||||||
package docking.theme.builtin;
|
package docking.theme.builtin;
|
||||||
|
|
||||||
import docking.theme.DiscoverableGTheme;
|
import docking.theme.DiscoverableGTheme;
|
||||||
import docking.theme.LookAndFeelType;
|
import docking.theme.LafType;
|
||||||
|
|
||||||
public class WindowsTheme extends DiscoverableGTheme {
|
public class WindowsTheme extends DiscoverableGTheme {
|
||||||
|
|
||||||
public WindowsTheme() {
|
public WindowsTheme() {
|
||||||
super("Windows", LookAndFeelType.WINDOWS);
|
super("Windows", LafType.WINDOWS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,200 +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 docking.theme.gui;
|
|
||||||
|
|
||||||
import java.awt.*;
|
|
||||||
import java.awt.event.*;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
|
|
||||||
import docking.DialogComponentProvider;
|
|
||||||
import docking.theme.*;
|
|
||||||
import docking.widgets.combobox.GhidraComboBox;
|
|
||||||
import docking.widgets.table.GFilterTable;
|
|
||||||
import docking.widgets.table.GTable;
|
|
||||||
import ghidra.util.Swing;
|
|
||||||
import resources.Icons;
|
|
||||||
|
|
||||||
public class GThemeDialog extends DialogComponentProvider {
|
|
||||||
|
|
||||||
private ThemeColorTableModel colorTableModel;
|
|
||||||
private GThemeColorEditorDialog dialog;
|
|
||||||
|
|
||||||
public GThemeDialog() {
|
|
||||||
super("Theme Dialog", false);
|
|
||||||
addWorkPanel(createMainPanel());
|
|
||||||
addOKButton();
|
|
||||||
addCancelButton();
|
|
||||||
setOkButtonText("Save");
|
|
||||||
setPreferredSize(1100, 500);
|
|
||||||
setRememberSize(false);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void okCallback() {
|
|
||||||
for (Window window : Window.getWindows()) {
|
|
||||||
SwingUtilities.updateComponentTreeUI(window);
|
|
||||||
}
|
|
||||||
|
|
||||||
// GhidraFileChooser chooser = new GhidraFileChooser(getComponent());
|
|
||||||
// chooser.setTitle("Choose Theme File");
|
|
||||||
// chooser.setApproveButtonText("Select Output File");
|
|
||||||
// chooser.setApproveButtonToolTipText("Select File");
|
|
||||||
// chooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY);
|
|
||||||
// chooser.setSelectedFileFilter(GhidraFileFilter.ALL);
|
|
||||||
// File file = chooser.getSelectedFile();
|
|
||||||
// try {
|
|
||||||
// Gui.getActiveTheme().saveToFile(file, Gui.getAllDefaultValues());
|
|
||||||
// }
|
|
||||||
// catch (IOException e) {
|
|
||||||
// // TODO Auto-generated catch block
|
|
||||||
// e.printStackTrace();
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
private JComponent createMainPanel() {
|
|
||||||
JPanel panel = new JPanel();
|
|
||||||
|
|
||||||
panel.setLayout(new BorderLayout());
|
|
||||||
panel.add(buildControlPanel(), BorderLayout.NORTH);
|
|
||||||
panel.add(buildTabedTables());
|
|
||||||
return panel;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Component buildControlPanel() {
|
|
||||||
JPanel panel = new JPanel(new BorderLayout());
|
|
||||||
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
|
||||||
// panel.add(buildThemeChoiceButtons(), BorderLayout.WEST);
|
|
||||||
panel.add(buildThemeCombo(), BorderLayout.WEST);
|
|
||||||
panel.add(buildReloadDefaultsButton(), BorderLayout.EAST);
|
|
||||||
|
|
||||||
return panel;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Component buildReloadDefaultsButton() {
|
|
||||||
JButton button = new JButton(Icons.REFRESH_ICON);
|
|
||||||
button.addActionListener(this::reloadThemeDefaults);
|
|
||||||
button.setToolTipText("Reload Theme Defaults");
|
|
||||||
return button;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Component buildThemeCombo() {
|
|
||||||
JPanel panel = new JPanel();
|
|
||||||
Set<GTheme> supportedThemes = Gui.getSupportedThemes();
|
|
||||||
List<String> themeNames =
|
|
||||||
supportedThemes.stream().map(t -> t.getName()).collect(Collectors.toList());
|
|
||||||
Collections.sort(themeNames);
|
|
||||||
|
|
||||||
GhidraComboBox<String> combo = new GhidraComboBox<>(themeNames);
|
|
||||||
combo.setSelectedItem(Gui.getActiveTheme().getName());
|
|
||||||
combo.addItemListener(this::themeComboChanged);
|
|
||||||
|
|
||||||
panel.add(new JLabel("Theme: "), BorderLayout.WEST);
|
|
||||||
panel.add(combo);
|
|
||||||
panel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));
|
|
||||||
return panel;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Component buildThemeChoiceButtons() {
|
|
||||||
JPanel panel = new JPanel(new FlowLayout());
|
|
||||||
panel.add(createThemeButton("Flat"));
|
|
||||||
panel.add(createThemeButton("Dark Flat"));
|
|
||||||
panel.add(createThemeButton("Metal"));
|
|
||||||
panel.add(createThemeButton("Nimbus"));
|
|
||||||
panel.add(createThemeButton("GDK+"));
|
|
||||||
panel.add(createThemeButton("CDE/Motif"));
|
|
||||||
return panel;
|
|
||||||
}
|
|
||||||
|
|
||||||
private JButton createThemeButton(String name) {
|
|
||||||
JButton button = new JButton(name);
|
|
||||||
button.addActionListener(e -> Gui.setTheme(Gui.getTheme(name)));
|
|
||||||
return button;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Component buildTabedTables() {
|
|
||||||
JTabbedPane tabbedPane = new JTabbedPane();
|
|
||||||
tabbedPane.add("Colors", buildColorTable());
|
|
||||||
return tabbedPane;
|
|
||||||
}
|
|
||||||
|
|
||||||
private JComponent buildColorTable() {
|
|
||||||
colorTableModel = new ThemeColorTableModel();
|
|
||||||
|
|
||||||
GFilterTable<ColorValue> filterTable = new GFilterTable<>(colorTableModel);
|
|
||||||
GTable table = filterTable.getTable();
|
|
||||||
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
|
||||||
|
|
||||||
table.addKeyListener(new KeyAdapter() {
|
|
||||||
@Override
|
|
||||||
public void keyPressed(KeyEvent e) {
|
|
||||||
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
|
|
||||||
ColorValue colorValue = filterTable.getSelectedRowObject();
|
|
||||||
if (colorValue != null) {
|
|
||||||
editColor(colorValue);
|
|
||||||
}
|
|
||||||
e.consume();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
table.addMouseListener(new MouseAdapter() {
|
|
||||||
@Override
|
|
||||||
public void mouseClicked(MouseEvent e) {
|
|
||||||
if (e.getClickCount() == 2) {
|
|
||||||
ColorValue value = filterTable.getItemAt(e.getPoint());
|
|
||||||
editColor(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return filterTable;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void themeComboChanged(ItemEvent e) {
|
|
||||||
if (e.getStateChange() == ItemEvent.SELECTED) {
|
|
||||||
String themeName = (String) e.getItem();
|
|
||||||
Swing.runLater(() -> Gui.setTheme(Gui.getTheme(themeName)));
|
|
||||||
Swing.runLater(() -> colorTableModel.reload());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void reloadThemeDefaults(ActionEvent e) {
|
|
||||||
Gui.reloadThemeDefaults();
|
|
||||||
colorTableModel.reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void editColor(ColorValue value) {
|
|
||||||
if (dialog == null) {
|
|
||||||
dialog = new GThemeColorEditorDialog(this);
|
|
||||||
}
|
|
||||||
dialog.editColor(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void colorChangeAccepted() {
|
|
||||||
colorTableModel.reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
void colorEditorClosed() {
|
|
||||||
dialog = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
+13
-18
@@ -26,18 +26,17 @@ import docking.DockingWindowManager;
|
|||||||
import docking.options.editor.GhidraColorChooser;
|
import docking.options.editor.GhidraColorChooser;
|
||||||
import docking.theme.ColorValue;
|
import docking.theme.ColorValue;
|
||||||
import docking.theme.Gui;
|
import docking.theme.Gui;
|
||||||
import ghidra.util.Swing;
|
|
||||||
|
|
||||||
public class GThemeColorEditorDialog extends DialogComponentProvider {
|
public class ThemeColorEditorDialog extends DialogComponentProvider {
|
||||||
|
|
||||||
private ColorValue originalColorValue;
|
private ColorValue startingColorValue;
|
||||||
private ColorValue currentColorValue;
|
private ColorValue currentColorValue;
|
||||||
|
|
||||||
private GThemeDialog themeDialog;
|
private ThemeDialog themeDialog;
|
||||||
private GhidraColorChooser colorChooser;
|
private GhidraColorChooser colorChooser;
|
||||||
private ChangeListener colorChangeListener = e -> colorChanged();
|
private ChangeListener colorChangeListener = e -> colorChanged();
|
||||||
|
|
||||||
public GThemeColorEditorDialog(GThemeDialog themeDialog) {
|
public ThemeColorEditorDialog(ThemeDialog themeDialog) {
|
||||||
super("Theme Color Editor", false);
|
super("Theme Color Editor", false);
|
||||||
this.themeDialog = themeDialog;
|
this.themeDialog = themeDialog;
|
||||||
addWorkPanel(buildColorPanel());
|
addWorkPanel(buildColorPanel());
|
||||||
@@ -46,14 +45,11 @@ public class GThemeColorEditorDialog extends DialogComponentProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void editColor(ColorValue colorValue) {
|
public void editColor(ColorValue colorValue) {
|
||||||
if (currentColorValue != null && !currentColorValue.equals(originalColorValue)) {
|
this.startingColorValue = colorValue;
|
||||||
themeDialog.colorChangeAccepted();
|
|
||||||
}
|
|
||||||
this.originalColorValue = colorValue;
|
|
||||||
this.currentColorValue = colorValue;
|
this.currentColorValue = colorValue;
|
||||||
|
|
||||||
setTitle("Edit Color For: " + colorValue.getId());
|
setTitle("Edit Color For: " + colorValue.getId());
|
||||||
Color color = Gui.getRawColor(originalColorValue.getId());
|
Color color = Gui.getRawColor(startingColorValue.getId());
|
||||||
colorChooser.getSelectionModel().removeChangeListener(colorChangeListener);
|
colorChooser.getSelectionModel().removeChangeListener(colorChangeListener);
|
||||||
colorChooser.setColor(color);
|
colorChooser.setColor(color);
|
||||||
colorChooser.getSelectionModel().addChangeListener(colorChangeListener);
|
colorChooser.getSelectionModel().addChangeListener(colorChangeListener);
|
||||||
@@ -74,11 +70,8 @@ public class GThemeColorEditorDialog extends DialogComponentProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void okCallback() {
|
protected void okCallback() {
|
||||||
if (!currentColorValue.equals(originalColorValue)) {
|
|
||||||
themeDialog.colorChangeAccepted();
|
|
||||||
}
|
|
||||||
currentColorValue = null;
|
currentColorValue = null;
|
||||||
originalColorValue = null;
|
startingColorValue = null;
|
||||||
close();
|
close();
|
||||||
themeDialog.colorEditorClosed();
|
themeDialog.colorEditorClosed();
|
||||||
}
|
}
|
||||||
@@ -87,19 +80,21 @@ public class GThemeColorEditorDialog extends DialogComponentProvider {
|
|||||||
protected void cancelCallback() {
|
protected void cancelCallback() {
|
||||||
restoreOriginalColor();
|
restoreOriginalColor();
|
||||||
currentColorValue = null;
|
currentColorValue = null;
|
||||||
originalColorValue = null;
|
startingColorValue = null;
|
||||||
close();
|
close();
|
||||||
themeDialog.colorEditorClosed();
|
themeDialog.colorEditorClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void restoreOriginalColor() {
|
private void restoreOriginalColor() {
|
||||||
Gui.setColor(originalColorValue);
|
themeDialog.colorChanged(currentColorValue, startingColorValue);
|
||||||
|
currentColorValue = startingColorValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void colorChanged() {
|
private void colorChanged() {
|
||||||
Color newColor = colorChooser.getColor();
|
Color newColor = colorChooser.getColor();
|
||||||
currentColorValue = new ColorValue(originalColorValue.getId(), newColor);
|
ColorValue newColorValue = new ColorValue(startingColorValue.getId(), newColor);
|
||||||
Swing.runLater(() -> Gui.setColor(currentColorValue));
|
themeDialog.colorChanged(currentColorValue, newColorValue);
|
||||||
|
currentColorValue = newColorValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
+82
-78
@@ -28,31 +28,43 @@ import docking.widgets.table.*;
|
|||||||
import ghidra.docking.settings.Settings;
|
import ghidra.docking.settings.Settings;
|
||||||
import ghidra.framework.plugintool.ServiceProvider;
|
import ghidra.framework.plugintool.ServiceProvider;
|
||||||
import ghidra.framework.plugintool.ServiceProviderStub;
|
import ghidra.framework.plugintool.ServiceProviderStub;
|
||||||
|
import ghidra.util.ColorUtils;
|
||||||
import ghidra.util.WebColors;
|
import ghidra.util.WebColors;
|
||||||
import ghidra.util.table.column.AbstractGColumnRenderer;
|
import ghidra.util.table.column.AbstractGColumnRenderer;
|
||||||
import ghidra.util.table.column.GColumnRenderer;
|
import ghidra.util.table.column.GColumnRenderer;
|
||||||
|
|
||||||
public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, Object> {
|
public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, Object> {
|
||||||
private List<ColorValue> colors;
|
private List<ColorValue> colors;
|
||||||
private GThemeValueMap values;
|
private GThemeValueMap currentValues;
|
||||||
private GThemeValueMap coreDefaults;
|
private GThemeValueMap themeValues;
|
||||||
private GThemeValueMap darkDefaults;
|
private GThemeValueMap defaultValues;
|
||||||
|
private GThemeValueMap lightDefaultValues;
|
||||||
|
private GThemeValueMap darkDefaultValues;
|
||||||
|
|
||||||
public ThemeColorTableModel() {
|
public ThemeColorTableModel() {
|
||||||
super(new ServiceProviderStub());
|
super(new ServiceProviderStub());
|
||||||
loadValues();
|
load();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reload() {
|
public void reloadCurrent() {
|
||||||
loadValues();
|
currentValues = Gui.getAllValues();
|
||||||
|
colors = currentValues.getColors();
|
||||||
fireTableDataChanged();
|
fireTableDataChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadValues() {
|
public void reloadAll() {
|
||||||
values = Gui.getAllValues();
|
load();
|
||||||
coreDefaults = Gui.getCoreDefaults();
|
fireTableDataChanged();
|
||||||
darkDefaults = Gui.getDarkDefaults();
|
}
|
||||||
colors = values.getColors();
|
|
||||||
|
public void load() {
|
||||||
|
currentValues = Gui.getAllValues();
|
||||||
|
colors = currentValues.getColors();
|
||||||
|
themeValues = new GThemeValueMap(currentValues);
|
||||||
|
defaultValues = Gui.getDefaults();
|
||||||
|
lightDefaultValues = Gui.getGhidraLightDefaults();
|
||||||
|
darkDefaultValues = Gui.getGhidraDarkDefaults();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -69,10 +81,11 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
|
|||||||
protected TableColumnDescriptor<ColorValue> createTableColumnDescriptor() {
|
protected TableColumnDescriptor<ColorValue> createTableColumnDescriptor() {
|
||||||
TableColumnDescriptor<ColorValue> descriptor = new TableColumnDescriptor<>();
|
TableColumnDescriptor<ColorValue> descriptor = new TableColumnDescriptor<>();
|
||||||
descriptor.addVisibleColumn(new IdColumn());
|
descriptor.addVisibleColumn(new IdColumn());
|
||||||
descriptor.addVisibleColumn(new ValueColumn("Current Color", () -> values));
|
descriptor.addVisibleColumn(new ValueColumn("Current Color", () -> currentValues));
|
||||||
descriptor.addVisibleColumn(new ValueColumn("Core Defaults", () -> coreDefaults));
|
descriptor.addVisibleColumn(new ValueColumn("Theme Color", () -> themeValues));
|
||||||
descriptor.addVisibleColumn(new ValueColumn("Dark Defaults", () -> darkDefaults));
|
descriptor.addVisibleColumn(new ValueColumn("Default Color", () -> defaultValues));
|
||||||
descriptor.addVisibleColumn(new IsLafPropertyColumn());
|
descriptor.addHiddenColumn(new ValueColumn("Light Defaults", () -> lightDefaultValues));
|
||||||
|
descriptor.addHiddenColumn(new ValueColumn("Dark Defaults", () -> darkDefaultValues));
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +113,7 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ValueColumn extends AbstractDynamicTableColumn<ColorValue, ColorValue, Object> {
|
class ValueColumn extends AbstractDynamicTableColumn<ColorValue, ResolvedColor, Object> {
|
||||||
private ThemeColorRenderer renderer;
|
private ThemeColorRenderer renderer;
|
||||||
private String name;
|
private String name;
|
||||||
private Supplier<GThemeValueMap> valueSupplier;
|
private Supplier<GThemeValueMap> valueSupplier;
|
||||||
@@ -108,7 +121,7 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
|
|||||||
ValueColumn(String name, Supplier<GThemeValueMap> supplier) {
|
ValueColumn(String name, Supplier<GThemeValueMap> supplier) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.valueSupplier = supplier;
|
this.valueSupplier = supplier;
|
||||||
renderer = new ThemeColorRenderer(supplier);
|
renderer = new ThemeColorRenderer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -117,28 +130,35 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ColorValue getValue(ColorValue themeColor, Settings settings, Object data,
|
public ResolvedColor getValue(ColorValue themeColor, Settings settings, Object data,
|
||||||
ServiceProvider provider) throws IllegalArgumentException {
|
ServiceProvider provider) throws IllegalArgumentException {
|
||||||
return themeColor;
|
GThemeValueMap valueMap = valueSupplier.get();
|
||||||
|
String id = themeColor.getId();
|
||||||
|
ColorValue colorValue = valueMap.getColor(id);
|
||||||
|
if (colorValue == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Color color = colorValue.get(valueMap);
|
||||||
|
return new ResolvedColor(id, colorValue.getReferenceId(), color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GColumnRenderer<ColorValue> getColumnRenderer() {
|
public GColumnRenderer<ResolvedColor> getColumnRenderer() {
|
||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Comparator<ColorValue> getComparator() {
|
public Comparator<ResolvedColor> getComparator() {
|
||||||
return (v1, v2) -> {
|
return (v1, v2) -> {
|
||||||
GThemeValueMap valueMap = valueSupplier.get();
|
if (v1 == null && v2 == null) {
|
||||||
ColorValue v1Color = valueMap.getColor(v1.getId());
|
|
||||||
ColorValue v2Color = valueMap.getColor(v2.getId());
|
|
||||||
if (v1Color == null && v2Color == null) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (v1Color == null) {
|
if (v1 == null) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return v1Color.compareValue(v2Color);
|
if (v2 == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return ColorUtils.COMPARATOR.compare(v1.color, v2.color);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,74 +166,47 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
|
|||||||
public int getColumnPreferredWidth() {
|
public int getColumnPreferredWidth() {
|
||||||
return 300;
|
return 300;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class IsLafPropertyColumn extends AbstractDynamicTableColumn<ColorValue, Boolean, Object> {
|
private class ThemeColorRenderer extends AbstractGColumnRenderer<ResolvedColor> {
|
||||||
|
|
||||||
@Override
|
public ThemeColorRenderer() {
|
||||||
public String getColumnName() {
|
|
||||||
return "Is Laf";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean getValue(ColorValue themeColor, Settings settings, Object data,
|
|
||||||
ServiceProvider provider) throws IllegalArgumentException {
|
|
||||||
return Gui.isJavaDefinedColor(themeColor.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getColumnPreferredWidth() {
|
|
||||||
return 20;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ThemeColorRenderer extends AbstractGColumnRenderer<ColorValue> {
|
|
||||||
|
|
||||||
private Supplier<GThemeValueMap> mapSupplier;
|
|
||||||
|
|
||||||
public ThemeColorRenderer(Supplier<GThemeValueMap> mapSupplier) {
|
|
||||||
this.mapSupplier = mapSupplier;
|
|
||||||
setFont(new Font("Monospaced", Font.PLAIN, 12));
|
setFont(new Font("Monospaced", Font.PLAIN, 12));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
|
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
|
||||||
GThemeValueMap valueMap = mapSupplier.get();
|
|
||||||
JLabel label = (JLabel) super.getTableCellRendererComponent(data);
|
JLabel label = (JLabel) super.getTableCellRendererComponent(data);
|
||||||
String id = ((ColorValue) data.getValue()).getId();
|
ResolvedColor resolved = (ResolvedColor) data.getValue();
|
||||||
|
|
||||||
ColorValue colorValue = valueMap.getColor(id);
|
String text = getValueText(resolved);
|
||||||
Color color;
|
Color color = resolved == null ? GThemeDefaults.Colors.BACKGROUND : resolved.color;
|
||||||
String text;
|
|
||||||
if (colorValue != null) {
|
|
||||||
color = colorValue.get(valueMap);
|
|
||||||
if (colorValue.getReferenceId() != null) {
|
|
||||||
text = colorValue.getReferenceId();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
text = WebColors.toString(color, false);
|
|
||||||
String name = WebColors.toWebColorName(color);
|
|
||||||
if (name != null) {
|
|
||||||
text += " [" + name + "]";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
color = GThemeDefaults.Colors.BACKGROUND;
|
|
||||||
text = "<No Value>";
|
|
||||||
}
|
|
||||||
label.setText(text);
|
label.setText(text);
|
||||||
label.setIcon(new SwatchIcon(color, label.getForeground()));
|
label.setIcon(new SwatchIcon(color, label.getForeground()));
|
||||||
// label.setBackground(color);
|
|
||||||
// label.setForeground(ColorUtils.contrastForegroundColor(color));
|
|
||||||
label.setOpaque(true);
|
label.setOpaque(true);
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getValueText(ResolvedColor resolvedColor) {
|
||||||
|
if (resolvedColor == null) {
|
||||||
|
return "<No Value>";
|
||||||
|
}
|
||||||
|
if (resolvedColor.refId != null) {
|
||||||
|
return resolvedColor.refId;
|
||||||
|
}
|
||||||
|
Color color = resolvedColor.color;
|
||||||
|
String text = WebColors.toString(color, false);
|
||||||
|
String name = WebColors.toWebColorName(color);
|
||||||
|
if (name != null) {
|
||||||
|
text += " [" + name + "]";
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getFilterString(ColorValue t, Settings settings) {
|
public String getFilterString(ResolvedColor colorValue, Settings settings) {
|
||||||
return t.getId();
|
return getValueText(colorValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -244,6 +237,17 @@ public class ThemeColorTableModel extends GDynamicColumnTableModel<ColorValue, O
|
|||||||
public int getIconHeight() {
|
public int getIconHeight() {
|
||||||
return 16;
|
return 16;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ResolvedColor {
|
||||||
|
String id;
|
||||||
|
String refId;
|
||||||
|
Color color;
|
||||||
|
|
||||||
|
ResolvedColor(String id, String refId, Color color) {
|
||||||
|
this.id = id;
|
||||||
|
this.refId = refId;
|
||||||
|
this.color = color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,390 @@
|
|||||||
|
/* ###
|
||||||
|
* 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 java.awt.BorderLayout;
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.event.*;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import javax.swing.table.TableColumn;
|
||||||
|
|
||||||
|
import docking.DialogComponentProvider;
|
||||||
|
import docking.DockingWindowManager;
|
||||||
|
import docking.theme.*;
|
||||||
|
import docking.widgets.OptionDialog;
|
||||||
|
import docking.widgets.combobox.GhidraComboBox;
|
||||||
|
import docking.widgets.dialogs.InputDialog;
|
||||||
|
import docking.widgets.table.GFilterTable;
|
||||||
|
import docking.widgets.table.GTable;
|
||||||
|
import ghidra.framework.Application;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
import ghidra.util.Swing;
|
||||||
|
import resources.Icons;
|
||||||
|
|
||||||
|
public class ThemeDialog extends DialogComponentProvider {
|
||||||
|
private static ThemeDialog INSTANCE;
|
||||||
|
private ThemeColorTableModel colorTableModel;
|
||||||
|
private ThemeColorEditorDialog dialog;
|
||||||
|
|
||||||
|
// stores the original value for ids whose value has changed
|
||||||
|
private GThemeValueMap changedValuesMap = new GThemeValueMap();
|
||||||
|
private JButton saveButton;
|
||||||
|
private JButton restoreButton;
|
||||||
|
private GhidraComboBox<String> combo;
|
||||||
|
private ItemListener comboListener = this::themeComboChanged;
|
||||||
|
|
||||||
|
public ThemeDialog() {
|
||||||
|
super("Theme Dialog", false);
|
||||||
|
addWorkPanel(createMainPanel());
|
||||||
|
|
||||||
|
addDismissButton();
|
||||||
|
addButton(createSaveButton());
|
||||||
|
addButton(createRestoreButton());
|
||||||
|
|
||||||
|
setPreferredSize(1100, 500);
|
||||||
|
setRememberSize(false);
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void dismissCallback() {
|
||||||
|
if (hasChanges()) {
|
||||||
|
int result = OptionDialog.showYesNoCancelDialog(null, "Close Theme Dialog",
|
||||||
|
"You have changed the theme.\n Do you want save your changes?");
|
||||||
|
if (result == OptionDialog.CANCEL_OPTION) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result == OptionDialog.YES_OPTION) {
|
||||||
|
if (!save()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Gui.reloadGhidraDefaults();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
INSTANCE = null;
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void saveCallback() {
|
||||||
|
save();
|
||||||
|
updateCombo();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void restoreCallback() {
|
||||||
|
if (hasChanges()) {
|
||||||
|
int result = OptionDialog.showYesNoDialog(null, "Restore Theme Values",
|
||||||
|
"Are you sure you want to discard all your changes?");
|
||||||
|
if (result == OptionDialog.NO_OPTION) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Gui.restoreThemeValues();
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reloadDefaultsCallback(ActionEvent e) {
|
||||||
|
if (hasChanges()) {
|
||||||
|
int result = OptionDialog.showYesNoDialog(null, "Reload Ghidra Default Values",
|
||||||
|
"This will discard all your theme changes. Continue?");
|
||||||
|
if (result == OptionDialog.NO_OPTION) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Gui.reloadGhidraDefaults();
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reset() {
|
||||||
|
changedValuesMap.clear();
|
||||||
|
colorTableModel.reloadAll();
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves all current theme changes
|
||||||
|
* @return true if the operation was not cancelled.
|
||||||
|
*/
|
||||||
|
private boolean save() {
|
||||||
|
GTheme activeTheme = Gui.getActiveTheme();
|
||||||
|
if (activeTheme instanceof FileGTheme) {
|
||||||
|
FileGTheme fileTheme = (FileGTheme) activeTheme;
|
||||||
|
if (fileTheme.canSave()) {
|
||||||
|
int result = OptionDialog.showYesNoCancelDialog(null, "Overwrite Existing Theme",
|
||||||
|
"Do you want to overwrite the existing theme file?");
|
||||||
|
if (result == OptionDialog.CANCEL_OPTION) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (result == OptionDialog.YES_OPTION) {
|
||||||
|
return saveCurrentValuesToTheme(fileTheme, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// save to new Theme file
|
||||||
|
|
||||||
|
InputDialog inputDialog = new InputDialog("Create Theme", "New Theme Name");
|
||||||
|
DockingWindowManager.showDialog(inputDialog);
|
||||||
|
String themeName = inputDialog.getValue();
|
||||||
|
if (themeName == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
File file = getSaveFile(themeName);
|
||||||
|
LafType laf = activeTheme.getLookAndFeelType();
|
||||||
|
return saveCurrentValuesToTheme(new FileGTheme(file, themeName, laf), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean saveCurrentValuesToTheme(FileGTheme newTheme, boolean includeDefaults) {
|
||||||
|
newTheme.clear();
|
||||||
|
GThemeValueMap allValues = Gui.getAllValues();
|
||||||
|
if (includeDefaults) {
|
||||||
|
newTheme.load(allValues);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Gui.getAllValues();
|
||||||
|
newTheme.load(allValues.removeSameValues(Gui.getDefaults()));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
newTheme.save();
|
||||||
|
Gui.addTheme(newTheme);
|
||||||
|
Gui.setTheme(newTheme);
|
||||||
|
}
|
||||||
|
catch (IOException e) {
|
||||||
|
Msg.showError(this, null, "I/O Error",
|
||||||
|
"Error writing theme file: " + newTheme.getFile().getAbsolutePath(), e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private File getSaveFile(String themeName) {
|
||||||
|
File dir = Application.getUserSettingsDirectory();
|
||||||
|
String cleanedName = themeName.replaceAll(" ", "_") + GTheme.FILE_EXTENSION;
|
||||||
|
return new File(dir, cleanedName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// private void export() {
|
||||||
|
// GhidraFileChooser chooser = new GhidraFileChooser(getComponent());
|
||||||
|
// chooser.setTitle("Choose Theme File");
|
||||||
|
// chooser.setApproveButtonText("Select Output File");
|
||||||
|
// chooser.setApproveButtonToolTipText("Select File");
|
||||||
|
// chooser.setFileSelectionMode(GhidraFileChooserMode.FILES_ONLY);
|
||||||
|
// chooser.setSelectedFileFilter(GhidraFileFilter.ALL);
|
||||||
|
// File file = chooser.getSelectedFile();
|
||||||
|
// try {
|
||||||
|
// Gui.getActiveTheme().saveToFile(file, Gui.getDefaults());
|
||||||
|
// return true;
|
||||||
|
// }
|
||||||
|
// catch (IOException e) {
|
||||||
|
// // TODO Auto-generated catch block
|
||||||
|
// e.printStackTrace();
|
||||||
|
// }
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
private void themeComboChanged(ItemEvent e) {
|
||||||
|
if (e.getStateChange() == ItemEvent.SELECTED) {
|
||||||
|
String themeName = (String) e.getItem();
|
||||||
|
if (hasChanges()) {
|
||||||
|
Msg.debug(this, "has changes");
|
||||||
|
}
|
||||||
|
Swing.runLater(() -> {
|
||||||
|
Gui.setTheme(Gui.getTheme(themeName));
|
||||||
|
changedValuesMap.clear();
|
||||||
|
colorTableModel.reloadAll();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasChanges() {
|
||||||
|
return !changedValuesMap.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void editColor(ColorValue value) {
|
||||||
|
if (dialog == null) {
|
||||||
|
dialog = new ThemeColorEditorDialog(this);
|
||||||
|
}
|
||||||
|
dialog.editColor(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void colorChanged(ColorValue oldValue, ColorValue newValue) {
|
||||||
|
updateChanagedValueMap(oldValue, newValue);
|
||||||
|
// run later - don't rock the boat in the middle of a listener callback
|
||||||
|
Swing.runLater(() -> {
|
||||||
|
Gui.setColor(newValue);
|
||||||
|
colorTableModel.reloadCurrent();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateChanagedValueMap(ColorValue oldValue, ColorValue newValue) {
|
||||||
|
ColorValue originalValue = changedValuesMap.getColor(oldValue.getId());
|
||||||
|
if (originalValue == null) {
|
||||||
|
changedValuesMap.addColor(oldValue);
|
||||||
|
}
|
||||||
|
else if (originalValue.equals(newValue)) {
|
||||||
|
// if restoring the original color, remove it from the map of changes
|
||||||
|
changedValuesMap.removeColor(oldValue.getId());
|
||||||
|
}
|
||||||
|
updateButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateButtons() {
|
||||||
|
boolean hasChanges = hasChanges();
|
||||||
|
saveButton.setEnabled(hasChanges);
|
||||||
|
restoreButton.setEnabled(hasChanges);
|
||||||
|
}
|
||||||
|
|
||||||
|
void colorEditorClosed() {
|
||||||
|
dialog = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JComponent createMainPanel() {
|
||||||
|
JPanel panel = new JPanel();
|
||||||
|
|
||||||
|
panel.setLayout(new BorderLayout());
|
||||||
|
panel.add(buildControlPanel(), BorderLayout.NORTH);
|
||||||
|
panel.add(buildTabedTables());
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Component buildControlPanel() {
|
||||||
|
JPanel panel = new JPanel(new BorderLayout());
|
||||||
|
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
|
||||||
|
panel.add(buildThemeCombo(), BorderLayout.WEST);
|
||||||
|
panel.add(buildReloadDefaultsButton(), BorderLayout.EAST);
|
||||||
|
panel.setName("gthemePanel");
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Component buildReloadDefaultsButton() {
|
||||||
|
JButton button = new JButton(Icons.REFRESH_ICON);
|
||||||
|
button.addActionListener(this::reloadDefaultsCallback);
|
||||||
|
button.setToolTipText(
|
||||||
|
"Reload Ghidra Defaults (Only needed if you change a theme.properties file)");
|
||||||
|
return button;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateCombo() {
|
||||||
|
Set<GTheme> supportedThemes = Gui.getSupportedThemes();
|
||||||
|
List<String> themeNames =
|
||||||
|
supportedThemes.stream().map(t -> t.getName()).collect(Collectors.toList());
|
||||||
|
Collections.sort(themeNames);
|
||||||
|
combo.removeItemListener(comboListener);
|
||||||
|
combo.setModel(new DefaultComboBoxModel<String>(new Vector<String>(themeNames)));
|
||||||
|
combo.setSelectedItem(Gui.getActiveTheme().getName());
|
||||||
|
combo.addItemListener(comboListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Component buildThemeCombo() {
|
||||||
|
JPanel panel = new JPanel();
|
||||||
|
Set<GTheme> supportedThemes = Gui.getSupportedThemes();
|
||||||
|
List<String> themeNames =
|
||||||
|
supportedThemes.stream().map(t -> t.getName()).collect(Collectors.toList());
|
||||||
|
Collections.sort(themeNames);
|
||||||
|
|
||||||
|
combo = new GhidraComboBox<>(themeNames);
|
||||||
|
combo.setSelectedItem(Gui.getActiveTheme().getName());
|
||||||
|
combo.addItemListener(comboListener);
|
||||||
|
|
||||||
|
panel.add(new JLabel("Theme: "), BorderLayout.WEST);
|
||||||
|
panel.add(combo);
|
||||||
|
panel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));
|
||||||
|
return panel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Component buildTabedTables() {
|
||||||
|
JTabbedPane tabbedPane = new JTabbedPane();
|
||||||
|
tabbedPane.add("Colors", buildColorTable());
|
||||||
|
return tabbedPane;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JComponent buildColorTable() {
|
||||||
|
colorTableModel = new ThemeColorTableModel();
|
||||||
|
|
||||||
|
GFilterTable<ColorValue> filterTable = new GFilterTable<>(colorTableModel);
|
||||||
|
GTable table = filterTable.getTable();
|
||||||
|
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||||
|
|
||||||
|
table.addKeyListener(new KeyAdapter() {
|
||||||
|
@Override
|
||||||
|
public void keyPressed(KeyEvent e) {
|
||||||
|
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
|
||||||
|
ColorValue colorValue = filterTable.getSelectedRowObject();
|
||||||
|
if (colorValue != null) {
|
||||||
|
editColor(colorValue);
|
||||||
|
}
|
||||||
|
e.consume();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
table.addMouseListener(new MouseAdapter() {
|
||||||
|
@Override
|
||||||
|
public void mouseClicked(MouseEvent e) {
|
||||||
|
if (e.getClickCount() == 2) {
|
||||||
|
ColorValue value = filterTable.getItemAt(e.getPoint());
|
||||||
|
Object cellValue = filterTable.getCellValue(e.getPoint());
|
||||||
|
// editColor(value);
|
||||||
|
|
||||||
|
int col = filterTable.getColumn(e.getPoint());
|
||||||
|
TableColumn column = table.getColumnModel().getColumn(col);
|
||||||
|
Object identifier = column.getIdentifier();
|
||||||
|
if ("Current Color".equals(identifier) || "Id".equals(identifier)) {
|
||||||
|
editColor(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return filterTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JButton createRestoreButton() {
|
||||||
|
restoreButton = new JButton("Restore");
|
||||||
|
restoreButton.setMnemonic('R');
|
||||||
|
restoreButton.setName("Restore");
|
||||||
|
restoreButton.addActionListener(e -> restoreCallback());
|
||||||
|
restoreButton.setToolTipText("Restores all values to current theme");
|
||||||
|
return restoreButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
private JButton createSaveButton() {
|
||||||
|
saveButton = new JButton("Save");
|
||||||
|
saveButton.setMnemonic('S');
|
||||||
|
saveButton.setName("Save");
|
||||||
|
saveButton.addActionListener(e -> saveCallback());
|
||||||
|
saveButton.setToolTipText("Saves changed values to a new Theme");
|
||||||
|
return saveButton;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void editTheme() {
|
||||||
|
if (INSTANCE != null) {
|
||||||
|
INSTANCE.toFront();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
INSTANCE = new ThemeDialog();
|
||||||
|
DockingWindowManager.showDialog(INSTANCE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+8
-11
@@ -16,25 +16,22 @@
|
|||||||
package docking.theme.laf;
|
package docking.theme.laf;
|
||||||
|
|
||||||
import javax.swing.UIManager;
|
import javax.swing.UIManager;
|
||||||
import javax.swing.UnsupportedLookAndFeelException;
|
|
||||||
|
|
||||||
import com.formdev.flatlaf.FlatLaf;
|
import docking.theme.LafType;
|
||||||
|
|
||||||
public class FlatLookAndFeelInstaller extends LookAndFeelInstaller {
|
public class FlatLookAndFeelInstaller extends LookAndFeelInstaller {
|
||||||
private FlatLaf lookAndFeel;
|
|
||||||
|
|
||||||
public FlatLookAndFeelInstaller(FlatLaf lookAndFeel) {
|
public FlatLookAndFeelInstaller(LafType lookAndFeelType) {
|
||||||
this.lookAndFeel = lookAndFeel;
|
super(lookAndFeelType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void installLookAndFeel() throws UnsupportedLookAndFeelException {
|
protected void fixupLookAndFeelIssues() {
|
||||||
UIManager.setLookAndFeel(lookAndFeel);
|
super.fixupLookAndFeelIssues();
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
// We have historically managed button focusability ourselves. Allow this by default so
|
||||||
public boolean isSupportedForCurrentPlatform() {
|
// features continue to work as expected, such as right-clicking on ToolButtons.
|
||||||
return true;
|
UIManager.put("ToolBar.focusableButtons", Boolean.TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-53
@@ -15,68 +15,29 @@
|
|||||||
*/
|
*/
|
||||||
package docking.theme.laf;
|
package docking.theme.laf;
|
||||||
|
|
||||||
import java.awt.Color;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.plaf.synth.SynthLookAndFeel;
|
|
||||||
|
|
||||||
import docking.theme.*;
|
import docking.theme.LafType;
|
||||||
import ghidra.docking.util.LookAndFeelUtils;
|
|
||||||
|
|
||||||
public class GTKLookAndFeelInstaller extends LookAndFeelInstaller {
|
public class GTKLookAndFeelInstaller extends LookAndFeelInstaller {
|
||||||
|
|
||||||
|
public GTKLookAndFeelInstaller() {
|
||||||
|
super(LafType.GTK);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void installJavaDefaults() {
|
protected void installLookAndFeel() throws ClassNotFoundException, InstantiationException,
|
||||||
// do nothing - already handled by wrapped GTK lookAndFeel
|
IllegalAccessException, UnsupportedLookAndFeelException {
|
||||||
|
|
||||||
|
super.installLookAndFeel();
|
||||||
|
LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
|
||||||
|
WrappingLookAndFeel wrappingLookAndFeel = new WrappingLookAndFeel(lookAndFeel);
|
||||||
|
UIManager.setLookAndFeel(wrappingLookAndFeel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void installLookAndFeel() throws UnsupportedLookAndFeelException {
|
protected void installJavaDefaults() {
|
||||||
String name = LookAndFeelType.GTK.getName();
|
// handled by WrappingLookAndFeel
|
||||||
try {
|
|
||||||
UIManager.setLookAndFeel(findLookAndFeelClassName(name));
|
|
||||||
LookAndFeel gtk = UIManager.getLookAndFeel();
|
|
||||||
UIManager.setLookAndFeel(new WrappingLookAndFeel(gtk));
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
throw new UnsupportedLookAndFeelException(name + " not supported on this platform");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSupportedForCurrentPlatform() {
|
|
||||||
return isSupported(LookAndFeelType.GTK.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extends the NimbusLookAndFeel to intercept the {@link #getDefaults()}. To get Nimbus
|
|
||||||
* to use our indirect values, we have to get in early.
|
|
||||||
*/
|
|
||||||
static class ExtendedGTKLookAndFeel extends SynthLookAndFeel {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UIDefaults getDefaults() {
|
|
||||||
GThemeValueMap javaDefaults = new GThemeValueMap();
|
|
||||||
|
|
||||||
UIDefaults defaults = super.getDefaults();
|
|
||||||
List<String> colorIds =
|
|
||||||
LookAndFeelUtils.getLookAndFeelIdsForType(defaults, Color.class);
|
|
||||||
for (String id : colorIds) {
|
|
||||||
Color color = defaults.getColor(id);
|
|
||||||
ColorValue value = new ColorValue(id, color);
|
|
||||||
javaDefaults.addColor(value);
|
|
||||||
}
|
|
||||||
Gui.setJavaDefaults(javaDefaults);
|
|
||||||
for (String id : colorIds) {
|
|
||||||
defaults.put(id, Gui.getGColorUiResource(id));
|
|
||||||
}
|
|
||||||
// javaDefaults.addColor(new ColorValue("Label.textForground", "Label.foreground"));
|
|
||||||
defaults.put("Label.textForeground", Gui.getGColorUiResource("Label.foreground"));
|
|
||||||
GColor.refreshAll();
|
|
||||||
return defaults;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+81
-38
@@ -22,15 +22,37 @@ import java.util.Map.Entry;
|
|||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.UIManager.LookAndFeelInfo;
|
import javax.swing.UIManager.LookAndFeelInfo;
|
||||||
import javax.swing.plaf.UIResource;
|
|
||||||
|
|
||||||
import docking.theme.*;
|
import docking.theme.*;
|
||||||
import ghidra.docking.util.LookAndFeelUtils;
|
import ghidra.docking.util.LookAndFeelUtils;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
|
|
||||||
public abstract class LookAndFeelInstaller {
|
/**
|
||||||
|
* Installs a specific {@link LookAndFeel} into the {@link UIManager}. The idea is that there
|
||||||
|
* is a specific installer for each supported {@link LookAndFeel} to handle unique needs for
|
||||||
|
* that LookAndFeel. Subclasses can also override {@link #fixupLookAndFeelIssues()} to make
|
||||||
|
* UI tweaks to specific LookAndFeels.
|
||||||
|
*/
|
||||||
|
public class LookAndFeelInstaller {
|
||||||
|
|
||||||
public void install() throws Exception {
|
private LafType lookAndFeel;
|
||||||
|
|
||||||
|
public LookAndFeelInstaller(LafType lookAndFeel) {
|
||||||
|
this.lookAndFeel = lookAndFeel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs the {@link LookAndFeel} associated with this installer
|
||||||
|
* @throws ClassNotFoundException if the <code>LookAndFeel</code>
|
||||||
|
* class could not be found
|
||||||
|
* @throws InstantiationException if a new instance of the class
|
||||||
|
* couldn't be created
|
||||||
|
* @throws IllegalAccessException if the class or initializer isn't accessible
|
||||||
|
* @throws UnsupportedLookAndFeelException if
|
||||||
|
* <code>lnf.isSupportedLookAndFeel()</code> is false
|
||||||
|
*/
|
||||||
|
public void install() throws ClassNotFoundException, InstantiationException,
|
||||||
|
IllegalAccessException, UnsupportedLookAndFeelException {
|
||||||
cleanUiDefaults();
|
cleanUiDefaults();
|
||||||
installLookAndFeel();
|
installLookAndFeel();
|
||||||
installJavaDefaults();
|
installJavaDefaults();
|
||||||
@@ -38,21 +60,34 @@ public abstract class LookAndFeelInstaller {
|
|||||||
installGlobalProperties();
|
installGlobalProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void installGlobalProperties() {
|
/**
|
||||||
installGlobalLookAndFeelAttributes();
|
* Subclass provide this method to install the specific loo
|
||||||
installGlobalFontSizeOverride();
|
* @throws ClassNotFoundException if the <code>LookAndFeel</code>
|
||||||
installCustomLookAndFeelActions();
|
* class could not be found
|
||||||
installPopupMenuSettingsOverride();
|
* @throws InstantiationException if a new instance of the class
|
||||||
|
* couldn't be created
|
||||||
|
* @throws IllegalAccessException if the class or initializer isn't accessible
|
||||||
|
* @throws UnsupportedLookAndFeelException if
|
||||||
|
* <code>lnf.isSupportedLookAndFeel()</code> is false
|
||||||
|
*/
|
||||||
|
protected void installLookAndFeel() throws ClassNotFoundException, InstantiationException,
|
||||||
|
IllegalAccessException, UnsupportedLookAndFeelException {
|
||||||
|
String name = lookAndFeel.getName();
|
||||||
|
UIManager.setLookAndFeel(findLookAndFeelClassName(name));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract boolean isSupportedForCurrentPlatform();
|
/**
|
||||||
|
* Subclass can override this method to do specific LookAndFeel fix ups
|
||||||
protected abstract void installLookAndFeel() throws Exception;
|
*/
|
||||||
|
|
||||||
protected void fixupLookAndFeelIssues() {
|
protected void fixupLookAndFeelIssues() {
|
||||||
// no generic fix-ups at this time.
|
// no generic fix-ups at this time.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs GColors into the UIDefaults. Subclasses my override this if they need to install
|
||||||
|
* GColors in a different way.
|
||||||
|
*/
|
||||||
protected void installJavaDefaults() {
|
protected void installJavaDefaults() {
|
||||||
GThemeValueMap javaDefaults = extractJavaDefaults();
|
GThemeValueMap javaDefaults = extractJavaDefaults();
|
||||||
Gui.setJavaDefaults(javaDefaults);
|
Gui.setJavaDefaults(javaDefaults);
|
||||||
@@ -82,36 +117,14 @@ public abstract class LookAndFeelInstaller {
|
|||||||
List<String> ids =
|
List<String> ids =
|
||||||
LookAndFeelUtils.getLookAndFeelIdsForType(UIManager.getDefaults(), Color.class);
|
LookAndFeelUtils.getLookAndFeelIdsForType(UIManager.getDefaults(), Color.class);
|
||||||
for (String id : ids) {
|
for (String id : ids) {
|
||||||
values.addColor(new ColorValue(id, getNonUiColor(id)));
|
// only use standard java colors here to avoid weird issues (such as GColor not
|
||||||
|
// resolving or ColorUIResource not being honored. Later we will go back
|
||||||
|
// and fix up the java defaults to use standard java color indirection
|
||||||
|
values.addColor(new ColorValue(id, getNormalizedColor(UIManager.getColor(id))));
|
||||||
}
|
}
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Color getNonUiColor(String id) {
|
|
||||||
// Not sure, but for now, make sure colors are not UIResource
|
|
||||||
Color color = UIManager.getColor(id);
|
|
||||||
if (color instanceof UIResource) {
|
|
||||||
return new Color(color.getRGB(), true);
|
|
||||||
}
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void cleanUiDefaults() {
|
|
||||||
GThemeValueMap javaDefaults = Gui.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);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String findLookAndFeelClassName(String lookAndFeelName) {
|
protected String findLookAndFeelClassName(String lookAndFeelName) {
|
||||||
LookAndFeelInfo[] installedLookAndFeels = UIManager.getInstalledLookAndFeels();
|
LookAndFeelInfo[] installedLookAndFeels = UIManager.getInstalledLookAndFeels();
|
||||||
for (LookAndFeelInfo info : installedLookAndFeels) {
|
for (LookAndFeelInfo info : installedLookAndFeels) {
|
||||||
@@ -233,4 +246,34 @@ public abstract class LookAndFeelInstaller {
|
|||||||
inputMap.put(keyStroke, action);
|
inputMap.put(keyStroke, action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void installGlobalProperties() {
|
||||||
|
installGlobalLookAndFeelAttributes();
|
||||||
|
installGlobalFontSizeOverride();
|
||||||
|
installCustomLookAndFeelActions();
|
||||||
|
installPopupMenuSettingsOverride();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Color getNormalizedColor(Color color) {
|
||||||
|
if (color.getClass() == Color.class) {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
return new Color(color.getRGB(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cleanUiDefaults() {
|
||||||
|
GThemeValueMap javaDefaults = Gui.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);
|
||||||
|
// }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +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 docking.theme.laf;
|
|
||||||
|
|
||||||
import javax.swing.UIManager;
|
|
||||||
|
|
||||||
import docking.theme.LookAndFeelType;
|
|
||||||
|
|
||||||
public class MacLookAndFeelInstaller extends LookAndFeelInstaller {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSupportedForCurrentPlatform() {
|
|
||||||
return isSupported(LookAndFeelType.MAC.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void installLookAndFeel() throws Exception {
|
|
||||||
String name = LookAndFeelType.MAC.getName();
|
|
||||||
UIManager.setLookAndFeel(findLookAndFeelClassName(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
-34
@@ -1,34 +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 docking.theme.laf;
|
|
||||||
|
|
||||||
import javax.swing.UIManager;
|
|
||||||
import javax.swing.UnsupportedLookAndFeelException;
|
|
||||||
import javax.swing.plaf.metal.MetalLookAndFeel;
|
|
||||||
|
|
||||||
public class MetalLookAndFeelInstaller extends LookAndFeelInstaller {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void installLookAndFeel() throws UnsupportedLookAndFeelException {
|
|
||||||
UIManager.setLookAndFeel(new MetalLookAndFeel());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isSupportedForCurrentPlatform() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user