GP-1981 added quick font adjust action, cleaned up tempColorUtils

and converted File extension icons file to use theming
This commit is contained in:
ghidragon 2022-10-13 14:08:35 -04:00
parent 45395d7575
commit c86b884daf
51 changed files with 513 additions and 477 deletions

View file

@ -1,60 +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 ghidra.util;
import java.awt.Color;
import java.util.HashMap;
import java.util.Map;
import javax.swing.*;
import javax.swing.border.Border;
public class UIManagerWrapper {
private static Map<String, Color> colorMap = new HashMap<>();
private static Map<String, Border> borderMap = new HashMap<>();
static {
colorMap.put("Table[Enabled+Selected].textForeground", new Color(255, 255, 255));
colorMap.put("Table[Enabled+Selected].textBackground", new Color(57, 105, 138));
colorMap.put("Table.textForeground", new Color(35, 35, 36));
colorMap.put("Table.alternateRowColor", new Color(237, 243, 254));
colorMap.put("Table:\"Table.cellRenderer\".background", new Color(255, 255, 255));
borderMap.put("Table.focusCellHighlightBorder",
BorderFactory.createEmptyBorder(2, 5, 2, 5));
borderMap.put("Table.cellNoFocusBorder", BorderFactory.createEmptyBorder(2, 5, 2, 5));
}
public static Color getColor(String text) {
UIDefaults uiDefaults = UIManager.getDefaults();
Color color = uiDefaults.getColor(text);
if (color == null) {
color = colorMap.get(text);
}
return color;
}
public static Border getBorder(String text) {
UIDefaults uiDefaults = UIManager.getDefaults();
Border border = uiDefaults.getBorder(text);
if (border == null) {
border = borderMap.get(text);
}
return border;
}
}

View file

@ -41,7 +41,7 @@ import com.google.common.collect.Iterators;
import db.DBHandle;
import db.DBRecord;
import generic.theme.GThemeDefaults.Colors.Palette;
import generic.theme.TempColorUtils;
import ghidra.util.ColorUtils;
import ghidra.util.LockHold;
import ghidra.util.database.*;
import ghidra.util.database.annot.*;
@ -566,13 +566,13 @@ public class RStarTreeMapTest {
public void selectColor(Graphics g, NodeType type) {
if (type.isLeaf()) {
g.setColor(TempColorUtils.fromRgba(179, 0, 0, 128));
g.setColor(ColorUtils.getColor(179, 0, 0, 128));
}
else if (type.isLeafParent()) {
g.setColor(TempColorUtils.fromRgba(0, 179, 0, 128));
g.setColor(ColorUtils.getColor(0, 179, 0, 128));
}
else {
g.setColor(TempColorUtils.fromRgba(0, 0, 179, 128));
g.setColor(ColorUtils.getColor(0, 0, 179, 128));
}
}
@ -610,7 +610,7 @@ public class RStarTreeMapTest {
@Override
protected VisitResult visitData(DBIntRectNodeRecord parent,
DBIntRectStringDataRecord d, boolean included) {
g.setColor(TempColorUtils.fromRgba(0, 0, 0, 128));
g.setColor(ColorUtils.getColor(0, 0, 0, 128));
drawRect(g, d.getShape(), true);
return VisitResult.NEXT;
}
@ -876,7 +876,6 @@ public class RStarTreeMapTest {
List<Pair<IntRect, String>> entries = generateRandom(rect(0, 100, 0, 100), 10, 10, 1000);
Consumer<List<Pair<IntRect, String>>> inserter = list -> {
try (UndoableTransaction tid = UndoableTransaction.start(obj, "AddRandom")) {
int i = 0;
for (Entry<IntRect, String> ent : list) {
obj.map.put(ent.getKey(), ent.getValue());
// Note, underlying tree is not synchronized, but map is

View file

@ -81,6 +81,7 @@ data/symbols/win64/mfc80u.exports||GHIDRA||||END|
data/symbols/win64/mfc90.exports||GHIDRA||||END|
data/symbols/win64/mfc90u.exports||GHIDRA||||END|
data/symbols/win64/msvcrt.hints||GHIDRA||||END|
data/typeinfo/file.extensions.icons.theme.properties||GHIDRA||||END|
data/typeinfo/generic/generic_clib.gdt||GHIDRA||||END|
data/typeinfo/generic/generic_clib_64.gdt||GHIDRA||||END|
data/typeinfo/mac_10.9/mac_osx.gdt||GHIDRA||||END|

View file

@ -48,7 +48,6 @@ icon.plugin.bookmark.type.error = icon.base.delete
icon.plugin.bookmark.type.analysis = applications-system.png
icon.plugin.bookmark.type.default = unknown.gif
icon.plugin.calltree.provider =
icon.plugin.calltree.function = FunctionScope.gif
icon.plugin.calltree.recursive = arrow_rotate_clockwise.png
icon.plugin.calltree.refresh = icon.refresh

View file

@ -0,0 +1,43 @@
[Defaults]
// Only single level file exts supported right now
icon.fsbrowser.file.extension.default = images/famfamfam_silk_icons_v013/page_white.png
icon.fsbrowser.file.extension.apk = images/famfamfam_silk_icons_v013/package.png
icon.fsbrowser.file.extension.c = images/text-x-csrc.png
icon.fsbrowser.file.extension.cpp = images/oxygen/16x16/text-x-c++src.png
icon.fsbrowser.file.extension.class = images/famfamfam_silk_icons_v013/cup.png
icon.fsbrowser.file.extension.cs = images/oxygen/16x16/text-x-csharp.png
icon.fsbrowser.file.extension.css = images/famfamfam_silk_icons_v013/css.png
icon.fsbrowser.file.extension.data = images/famfamfam_silk_icons_v013/database.png
icon.fsbrowser.file.extension.dfu = images/famfamfam_silk_icons_v013/bullet_blue.png
icon.fsbrowser.file.extension.dmg = images/famfamfam_silk_icons_v013/bullet_green.png
icon.fsbrowser.file.extension.f = images/F.gif
icon.fsbrowser.file.extension.h = images/oxygen/16x16/text-x-chdr.png
icon.fsbrowser.file.extension.html = images/famfamfam_silk_icons_v013/html.png
icon.fsbrowser.file.extension.img = images/famfamfam_silk_icons_v013/images.png
icon.fsbrowser.file.extension.img3 = images/famfamfam_silk_icons_v013/bullet_orange.png
icon.fsbrowser.file.extension.index = images/oxygen/16x16/bookmarks.png
icon.fsbrowser.file.extension.ipsw = images/oxygen/16x16/multimedia-player-apple-ipod.png
icon.fsbrowser.file.extension.iso = images/nuvola/16x16/cdimage.png
icon.fsbrowser.file.extension.jar = images/oxygen/16x16/application-x-java-archive.png
icon.fsbrowser.file.extension.java = images/famfamfam_silk_icons_v013/page_white_cup.png
icon.fsbrowser.file.extension.kext = images/famfamfam_silk_icons_v013/bullet_pink.png
icon.fsbrowser.file.extension.lib = images/famfamfam_silk_icons_v013/server.png
icon.fsbrowser.file.extension.obj = images/oxygen/16x16/application-x-subrip.png
icon.fsbrowser.file.extension.p = images/oxygen/16x16/text-x-pascal.png
icon.fsbrowser.file.extension.pdf = images/oxygen/16x16/application-pdf.png
icon.fsbrowser.file.extension.plist = images/oxygen/16x16/insert-table.png
icon.fsbrowser.file.extension.png = images/famfamfam_silk_icons_v013/bullet_red.png
icon.fsbrowser.file.extension.rss = images/famfamfam_silk_icons_v013/rss.png
icon.fsbrowser.file.extension.strings = images/oxygen/16x16/insert-text.png
icon.fsbrowser.file.extension.txt = images/oxygen/16x16/text-x-bibtex.png
icon.fsbrowser.file.extension.usb = images/nuvola/16x16/usb.png
icon.fsbrowser.file.extension.xhtml = images/famfamfam_silk_icons_v013/xhtml.png
icon.fsbrowser.file.extension.xml = images/oxygen/16x16/text-xml.png
icon.fsbrowser.file.extension.zip = images/oxygen/16x16/application-x-bzip.png
icon.fsbrowser.file.substring.release. = images/famfamfam_silk_icons_v013/bullet_purple.png
icon.fsbrowser.file.overlay.imported = images/checkmark_green.gif
icon.fsbrowser.file.overlay.filesystem = EMPTY_ICON{images/nuvola/16x16/ledgreen.png[size(8,8)][move(8,8)]} // lower right quadrant
icon.fsbrowser.file.overlay.missing.password = EMPTY_ICON{images/lock.png[size(8,8)][move(8,0)]} // upper right quadrant

View file

@ -48,6 +48,7 @@ import ghidra.app.util.viewer.field.FieldFactory;
import ghidra.app.util.viewer.format.*;
import ghidra.app.util.viewer.listingpanel.*;
import ghidra.app.util.viewer.multilisting.MultiListingLayoutModel;
import ghidra.app.util.viewer.options.ListingDisplayOptionsEditor;
import ghidra.app.util.viewer.util.FieldNavigator;
import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.NavigatableComponentProviderAdapter;
@ -128,7 +129,7 @@ public class CodeViewerProvider extends NavigatableComponentProviderAdapter
// note: the owner has not changed, just the name; remove sometime after version 10
String owner = plugin.getName();
ComponentProvider.registerProviderNameOwnerChange(OLD_NAME, owner, NAME, owner);
registerAdjustableFontId(ListingDisplayOptionsEditor.DEFAULT_FONT_ID);
setConnected(isConnected);
setIcon(new GIcon("icon.plugin.codebrowser.provider"));
if (!isConnected) {

View file

@ -18,9 +18,9 @@ package ghidra.app.plugin.core.codebrowser;
import java.awt.Color;
import java.math.BigInteger;
import generic.theme.TempColorUtils;
import ghidra.app.util.viewer.listingpanel.ListingBackgroundColorModel;
import ghidra.app.util.viewer.listingpanel.ListingPanel;
import ghidra.util.ColorUtils;
/**
* Class for blending two {@link ListingBackgroundColorModel}s. If neither model has a color
@ -53,7 +53,7 @@ public class LayeredColorModel implements ListingBackgroundColorModel {
}
private Color blend(Color primary, Color secondary) {
return TempColorUtils.blend1(primary, secondary);
return ColorUtils.blend(primary, secondary, 0.67);
}
@Override

View file

@ -25,7 +25,6 @@ import docking.ActionContext;
import docking.action.DockingAction;
import docking.action.MenuData;
import generic.theme.GColor;
import generic.theme.TempColorUtils;
import ghidra.app.CorePluginPackage;
import ghidra.app.context.ListingActionContext;
import ghidra.app.plugin.PluginCategoryNames;
@ -43,6 +42,7 @@ import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ChangeManager;
import ghidra.program.util.ProgramSelection;
import ghidra.util.ColorUtils;
import ghidra.util.HelpLocation;
import ghidra.util.task.SwingUpdateManager;
@ -109,8 +109,8 @@ public class ColorizingPlugin extends ProgramPlugin implements DomainObjectListe
List<Element> colorElements = xmlElement.getChildren("COLOR");
for (Element element : colorElements) {
String rgbString = element.getAttributeValue("RGB");
int rgb = Integer.parseInt(rgbString);
savedColorHistory.add(TempColorUtils.fromRgba(rgb));
int rgba = Integer.parseInt(rgbString);
savedColorHistory.add(ColorUtils.getColor(rgba));
}
service.setColorHistory(savedColorHistory);

View file

@ -22,12 +22,12 @@ import java.util.List;
import docking.options.editor.GhidraColorChooser;
import generic.theme.GColor;
import generic.theme.GThemeDefaults.Colors.Palette;
import generic.theme.TempColorUtils;
import ghidra.app.util.viewer.listingpanel.PropertyBasedBackgroundColorModel;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.database.IntRangeMap;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
import ghidra.util.ColorUtils;
import ghidra.util.exception.DuplicateNameException;
class ColorizingServiceProvider implements ColorizingService {
@ -136,9 +136,9 @@ class ColorizingServiceProvider implements ColorizingService {
public Color getBackgroundColor(Address address) {
IntRangeMap map = getColorRangeMap(false);
if (map != null) {
Integer value = map.getValue(address);
if (value != null) {
return TempColorUtils.fromRgba(value);
Integer rgba = map.getValue(address);
if (rgba != null) {
return ColorUtils.getColor(rgba);
}
}
return null;

View file

@ -20,8 +20,8 @@ import java.awt.Color;
import javax.swing.text.*;
import generic.theme.GColor;
import generic.theme.TempColorUtils;
import ghidra.app.plugin.core.interpreter.AnsiParser.AnsiParserHandler;
import ghidra.util.ColorUtils;
/**
* An object for parsing and rendering ANSI-styled strings into a Swing {@link Document}.
@ -103,12 +103,12 @@ public class AnsiRenderer {
int b = v % 6;
int g = (v / 6) % 6;
int r = (v / 36) % 6;
return TempColorUtils.fromRgb(CUBE_STEPS[r], CUBE_STEPS[g], CUBE_STEPS[b]);
return ColorUtils.getColor(CUBE_STEPS[r], CUBE_STEPS[g], CUBE_STEPS[b]);
}
else if (v < 256) {
v -= 232;
int gray = v * 10 + 8;
return TempColorUtils.fromRgb(gray, gray, gray);
return ColorUtils.getColor(gray, gray, gray);
}
else {
/* invalid */
@ -158,7 +158,7 @@ public class AnsiRenderer {
int r = Integer.parseInt(bits[pos + 2]);
int g = Integer.parseInt(bits[pos + 3]);
int b = Integer.parseInt(bits[pos + 4]);
attributes.addAttribute(attributeName, TempColorUtils.fromRgb(r, g, b));
attributes.addAttribute(attributeName, ColorUtils.getColor(r, g, b));
return 5;
}
return 1;

View file

@ -27,7 +27,6 @@ import javax.swing.ImageIcon;
import docking.widgets.fieldpanel.support.FieldRange;
import docking.widgets.fieldpanel.support.FieldSelection;
import generic.json.Json;
import generic.theme.TempColorUtils;
import ghidra.app.services.MarkerDescriptor;
import ghidra.app.services.MarkerSet;
import ghidra.app.util.viewer.listingpanel.VerticalPixelAddressMap;
@ -36,6 +35,7 @@ import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
import ghidra.program.util.MarkerLocation;
import ghidra.program.util.ProgramLocation;
import ghidra.util.ColorUtils;
import ghidra.util.Swing;
import ghidra.util.datastruct.SortedRangeList;
@ -260,7 +260,10 @@ abstract class MarkerSetImpl implements MarkerSet {
}
protected static Color getFillColor(Color c) {
return TempColorUtils.blend2(c, COLOR_VALUE);
int red = (c.getRed() + 3 * COLOR_VALUE) / 4;
int green = (c.getGreen() + 3 * COLOR_VALUE) / 4;
int blue = (c.getBlue() + 3 * COLOR_VALUE) / 4;
return ColorUtils.getColor(red, green, blue);
}
@Override

View file

@ -0,0 +1,73 @@
/* ###
* 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 ghidra.app.plugin.core.misc;
import docking.ActionContext;
import docking.ComponentProvider;
import docking.action.builder.ActionBuilder;
import ghidra.app.CorePluginPackage;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.util.Msg;
/**
* Manages the markers to display areas where changes have occurred
*/
@PluginInfo( //@formatter:off
status = PluginStatus.RELEASED,
packageName = CorePluginPackage.NAME,
category = PluginCategoryNames.MISC,
shortDescription = "Provides generic actions for increasing/decreasing fonts.",
description = "This plugin provides actions for increasing fonts used by component providers. "+
"ComponentProviders can either override the \"changeFontSize()\" method or register a" +
"theme font id that can be automatically adjusted."
) //@formatter:on
public class FontAdjustPlugin extends Plugin {
public FontAdjustPlugin(PluginTool tool) {
super(tool);
new ActionBuilder("Increment Font", "tool")
.keyBinding("ctrl EQUALS")
.onAction(this::incrementFont)
.buildAndInstall(tool);
new ActionBuilder("Decrement Font", "tool")
.keyBinding("ctrl MINUS")
.onAction(this::decrementFont)
.buildAndInstall(tool);
}
private void incrementFont(ActionContext context) {
Msg.debug(this, "incrementFont");
ComponentProvider provider = context.getComponentProvider();
if (provider != null) {
provider.adjustFontSize(true);
}
}
private void decrementFont(ActionContext context) {
Msg.debug(this, "decrementFont");
ComponentProvider provider = context.getComponentProvider();
if (provider != null) {
provider.adjustFontSize(false);
}
}
}

View file

@ -21,7 +21,7 @@ import java.util.ArrayList;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import generic.theme.TempColorUtils;
import ghidra.util.ColorUtils;
import ghidra.util.datastruct.WeakDataStructureFactory;
import ghidra.util.datastruct.WeakSet;
@ -76,7 +76,7 @@ public class OverviewPalette {
int green = (int) (lo.getGreen() * (1.0 - t) + hi.getGreen() * t);
int blue = (int) (lo.getBlue() * (1.0 - t) + hi.getGreen() * t);
t += step;
colors[i] = TempColorUtils.fromRgb(red, green, blue);
colors[i] = ColorUtils.getColor(red, green, blue);
}
knots.clear();
firePaletteChanged();
@ -112,7 +112,7 @@ public class OverviewPalette {
int green = (int) Math.floor(tmp);
tmp = (knot.getBlue() - oldcolor.getBlue()) * t + oldcolor.getBlue();
int blue = (int) Math.floor(tmp);
colors[start] = TempColorUtils.fromRgb(red, green, blue);
colors[start] = ColorUtils.getColor(red, green, blue);
cur += radianstep;
start += 1;
}

View file

@ -32,7 +32,8 @@ import generic.theme.Gui;
public class FixedBitSizeValueField extends JPanel {
private static final Icon DROP_DOWN_MENU_ICON = new GIcon("icon.base.app.fixed.bit.size.field");
private static final Icon DROP_DOWN_MENU_ICON =
new GIcon("icon.base.util.fixed.bit.size.field");
protected JTextField valueField;
protected JButton menuButton;

View file

@ -22,7 +22,6 @@ import java.util.Map;
import docking.widgets.fieldpanel.support.BackgroundColorModel;
import generic.theme.GColor;
import generic.theme.TempColorUtils;
import ghidra.app.util.viewer.util.AddressIndexMap;
import ghidra.framework.model.DomainObjectChangedEvent;
import ghidra.framework.model.DomainObjectListener;
@ -30,6 +29,7 @@ import ghidra.program.database.IntRangeMap;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ChangeManager;
import ghidra.util.ColorUtils;
/**
* Default {@link BackgroundColorModel} for the ListingPanel where the color returned
@ -95,7 +95,7 @@ public class PropertyBasedBackgroundColorModel
}
Color c = colorCache.get(value);
if (c == null) {
c = TempColorUtils.fromRgba(value);
c = ColorUtils.getColor(value);
colorCache.put(value, c);
}
return c;

View file

@ -24,12 +24,12 @@ import javax.swing.KeyStroke;
import org.xml.sax.SAXParseException;
import generic.theme.TempColorUtils;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.*;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.util.*;
import ghidra.util.ColorUtils;
import ghidra.util.XmlProgramUtilities;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
@ -255,7 +255,7 @@ class PropertiesXmlMgr {
}
else if ("color".equals(type)) {
Color color =
TempColorUtils.fromRgb(XmlUtilities.parseInt(element.getAttribute("VALUE")));
ColorUtils.getColor(XmlUtilities.parseInt(element.getAttribute("VALUE")));
list.setColor(name, color);
}
else if ("file".equals(type)) {

View file

@ -15,23 +15,13 @@
*/
package ghidra.plugins.fsbrowser;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import org.jdom.*;
import org.jdom.input.SAXBuilder;
import generic.jar.ResourceFile;
import generic.theme.*;
import ghidra.formats.gfilesystem.FSUtilities;
import ghidra.framework.Application;
import ghidra.util.Msg;
import ghidra.util.xml.XmlUtilities;
import resources.*;
import util.CollectionUtils;
import resources.MultiIcon;
/**
* Provides {@link Icon}s that represent the type and status of a file, based on
@ -58,76 +48,33 @@ public class FileIconService {
return Singleton.INSTANCE;
}
public static final String OVERLAY_IMPORTED = "imported";
public static final String OVERLAY_FILESYSTEM = "filesystem";
public static final String OVERLAY_MISSING_PASSWORD = "password_missing";
public static final Icon IMPORTED_OVERLAY_ICON =
new GIcon("icon.fsbrowser.file.overlay.imported");
public static final Icon FILESYSTEM_OVERLAY_ICON =
new GIcon("icon.fsbrowser.file.overlay.filesystem");
public static final Icon MISSING_PASSWORD_OVERLAY_ICON =
new GIcon("icon.fsbrowser.file.overlay.missing.password");
public static final Icon DEFAULT_ICON = new GIcon("icon.fsbrowser.file.extension.default");
private static final String FILEEXT_MAPPING_FILE = "file_extension_icons.xml";
private static final String EXTENSION_ICON_PREFIX = "icon.fsbrowser.file.extension";
private static final String SUBSTRING_ICON_PREFIX = "icon.fsbrowser.file.substring";
private Map<String, String> fileExtToIconName = new HashMap<>();
private Map<String, String> fileSubstrToIconName = new HashMap<>();
private Map<String, String> overlayNameToIconName = new HashMap<>();
private Map<String, QUADRANT> overlayNameToQuad = new HashMap<>();
private String defaultIconPath = "images/famfamfam_silk_icons_v013/page_white.png";
private int maxExtLevel = 1;
private Map<String, Icon> iconKeyToIcon = new HashMap<>();
private ResourceFile xmlFile;
private Map<String, Icon> substringToIconMap = new HashMap<>();
private FileIconService() {
this.xmlFile = Application.findDataFileInAnyModule(FILEEXT_MAPPING_FILE);
if (xmlFile == null) {
Msg.error(this, "Cannot find " + FILEEXT_MAPPING_FILE +
". File system browser will not have icons.");
}
createSubstringMap();
}
private String makeKey(String key, String[] overlays) {
StringBuilder sb = new StringBuilder();
sb.append(key).append("__");
for (String o : overlays) {
if (o == null || o.isEmpty()) {
continue;
private void createSubstringMap() {
GThemeValueMap values = Gui.getAllValues();
List<IconValue> icons = values.getIcons();
for (IconValue iconValue : icons) {
String id = iconValue.getId();
if (id.startsWith(SUBSTRING_ICON_PREFIX)) {
String substring = id.substring(SUBSTRING_ICON_PREFIX.length());
substringToIconMap.put(substring, new GIcon(id));
}
sb.append(o).append("__");
}
return sb.toString();
}
private Icon getCachedIcon(String key, String path, String... overlays) {
key = makeKey(key, overlays);
Icon cachedIcon = iconKeyToIcon.get(key);
if (cachedIcon == null) {
cachedIcon = ResourceManager.loadImage(path);
if (overlays.length > 0) {
int expectedOW = cachedIcon.getIconWidth() / 2;
int expectedOH = cachedIcon.getIconHeight() / 2;
EnumSet<QUADRANT> usedQuads = EnumSet.noneOf(QUADRANT.class);
MultiIconBuilder iconBuilder = new MultiIconBuilder(cachedIcon);
for (String overlay : overlays) {
if (overlay == null || overlay.isEmpty()) {
continue;
}
String overlayPath = overlayNameToIconName.get(overlay);
QUADRANT quad = overlayNameToQuad.get(overlay);
if (overlayPath == null || quad == null) {
continue;
}
if (usedQuads.contains(quad)) {
Msg.warn(this, "File icon already contains an overlay at " + quad);
}
usedQuads.add(quad);
ImageIcon overlayIcon = ResourceManager.loadImage(overlayPath);
iconBuilder.addIcon(overlayIcon, expectedOW, expectedOH, quad);
}
cachedIcon = iconBuilder.build();
}
iconKeyToIcon.put(key, cachedIcon);
}
return cachedIcon;
}
/**
@ -135,106 +82,43 @@ public class FileIconService {
* name.
*
* @param fileName name of file that an icon is being requested for.
* @param overlays optional list of overlay names, names of icons that
* should be overlaid on top of the base icon, that represent a
* @param overlays optional list of overlay icons that
* should be overlaid on top of the base icon. These icons represent a
* status or feature independent of the file's base icon.
* @return {@link Icon} instance that best represents the named file, never
* null.
*/
public synchronized Icon getImage(String fileName, String... overlays) {
loadIfNeeded();
public Icon getIcon(String fileName, List<Icon> overlays) {
fileName = fileName.toLowerCase();
for (int extLevel = 1; extLevel <= maxExtLevel; extLevel++) {
String ext = FSUtilities.getExtension(fileName, extLevel);
if (ext == null) {
break;
}
String path = fileExtToIconName.get(ext);
if (path != null) {
return getCachedIcon(ext, path, overlays);
String ext = FSUtilities.getExtension(fileName, 1);
if (ext != null) {
String iconId = EXTENSION_ICON_PREFIX + ext;
if (Gui.hasIcon(iconId)) {
Icon base = new GIcon(iconId);
return buildIcon(base, overlays);
}
}
for (String substr : fileSubstrToIconName.keySet()) {
if (fileName.indexOf(substr) != -1) {
return getCachedIcon("####" + substr, fileSubstrToIconName.get(substr), overlays);
for (String substring : substringToIconMap.keySet()) {
if (fileName.indexOf(substring) != -1) {
return buildIcon(substringToIconMap.get(substring), overlays);
}
}
// return default icon for generic file
return getCachedIcon("", defaultIconPath, overlays);
return buildIcon(DEFAULT_ICON, overlays);
}
/**
* Loads XML file if it has not been loaded yet.
*/
protected void loadIfNeeded() {
if (fileExtToIconName.isEmpty()) {
load();
private Icon buildIcon(Icon base, List<Icon> overlays) {
if (overlays == null || overlays.isEmpty()) {
return base;
}
}
private void load() {
fileExtToIconName.clear();
fileSubstrToIconName.clear();
overlayNameToIconName.clear();
overlayNameToQuad.clear();
iconKeyToIcon.clear();
defaultIconPath = null;
maxExtLevel = 1;
try (InputStream xmlInputStream = xmlFile.getInputStream()) {
SAXBuilder sax = XmlUtilities.createSecureSAXBuilder(false, false);
Document doc = sax.build(xmlInputStream);
Element root = doc.getRootElement();
for (Element child : CollectionUtils.asList(root.getChildren("file_extension"),
Element.class)) {
String extension = child.getAttributeValue("extension");
String iconPath = child.getAttributeValue("icon");
if (extension.endsWith(".")) {
addSubstrMapping(extension, iconPath);
}
else if (!extension.isEmpty()) {
addExtMapping(extension, iconPath);
}
else {
defaultIconPath = iconPath;
}
}
for (Element child : CollectionUtils.asList(root.getChildren("file_overlay"),
Element.class)) {
String name = child.getAttributeValue("name");
String iconPath = child.getAttributeValue("icon");
QUADRANT quadrant =
QUADRANT.valueOf(child.getAttributeValue("quadrant"), QUADRANT.LR);
overlayNameToIconName.put(name, iconPath);
overlayNameToQuad.put(name, quadrant);
MultiIcon multiIcon = new MultiIcon(base);
for (Icon overlay : overlays) {
if (overlay != null) {
multiIcon.addIcon(overlay);
}
}
catch (JDOMException | IOException e) {
Msg.error(this, "Error reading file icon data: " + e.getMessage(), e);
}
return multiIcon;
}
private void addSubstrMapping(String substr, String iconPath) {
fileSubstrToIconName.put(substr, iconPath);
}
private void addExtMapping(String ext, String iconPath) {
fileExtToIconName.put(ext, iconPath);
maxExtLevel = Math.max(maxExtLevel, countExtLevel(ext));
}
private int countExtLevel(String ext) {
int count = 0;
for (int i = 0; i < ext.length(); i++) {
if (ext.charAt(i) == '.') {
count++;
}
}
return count;
}
}

View file

@ -129,29 +129,28 @@ class FileSystemBrowserComponentProvider extends ComponentProviderAdapter
String containerFilename =
fsFSRL.hasContainer() ? fsFSRL.getContainer().getName() : "unknown";
Icon image = FileIconService.getInstance()
.getImage(containerFilename,
FileIconService.OVERLAY_FILESYSTEM);
.getIcon(containerFilename,
List.of(FileIconService.FILESYSTEM_OVERLAY_ICON));
setIcon(image);
}
private void renderFile(FSBFileNode node, boolean selected) {
FSRL fsrl = node.getFSRL();
String filename = fsrl.getName();
List<Icon> overlays = new ArrayList<>(3);
String importOverlay = ProgramMappingService.isFileImportedIntoProject(fsrl)
? FileIconService.OVERLAY_IMPORTED
: null;
String mountedOverlay = fsService.isFilesystemMountedAt(fsrl)
? FileIconService.OVERLAY_FILESYSTEM
: null;
if (ProgramMappingService.isFileImportedIntoProject(fsrl)) {
overlays.add(FileIconService.IMPORTED_OVERLAY_ICON);
}
if (fsService.isFilesystemMountedAt(fsrl)) {
overlays.add(FileIconService.FILESYSTEM_OVERLAY_ICON);
}
if (node.hasMissingPassword()) {
overlays.add(FileIconService.MISSING_PASSWORD_OVERLAY_ICON);
}
String missingPasswordOverlay = node.hasMissingPassword()
? FileIconService.OVERLAY_MISSING_PASSWORD
: null;
Icon ico = FileIconService.getInstance()
.getImage(filename, importOverlay, mountedOverlay, missingPasswordOverlay);
setIcon(ico);
Icon icon = FileIconService.getInstance().getIcon(filename, overlays);
setIcon(icon);
if (ProgramMappingService.isFileOpen(fsrl)) {
// TODO: change this to a OVERLAY_OPEN option when fetching icon

View file

@ -50,7 +50,6 @@ import generic.test.AbstractGenericTest;
import generic.theme.GThemeDefaults.Colors;
import generic.theme.GThemeDefaults.Colors.Java;
import generic.theme.GThemeDefaults.Colors.Palette;
import generic.theme.TempColorUtils;
import generic.util.image.ImageUtils;
import ghidra.app.events.ProgramSelectionPluginEvent;
import ghidra.app.plugin.core.analysis.AnalysisOptionsDialog;
@ -80,6 +79,7 @@ import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramSelection;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv;
import ghidra.util.ColorUtils;
import ghidra.util.exception.AssertException;
import resources.ResourceManager;
@ -794,14 +794,14 @@ public abstract class AbstractScreenShotGenerator extends AbstractGhidraHeadedIn
for (Component component : comps) {
int pad = 6;
Point p = component.getLocationOnScreen();
g.setColor(TempColorUtils.fromRgb(250, 250, 250)); // just slightly not white
g.setColor(ColorUtils.getOpaqueColor(0xfafafa)); // just slightly not white
g.fillRoundRect(p.x - rect.x - pad, p.y - rect.y - pad, component.getWidth() + pad * 2,
component.getHeight() + pad * 2, pad * 2, pad * 2);
}
for (Component component : comps) {
int pad = 3;
Point p = component.getLocationOnScreen();
g.setColor(TempColorUtils.fromRgb(240, 240, 240)); // faint gray
g.setColor(ColorUtils.getOpaqueColor(0xf0f0f0)); // faint gray
g.fillRoundRect(p.x - rect.x - pad, p.y - rect.y - pad, component.getWidth() + pad * 2,
component.getHeight() + pad * 2, pad * 2, pad * 2);
}

View file

@ -32,7 +32,6 @@ import docking.action.DockingActionIf;
import docking.options.editor.DefaultOptionComponent;
import docking.widgets.table.GTable;
import generic.theme.GThemeDefaults.Colors.Palette;
import generic.theme.TempColorUtils;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
import ghidra.app.services.*;
@ -44,6 +43,7 @@ import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.Program;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv;
import ghidra.util.ColorUtils;
import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.exception.AssertException;
import ghidra.util.exception.CancelledException;
@ -351,7 +351,7 @@ public class AnalysisOptions2Test extends AbstractGhidraHeadedIntegrationTest {
int r = Integer.parseInt(parts[0]);
int g = Integer.parseInt(parts[1]);
int b = Integer.parseInt(parts[2]);
return TempColorUtils.fromRgb(r, g, b);
return ColorUtils.getColor(r, g, b);
}
private void selectAnalyzer(String name) {

View file

@ -34,7 +34,6 @@ import docking.widgets.fieldpanel.FieldPanel;
import docking.widgets.fieldpanel.support.FieldLocation;
import docking.widgets.fieldpanel.support.FieldSelection;
import generic.theme.GThemeDefaults.Colors.Palette;
import generic.theme.TempColorUtils;
import ghidra.GhidraOptions;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.marker.MarkerManagerPlugin;
@ -50,6 +49,7 @@ import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv;
import ghidra.util.ColorUtils;
public class ColorizingPluginTest extends AbstractGhidraHeadedIntegrationTest {
@ -180,7 +180,7 @@ public class ColorizingPluginTest extends AbstractGhidraHeadedIntegrationTest {
Address address2 = address1.add(8);
Address address3 = address2.add(16);
Color color = TempColorUtils.fromRgba(100, 100, 100, 100);
Color color = ColorUtils.getColor(100, 100, 100, 100);
setColor(color, address1, address2, address3);
assertColorForAddress(color, address1, address2, address3);
@ -200,7 +200,7 @@ public class ColorizingPluginTest extends AbstractGhidraHeadedIntegrationTest {
// change the location so that the current line marker does not affect our color check below
address = address.add(400);
Color color = TempColorUtils.fromRgb(100, 100, 100);
Color color = ColorUtils.getColor(100, 100, 100);
setBackgroundFromAPI(address, color);
assertMarkerColorAtAddress(address, color);
@ -220,7 +220,7 @@ public class ColorizingPluginTest extends AbstractGhidraHeadedIntegrationTest {
Address address2 = address1.add(8);
Address address3 = address2.add(8);
Color color = TempColorUtils.fromRgba(100, 100, 100, 100);
Color color = ColorUtils.getColor(100, 100, 100, 100);
setColor(color, address1, address2, address3);
// start before the first address to test that the next range action is enabled and the

View file

@ -45,7 +45,6 @@ import docking.widgets.tree.GTree;
import docking.widgets.tree.GTreeNode;
import generic.test.TestUtils;
import generic.theme.GThemeDefaults.Colors.Palette;
import generic.theme.TempColorUtils;
import ghidra.GhidraOptions;
import ghidra.app.plugin.core.console.ConsolePlugin;
import ghidra.app.util.viewer.options.OptionsGui;
@ -57,6 +56,7 @@ import ghidra.framework.plugintool.dialog.KeyBindingsPanel;
import ghidra.framework.preferences.Preferences;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv;
import ghidra.util.ColorUtils;
/**
* Tests for the options dialog.
@ -126,7 +126,7 @@ public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest {
selectAddressEntryInScreenElementOptionsList(optionsGui);
Color newColor =
TempColorUtils.fromRgb(255, addressFieldColor.getGreen(), addressFieldColor.getBlue());
ColorUtils.getColor(255, addressFieldColor.getGreen(), addressFieldColor.getBlue());
setAddressColorValueInOptionsGUI(optionsGui, newColor);
// close the options

View file

@ -15,23 +15,57 @@
*/
package ghidra.plugins.fsbrowser;
import static org.junit.Assert.*;
import java.util.List;
import javax.swing.Icon;
import org.junit.Assert;
import org.junit.Test;
import generic.test.AbstractGenericTest;
import docking.test.AbstractDockingTest;
import generic.theme.GIcon;
import resources.MultiIcon;
public class FileIconServiceTest extends AbstractGenericTest
{
public class FileIconServiceTest extends AbstractDockingTest {
@Test
public void testGetIcon() {
FileIconService fis = FileIconService.getInstance();
Assert.assertNotNull(fis.getImage("blah.txt"));
Icon icon = fis.getIcon("blah.txt", null);
Assert.assertNotNull(icon);
assertTrue(icon instanceof GIcon);
GIcon gIcon = (GIcon) icon;
assertEquals("icon.fsbrowser.file.extension.txt", gIcon.getId());
}
@Test
public void testGetOverlayIcon() {
FileIconService fis = FileIconService.getInstance();
Assert.assertNotNull(fis.getImage("blah.txt", FileIconService.OVERLAY_FILESYSTEM));
Icon icon = fis.getIcon("blah.txt", List.of(FileIconService.FILESYSTEM_OVERLAY_ICON));
Assert.assertNotNull(icon);
assertTrue(icon instanceof MultiIcon);
MultiIcon multiIcon = (MultiIcon) icon;
assertEquals(
"MultiIcon[icon.fsbrowser.file.extension.txt, icon.fsbrowser.file.overlay.filesystem]",
multiIcon.toString());
}
@Test
public void testGetSubstringIcon() {
FileIconService fis = FileIconService.getInstance();
Icon icon = fis.getIcon("blah.release.abcx.123", null);
Assert.assertNotNull(icon);
assertTrue(icon instanceof GIcon);
GIcon gIcon = (GIcon) icon;
assertEquals("icon.fsbrowser.file.substring.release.", gIcon.getId());
}
@Test
public void testNoMatch() {
FileIconService fis = FileIconService.getInstance();
Icon icon = fis.getIcon("aaaaaaaa.bbbbbbbb.cccccccc", null);
assertEquals(FileIconService.DEFAULT_ICON, icon);
}
}

View file

@ -108,6 +108,7 @@ public abstract class ByteViewerComponentProvider extends ComponentProviderAdapt
String name, Class<?> contextType) {
super(tool, name, plugin.getName(), contextType);
this.plugin = plugin;
registerAdjustableFontId(DEFAULT_FONT_ID);
initializedDataFormatModelClassMap();

View file

@ -352,8 +352,7 @@ public class DecompileOptions {
private final static Color ERROR_COLOR = new GColor("color.fg.decompiler.comment");
final static String FONT_MSG = "Display.Font";
final static String DEFAULT_FONT_ID = "font.decompiler";
private Font font;
public final static String DEFAULT_FONT_ID = "font.decompiler";
private final static String CACHED_RESULTS_SIZE_MSG = "Cache Size (Functions)";
private final static int SUGGESTED_CACHED_RESULTS_SIZE = 10;

View file

@ -111,7 +111,7 @@ public class DecompilerProvider extends NavigatableComponentProviderAdapter
this.plugin = plugin;
this.clipboardProvider = new DecompilerClipboardProvider(plugin, this);
registerAdjustableFontId(DecompileOptions.DEFAULT_FONT_ID);
setConnected(isConnected);
decompilerOptions = new DecompileOptions();

View file

@ -44,7 +44,6 @@ import docking.widgets.textfield.HintTextField;
import generic.theme.GIcon;
import generic.theme.GThemeDefaults.Colors;
import generic.theme.GThemeDefaults.Colors.Messages;
import generic.theme.TempColorUtils;
import ghidra.app.util.bin.format.pdb.PdbParser;
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbIdentifiers;
import ghidra.app.util.pdb.pdbapplicator.PdbApplicatorControl;
@ -892,7 +891,7 @@ public class LoadPdbDialog extends DialogComponentProvider {
Color bg = parent.getBackground();
// mint a new Color object to avoid it being ignored because the parent handed us a
// DerivedColor instance
return TempColorUtils.fromRgb(bg.getRGB());
return ColorUtils.getColor(bg.getRGB());
}
return super.getBackground();
}
@ -933,7 +932,7 @@ public class LoadPdbDialog extends DialogComponentProvider {
Color bg = parent.getBackground();
// mint a new Color object to avoid it being ignored because the parent handed us a
// DerivedColor instance
return TempColorUtils.fromRgb(bg.getRGB());
return ColorUtils.getColor(bg.getRGB());
}
return super.getBackground();
}

View file

@ -31,12 +31,13 @@ import docking.widgets.label.GDLabel;
import docking.widgets.label.GHtmlLabel;
import docking.widgets.textfield.HexIntegerFormatter;
import generic.theme.GColor;
import generic.theme.TempColorUtils;
import ghidra.feature.vt.api.main.VTAssociation;
import ghidra.feature.vt.gui.provider.matchtable.NumberRangeProducer;
import ghidra.feature.vt.gui.provider.matchtable.NumberRangeSubFilterChecker;
import ghidra.framework.options.SaveState;
import ghidra.program.model.address.Address;
import ghidra.util.ColorUtils;
import ghidra.util.WebColors;
public abstract class AbstractAddressRangeFilter<T> extends AncillaryFilter<T>
implements NumberRangeSubFilterChecker, NumberRangeProducer {
@ -122,7 +123,7 @@ public abstract class AbstractAddressRangeFilter<T> extends AncillaryFilter<T>
//
// Lower Score Panel
//
String fgColor = TempColorUtils.toString(FG_TOOLTIP_DEFAULT);
String fgColor = WebColors.toString(FG_TOOLTIP_DEFAULT);
lowerRangePanel = new JPanel(new GridLayout(2, 1));
JLabel lowLabel =
new GHtmlLabel("<html><font size=\"2\" color=\"" + fgColor + "\">low</font>");
@ -208,7 +209,7 @@ public abstract class AbstractAddressRangeFilter<T> extends AncillaryFilter<T>
@Override
protected void paintComponent(Graphics g) {
Color bg = getBackground();
Color disabledColor = TempColorUtils.withAlpha(bg, 100);
Color disabledColor = ColorUtils.withAlpha(bg, 100);
g.setColor(disabledColor);
g.fillRect(0, 0, getWidth(), getHeight());
}

View file

@ -99,14 +99,13 @@ icon.home = go-home.png
icon.add = Plus2.png
icon.subtract = list-remove.png
icon.clear = erase16.png
icon.error = error.png
icon.error = emblem-important.png
icon.delete = icon.error
icon.collapse.all = collapse_all.png
icon.expand.all = expand_all.png
icon.toggle.expand = expand.gif
icon.toggle.collapse = collapse.gif
icon.configure.filter = exec.png
icon.error = emblem-important.png
icon.navigate.in = locationIn.gif
icon.navigate.out = locationOut.gif
icon.not.allowed = dialog-cancel.png
@ -149,7 +148,8 @@ icon.properties = document-properties.png
icon.table = table.png
icon.drive = drive.png
icon.run = play.png
icon.spreadsheet =
icon.spreadsheet = application-vnd.oasis.opendocument.spreadsheet-template.png
icon.pulldown = menu16.gif
icon.window = application_xp.png
icon.zoom.in = zoom_in.png
icon.zoom.out = zoom_out.png
@ -193,7 +193,7 @@ icon.widget.table.header.help = info_small.png
icon.widget.table.header.help.hovered = info_small_hover.png
icon.widget.table.header.pending = hourglass.png
icon.dialog.error.expandable.report = icon.speadsheet
icon.dialog.error.expandable.report = icon.spreadsheet
icon.dialog.error.expandable.exception = program_obj.png
icon.dialog.error.expandable.frame = StackFrameElement.png
icon.dialog.error.expandable.stack = StackFrame_Red.png

View file

@ -15,14 +15,14 @@
*/
package docking;
import java.awt.Component;
import java.awt.KeyboardFocusManager;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.util.*;
import javax.swing.*;
import docking.action.*;
import generic.theme.Gui;
import ghidra.util.*;
import ghidra.util.exception.AssertException;
import help.HelpDescriptor;
@ -114,6 +114,8 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
private String inceptionInformation;
private String registeredFontId;
/**
* Creates a new component provider with a default location of {@link WindowPosition#WINDOW}.
* @param tool The tool will manage and show this provider
@ -776,6 +778,41 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
return dockingTool;
}
/**
* Tells the provider to adjust the font size for this provider. By default, this method
* will adjust the font for the registered font id if it has been registered using
* {@link #registeredFontId}. Subclasses can override this method to a more comprehensive
* adjustment to multiple fonts if necessary.
* @param bigger if true, the font should be made bigger, otherwise the font should be made
* smaller
*/
public void adjustFontSize(boolean bigger) {
if (registeredFontId == null) {
return;
}
Font font = Gui.getFont(registeredFontId);
if (font == null) {
return;
}
int size = font.getSize();
if (bigger) {
size += 1;
}
else {
size = Math.max(size - 1, 3);
}
Gui.setFont(registeredFontId, font.deriveFont((float) size));
}
/**
* Registers a fontId for the font that will be automatically adjusted when
* {@link #adjustFontSize(boolean)} is called.
* @param fontId the id of the theme font to be adjusted
*/
protected void registerAdjustableFontId(String fontId) {
this.registeredFontId = fontId;
}
@Override
public String toString() {
return name + " - " + getTitle() + " - " + getSubTitle();
@ -885,4 +922,5 @@ public abstract class ComponentProvider implements HelpDescriptor, ActionContext
return inceptionInformation;
}
}
}

View file

@ -32,7 +32,6 @@ import docking.widgets.EmptyBorderButton;
import docking.widgets.label.GDLabel;
import generic.theme.GThemeDefaults.Colors;
import generic.theme.Gui;
import generic.theme.TempColorUtils;
import generic.util.WindowUtilities;
import ghidra.util.*;
import ghidra.util.layout.HorizontalLayout;
@ -318,14 +317,14 @@ public class StatusBar extends JPanel {
delta = -16;
}
Color start = TempColorUtils.fromRgb(value, value, value);
Color start = ColorUtils.getColor(value, value, value);
fadeColorMap.put(statusLabel.getForeground(), start);
for (int i = 0; i < 8; i++) {
Color from = TempColorUtils.fromRgb(value, value, value);
Color from = ColorUtils.getColor(value, value, value);
value += delta;
Color to = TempColorUtils.fromRgb(value, value, value);
Color to = ColorUtils.getColor(value, value, value);
fadeColorMap.put(from, to);
}
}
@ -404,7 +403,7 @@ public class StatusBar extends JPanel {
int red = color.getRed();
int green = color.getGreen();
int blue = color.getBlue();
return TempColorUtils.fromRgb((255 - red), (255 - green), (255 - blue));
return ColorUtils.getColor((255 - red), (255 - green), (255 - blue));
}
private void contrastStatusLabelColors() {

View file

@ -26,8 +26,8 @@ import docking.DialogComponentProvider;
import docking.DockingWindowManager;
import docking.widgets.label.GDHtmlLabel;
import generic.theme.GThemeDefaults.Colors.Palette;
import generic.theme.TempColorUtils;
import ghidra.util.ColorUtils;
import ghidra.util.WebColors;
/**
* Color editor that is a bit unusual in that its custom component is a button that when pushed,
@ -88,7 +88,7 @@ public class ColorEditor extends PropertyEditorSupport {
private void updateColor(Color newColor) {
// change the color to a darker value if the color being set is light
String colorString = TempColorUtils.toString(ColorUtils.contrastForegroundColor(newColor));
String colorString = WebColors.toString(ColorUtils.contrastForegroundColor(newColor));
previewLabel.setText(
"<HTML><CENTER><I><FONT SIZE=2 COLOR=" + colorString + ">click</FONT></I></CENTER>");
@ -148,8 +148,7 @@ public class ColorEditor extends PropertyEditorSupport {
// This could be a ColorUIResource, but Options only support storing Color. So,
// manually create a new Color object to avoid saving a ColorUIResource.
Color c = colorChooser.getColor();
lastUserSelectedColor = TempColorUtils.fromRgba(c.getRed(), c.getGreen(),
c.getBlue(), c.getAlpha());
lastUserSelectedColor = ColorUtils.getColor(c.getRGB());
});
colorChooser.setColor(color);
}

View file

@ -18,13 +18,11 @@ package docking.options.editor;
import java.awt.*;
import java.awt.event.ActionListener;
import java.beans.PropertyEditorSupport;
import java.util.Arrays;
import java.util.Objects;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import java.util.*;
import java.util.List;
import java.util.stream.*;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.*;
import docking.widgets.combobox.GComboBox;
import docking.widgets.label.GDLabel;
@ -67,6 +65,7 @@ public class FontPropertyEditor extends PropertyEditorSupport {
private GComboBox<Integer> sizeCombo;
private GComboBox<String> styleCombo;
private ActionListener actionListener = e -> fontChanged();
private List<FontWrapper> systemFontNames;
public FontChooserPanel() {
build();
@ -83,9 +82,10 @@ public class FontPropertyEditor extends PropertyEditorSupport {
styleCombo.removeActionListener(actionListener);
FontWrapper fontWrapper = new FontWrapper(font.getName());
updateComboBoxModeIfNeeded(fontWrapper);
int styleChoice = font.getStyle();
int size = font.getSize();
fontCombo.setSelectedItem(fontWrapper);
sizeCombo.setSelectedItem(size);
styleCombo.setSelectedIndex(styleChoice);
@ -96,6 +96,16 @@ public class FontPropertyEditor extends PropertyEditorSupport {
}
private void updateComboBoxModeIfNeeded(FontWrapper fontWrapper) {
if (systemFontNames.contains(fontWrapper)) {
return;
}
systemFontNames.add(fontWrapper);
DefaultComboBoxModel<FontWrapper> model =
new DefaultComboBoxModel<>(systemFontNames.toArray(new FontWrapper[0]));
fontCombo.setModel(model);
}
private void build() {
setLayout(new BorderLayout());
add(buildTopPanel(), BorderLayout.NORTH);
@ -104,7 +114,7 @@ public class FontPropertyEditor extends PropertyEditorSupport {
private Component buildTopPanel() {
JPanel panel = new JPanel(new FlowLayout(SwingConstants.CENTER, 10, 0));
panel.add(buildFontPanel());
panel.add(buildFontNamePanel());
panel.add(buildSizePanel());
panel.add(buildStylePanel());
return panel;
@ -154,7 +164,7 @@ public class FontPropertyEditor extends PropertyEditorSupport {
return panel;
}
private Component buildFontPanel() {
private Component buildFontNamePanel() {
JPanel panel = new JPanel(new GridLayout(2, 1));
GDLabel fontLabel = new GDLabel("Fonts");
@ -162,12 +172,8 @@ public class FontPropertyEditor extends PropertyEditorSupport {
fontLabel.setHorizontalAlignment(SwingConstants.CENTER);
panel.add(fontLabel);
GraphicsEnvironment gEnv = GraphicsEnvironment.getLocalGraphicsEnvironment();
Stream<String> stream = Arrays.stream(gEnv.getAvailableFontFamilyNames());
FontWrapper[] array = stream.map(s -> new FontWrapper(s)).toArray(FontWrapper[]::new);
Arrays.sort(array);
fontCombo = new GComboBox<>(array);
systemFontNames = getSystemFontNames();
fontCombo = new GComboBox<>(systemFontNames.toArray(new FontWrapper[0]));
fontCombo.setMaximumRowCount(9);
fontCombo.addActionListener(actionListener);
panel.add(fontCombo);
@ -175,6 +181,15 @@ public class FontPropertyEditor extends PropertyEditorSupport {
return panel;
}
private List<FontWrapper> getSystemFontNames() {
GraphicsEnvironment gEnv = GraphicsEnvironment.getLocalGraphicsEnvironment();
Stream<String> stream = Arrays.stream(gEnv.getAvailableFontFamilyNames());
List<FontWrapper> collect =
stream.map(s -> new FontWrapper(s)).collect(Collectors.toList());
Collections.sort(collect);
return new ArrayList<>(collect);
}
private void fontChanged() {
FontWrapper fontWrapper = (FontWrapper) fontCombo.getSelectedItem();
String fontNameChoice = fontWrapper.getFontName();

View file

@ -28,7 +28,7 @@ import docking.widgets.label.GHtmlLabel;
import docking.widgets.label.GLabel;
import generic.theme.GThemeDefaults.Colors;
import generic.theme.GThemeDefaults.Colors.Java;
import generic.theme.TempColorUtils;
import ghidra.util.ColorUtils;
import ghidra.util.layout.VerticalLayout;
public class SettableColorSwatchChooserPanel extends AbstractColorChooserPanel {
@ -388,9 +388,8 @@ class MainSwatchPanel extends SwatchPanel {
colors = new Color[numColors];
for (int i = 0; i < numColors; i++) {
colors[i] =
TempColorUtils.fromRgb(rawValues[(i * 3)], rawValues[(i * 3) + 1],
rawValues[(i * 3) + 2]);
colors[i] = ColorUtils.getColor(rawValues[(i * 3)], rawValues[(i * 3) + 1],
rawValues[(i * 3) + 2]);
}
}

View file

@ -40,9 +40,7 @@ import docking.widgets.indexedscrollpane.IndexScrollListener;
import docking.widgets.indexedscrollpane.IndexedScrollable;
import generic.theme.GColor;
import generic.theme.GThemeDefaults.Colors.Messages;
import generic.theme.TempColorUtils;
import ghidra.util.Msg;
import ghidra.util.SystemUtilities;
import ghidra.util.*;
public class FieldPanel extends JPanel
implements IndexedScrollable, LayoutModelListener, ChangeListener {
@ -1154,7 +1152,7 @@ public class FieldPanel extends JPanel
}
private Color blend(Color primary, Color secondary) {
return TempColorUtils.blend4(primary, secondary);
return ColorUtils.blend(primary, secondary, 0.75);
}
private void paintLayoutBackground(Graphics g, Rectangle rect, AnchoredLayout layout,

View file

@ -17,7 +17,7 @@ package docking.widgets.fieldpanel.internal;
import java.awt.Color;
import generic.theme.TempColorUtils;
import ghidra.util.ColorUtils;
import ghidra.util.datastruct.*;
public class ColorRangeMap {
@ -59,12 +59,12 @@ public class ColorRangeMap {
return getColor(valueRange.getValue());
}
private Color getColor(int colorValue) {
if (lastColorValue == colorValue) {
private Color getColor(int rgba) {
if (lastColorValue == rgba) {
return lastColor;
}
lastColorValue = colorValue;
lastColor = TempColorUtils.fromRgb(colorValue);
lastColorValue = rgba;
lastColor = ColorUtils.getColor(rgba);
return lastColor;
}

View file

@ -19,7 +19,7 @@ import java.awt.Color;
import generic.theme.GColor;
import generic.theme.GThemeDefaults.Colors.Palette;
import generic.theme.TempColorUtils;
import ghidra.util.ColorUtils;
/**
* Miscellaneous information needed by fields to paint.
@ -130,7 +130,7 @@ public class PaintContext {
}
private void adjustSelectedHighlightColor() {
selectedHighlightColor = TempColorUtils.blend3(selectionColor, highlightColor);
selectedHighlightColor = ColorUtils.blend(selectionColor, highlightColor, 0.5);
}
public void setBackgroundColor(Color c) {

View file

@ -34,9 +34,9 @@ import docking.widgets.tree.GTreeNode;
import docking.widgets.tree.support.GTreeDragNDropHandler;
import docking.widgets.tree.support.GTreeNodeTransferable;
import generic.theme.GThemeDefaults.Colors.Palette;
import generic.theme.TempColorUtils;
import ghidra.framework.OperatingSystem;
import ghidra.framework.Platform;
import ghidra.util.ColorUtils;
import ghidra.util.Msg;
public class GTreeDragNDropAdapter implements DragSourceListener, DragGestureListener,
@ -158,7 +158,7 @@ public class GTreeDragNDropAdapter implements DragSourceListener, DragGestureLis
Graphics2D g2 = (Graphics2D) graphics;
GradientPaint mask;
Color treeBg = tree.getBackground();
Color transparentTreeBackground = TempColorUtils.withAlpha(treeBg, 100);
Color transparentTreeBackground = ColorUtils.withAlpha(treeBg, 100);
mask =
new GradientPaint(0, 0, transparentTreeBackground, 0, size.height >> 1,
Palette.NO_COLOR);

View file

@ -1,7 +1,7 @@
[Defaults]
// Fonts
font.standard = [font]panel.font
font.standard = [font]Panel.font
font.bold = font.standard[bold]
font.italics = font.standard[italic]
font.bold.italic = font.standard[bold][italic]

View file

@ -107,7 +107,11 @@ public abstract class AbstractThemeReader {
private IconValue parseIconProperty(String key, String value, int lineNumber) {
try {
return IconValue.parse(key, value);
IconValue parsedValue = IconValue.parse(key, value);
if (parsedValue == null) {
error(lineNumber, "Could not parse Icon value: " + value);
}
return parsedValue;
}
catch (ParseException e) {
error(lineNumber,

View file

@ -144,7 +144,7 @@ public class FontValue extends ThemeValue<Font> {
@Override
protected Font getUnresolvedReferenceValue(String unresolvedId) {
Msg.warn(this, "Could not resolve indirect font for" + unresolvedId +
Msg.warn(this, "Could not resolve indirect font for " + unresolvedId +
", using last resort default");
return LAST_RESORT_DEFAULT;
}

View file

@ -302,4 +302,17 @@ public class GThemeValueMap {
Objects.equals(iconMap, other.iconMap);
}
public void checkForUnresolvedReferences() {
// attempting to get the values for all properties, will print warnings if they are unresolved
for (ColorValue colorValue : colorMap.values()) {
colorValue.get(this);
}
for (FontValue fontValue : fontMap.values()) {
fontValue.get(this);
}
for (IconValue iconValue : iconMap.values()) {
iconValue.get(this);
}
}
}

View file

@ -200,6 +200,7 @@ public class Gui {
"Error setting LookAndFeel: " + lookAndFeel.getName(), e);
}
}
currentValues.checkForUnresolvedReferences();
}
/**
@ -630,6 +631,33 @@ public class Gui {
return getIcon(id, true);
}
/**
* Returns true if an color for the given Id has been defined
* @param id the id to check for an existing color.
* @return true if an color for the given Id has been defined
*/
public static boolean hasColor(String id) {
return currentValues.containsColor(id);
}
/**
* Returns true if an font for the given Id has been defined
* @param id the id to check for an existing font.
* @return true if an font for the given Id has been defined
*/
public static boolean hasFont(String id) {
return currentValues.containsFont(id);
}
/**
* Returns true if an icon for the given Id has been defined
* @param id the id to check for an existing icon.
* @return true if an icon for the given Id has been defined
*/
public static boolean hasIcon(String id) {
return currentValues.containsIcon(id);
}
/**
* Returns the {@link Icon} registered for the given id. If no icon is registered, returns
* the default icon (bomb).

View file

@ -125,7 +125,7 @@ public class IconValue extends ThemeValue<Icon> {
* @param key the key to associate the parsed value with
* @param value the color value to parse
* @return an IconValue with the given key and the parsed value
* @throws ParseException
* @throws ParseException if the value can't be parsed
*/
public static IconValue parse(String key, String value) throws ParseException {
String id = fromExternalId(key);
@ -139,10 +139,16 @@ public class IconValue extends ThemeValue<Icon> {
int modifierIndex = getModifierIndex(value);
if (modifierIndex < 0) {
if (value.isBlank()) {
return null;
}
return new IconValue(id, getIcon(value));
}
String baseIconString = value.substring(0, modifierIndex).trim();
if (baseIconString.isBlank()) {
return null;
}
Icon icon = getIcon(baseIconString);
String iconModifierString = value.substring(modifierIndex);
IconModifier modifier = IconModifier.parse(iconModifierString);

View file

@ -1,83 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package generic.theme;
import java.awt.Color;
import ghidra.util.WebColors;
/**
* A class to serve as a placeholder for migrating code. After the migration is complete, uses
* of this class can be removed, with the original code being restored in the process.
*/
public class TempColorUtils {
public static Color fromRgb(int rgb) {
return new Color(rgb);
}
public static Color fromRgba(int rgba) {
return new Color(rgba, true);
}
public static Color fromRgb(int r, int g, int b) {
return new Color(r, g, b);
}
public static Color fromRgba(int r, int g, int b, int a) {
return new Color(r, g, b, a);
}
public static Color fromRgba(float r, float g, float b, float a) {
return new Color(r, g, b, a);
}
public static Color withAlpha(Color c, int a) {
return new Color(c.getRed(), c.getGreen(), c.getBlue(), a);
}
public static Color blend1(Color c1, Color c2) {
int red = (c1.getRed() * 2 + c2.getRed()) / 3;
int green = (c1.getGreen() * 2 + c2.getGreen()) / 3;
int blue = (c1.getBlue() * 2 + c2.getBlue()) / 3;
return new Color(red, green, blue);
}
public static Color blend2(Color c, int value) {
int red = (c.getRed() + 3 * value) / 4;
int green = (c.getGreen() + 3 * value) / 4;
int blue = (c.getBlue() + 3 * value) / 4;
return new Color(red, green, blue);
}
public static Color blend3(Color c1, Color c2) {
int red = (c1.getRed() + c2.getRed()) / 2;
int green = (c1.getGreen() + c2.getGreen()) / 2;
int blue = (c1.getBlue() + c2.getBlue()) / 2;
return new Color(red, green, blue);
}
public static Color blend4(Color c1, Color c2) {
int red = (c1.getRed() * 3 + c2.getRed()) / 4;
int green = (c1.getGreen() * 3 + c2.getGreen()) / 4;
int blue = (c1.getBlue() * 3 + c2.getBlue()) / 4;
return new Color(red, green, blue);
}
public static String toString(Color c) {
return WebColors.toString(c, false);
}
}

View file

@ -1,30 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package generic.theme.builtin;
import javax.swing.LookAndFeel;
import generic.theme.DiscoverableGTheme;
import generic.theme.LafType;
/**
* Built-in GTheme that uses the FlatDarcula {@link LookAndFeel} and the dark application defaults.
*/
public class FlatDarculaTheme extends DiscoverableGTheme {
public FlatDarculaTheme() {
super("Flat Darcula Theme", LafType.FLAT_DARCULA, true);
}
}

View file

@ -168,28 +168,24 @@ public class ColorUtils {
* @param ratio the amount of the first color to include in the final output
* @return the new color
*/
public static Color blend(Color c1, Color c2, float ratio) {
public static Color blend(Color c1, Color c2, double ratio) {
if (c1 == null) {
return c2;
}
if (c2 == null) {
return c1;
}
float rgb1[] = new float[3];
float rgb2[] = new float[3];
c1.getColorComponents(rgb1);
c2.getColorComponents(rgb2);
int red = blend(c1.getRed(), c2.getRed(), ratio);
int green = blend(c1.getGreen(), c2.getRed(), ratio);
int blue = blend(c1.getBlue(), c2.getBlue(), ratio);
int alpha = blend(c1.getAlpha(), c2.getAlpha(), ratio);
return new Color(red, green, blue, alpha);
}
float inverse = (float) 1.0 - ratio;
//@formatter:off
Color color = new Color(
rgb1[0] * ratio + rgb2[0] * inverse,
rgb1[1] * ratio + rgb2[1] * inverse,
rgb1[2] * ratio + rgb2[2] * inverse);
//@formatter:on
return color;
private static int blend(int colorValue1, int colorValue2, double ratio) {
double value = colorValue1 * ratio + colorValue2 * (1.0 - ratio);
int result = (int) (value + 0.5);
return Math.max(result, 255);
}
/**
@ -228,6 +224,68 @@ public class ColorUtils {
};
/**
* Return the color object given a rgba value that includes the desired alpha value.
* @param rgba value where bits 24-31 are alpha, 16-23 are red, 8-15 are green, 0-7 are
* blue
* @return the color object given a rgba value that includes the desired alpha value
*/
public static Color getColor(int rgba) {
return new Color(rgba, true);
}
/**
* Return an opaque color object given for the given red, green, and blue values.
* @param red the red value (0 - 255)
* @param green the green value (0 - 255)
* @param blue the blue value (0 - 255)
* @return the color object for the given values
*/
public static Color getColor(int red, int green, int blue) {
return new Color(red, green, blue);
}
/**
* Return the color object given for the given red, green, blue, and alpha values.
* @param red the red value (0 - 255)
* @param green the green value (0 - 255)
* @param blue the blue value (0 - 255)
* @param alpha the alpha (transparency) value (0 - 255) with 0 being fully transparent and 255
* being fully opaque opaque
* @return the color object for the given values
*/
public static Color getColor(int red, int green, int blue, int alpha) {
return new Color(red, green, blue, alpha);
}
/**
* Returns an opaque color with the given rgb value. The resulting color will have an alpha
* value of 0xff.
*
* @param rgb the value where bits 16-23 are red, 8-15 are green, 0-7 are blue. Bits 24-31 will
* be set to 0xff.
* @return an opaque color with the given rgb value
*/
public static Color getOpaqueColor(int rgb) {
return new Color(rgb);
}
/**
* Creates a new color by averaging the red, green, blue, and alpha values from the given
* colors.
* @param color1 the first color to average
* @param color2 the second color to average
* @return a new color that is the average of the two given colors
*/
public static Color average(Color color1, Color color2) {
int red = (color1.getRed() + color2.getRed()) / 2;
int green = (color1.getGreen() + color2.getGreen()) / 2;
int blue = (color1.getBlue() + color2.getBlue()) / 2;
int alpha = (color1.getAlpha() + color2.getAlpha()) / 2;
return new Color(red, green, blue, alpha);
}
/**
* Blender of colors
*/

View file

@ -21,7 +21,7 @@ import java.util.Objects;
import javax.swing.Icon;
import generic.theme.TempColorUtils;
import ghidra.util.ColorUtils;
/**
* Icon class for for displaying overlapping icons. Icons are drawn in the order they
@ -148,7 +148,7 @@ public class MultiIcon implements Icon {
if (disabled) {
// Alpha blend to background
Color bgColor = c.getBackground();
g.setColor(TempColorUtils.withAlpha(bgColor, 128));
g.setColor(ColorUtils.withAlpha(bgColor, 128));
g.fillRect(x, y, width, height);
}
}

View file

@ -52,7 +52,7 @@ public class ThemePropertyFileReaderTest {
" icon.a.11 = icon.a.10",
" icon.a.12 = icon.a.10[size(17,21)]",
" icon.a.13 = core.png[size(17,21)]",
" icon.a.14 = icon.a.10{core.png[size(4,4)][move(8, 8)]",
" icon.a.14 = icon.a.10{core.png[size(4,4)][move(8, 8)]}",
"")));
//@formatter:on
@ -151,7 +151,8 @@ public class ThemePropertyFileReaderTest {
//@formatter:on
List<String> errors = reader.getErrors();
assertEquals(1, errors.size());
assertEquals("Error parsing file \"test\" at line: 3, Could not parse Color value: sdfsdf",
assertEquals(
"Error parsing theme file \"test\" at line: 3, Could not parse Color value: sdfsdf",
errors.get(0));
}
@ -184,6 +185,20 @@ public class ThemePropertyFileReaderTest {
}
@Test
public void testIconNoRightHandValueError() throws IOException {
//@formatter:off
ThemePropertyFileReader reader = new ThemePropertyFileReader("test", new StringReader(String.join("\n",
"[Defaults]",
" icon.b.1 = core.png",
" icon.b.2 = ",
"")));
//@formatter:on
List<String> errors = reader.getErrors();
assertEquals(1, errors.size());
}
private Color getColor(GThemeValueMap values, String id) {
ColorValue color = values.getColor(id);
return color.get(values);

View file

@ -29,9 +29,9 @@ import javax.swing.table.*;
import docking.widgets.table.GTable;
import generic.theme.GThemeDefaults.Colors.Palette;
import generic.theme.TempColorUtils;
import ghidra.framework.main.datatree.DataTreeDragNDropHandler;
import ghidra.framework.model.DomainFile;
import ghidra.util.ColorUtils;
public class ProjectDataTableDnDHandler implements DragSourceListener, DragGestureListener {
@ -174,7 +174,7 @@ public class ProjectDataTableDnDHandler implements DragSourceListener, DragGestu
Graphics2D g2 = (Graphics2D) graphics;
GradientPaint mask;
Color treeBackground = table.getBackground();
Color transparentTreeBackground = TempColorUtils.withAlpha(treeBackground, 200);
Color transparentTreeBackground = ColorUtils.withAlpha(treeBackground, 200);
mask = new GradientPaint(0, 0, transparentTreeBackground, 0, size.height >> 1,
Palette.NO_COLOR);
g2.setPaint(mask);

View file

@ -21,7 +21,6 @@ import java.util.List;
import org.junit.Test;
import generic.theme.TempColorUtils;
import ghidra.GhidraOptions;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.colorizer.ColorizingService;
@ -38,6 +37,7 @@ import ghidra.framework.plugintool.util.OptionsService;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.block.*;
import ghidra.util.WebColors;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
@ -97,8 +97,8 @@ public class BlockModelScreenShots extends GhidraScreenShotGenerator {
ColorizingService colorizer = tool.getService(ColorizingService.class);
// note: 2 colors that look good together and are just used for this example
Color c1 = TempColorUtils.fromRgb(232, 242, 254); // alice blue;
Color c2 = TempColorUtils.fromRgb(170, 204, 245); // light sky blue
Color c1 = WebColors.ALICE_BLUE;
Color c2 = WebColors.LIGHT_SKY_BLUE;
Color color = c1;
BasicBlockModel basicBlockModel = new BasicBlockModel(program);