GP-1981 Review fixes

This commit is contained in:
ghidragon 2022-11-02 14:11:32 -04:00
parent 9679752523
commit a92a27e9f1
90 changed files with 375 additions and 381 deletions

View file

@ -1,2 +1,2 @@
MODULE FILE LICENSE: lib/flatlaf-2.1.jar Apache License 2.0

View file

@ -26,8 +26,6 @@ eclipse.project.name = 'Framework Docking'
dependencies {
api project(':Generic')
api project(':Help')
api 'com.formdev:flatlaf:2.2'
// include code from src/test in Generic
testImplementation project(path: ':Generic', configuration: 'testArtifacts')

View file

@ -124,8 +124,6 @@ icon.dragon.256 = GhidraIcon256.png
icon.help.navigation.aid.disabled.overlay = icon.not.allowed
icon.help.navigation.aid.enabled = software-update-available.png
icon.options.node.leaf = icon.properties
icon.filechooser.places.my.computer = computer.png
icon.filechooser.places.desktop = desktop.png
icon.filechooser.places.home = user-home.png

View file

@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
li { font-family:times new roman; font-size:14pt; }
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; }
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
/*

View file

@ -11,8 +11,6 @@
</HEAD>
<BODY>
Theming Development Documentation
<H1>Ghidra Theming Developer Documentation</H1>
<P>This document provides everything an application developer should know when developing

View file

@ -16,6 +16,7 @@
package docking;
import java.awt.*;
import java.awt.geom.GeneralPath;
import javax.swing.Icon;
@ -24,34 +25,86 @@ import javax.swing.Icon;
*/
public class CloseIcon implements Icon {
private int size;
private int margin;
private Color color;
private Shape shape;
/**
* Creates a close icon.
* @param size the width and height of the icon
* @param margin the margin around the "x"
* @param color the color of the "x"
*/
public CloseIcon(int size, int margin, Color color) {
this.size = size;
this.margin = margin;
* Creates a close icon.
* @param isSmall false signals to use a 16x16 size; true signals to use an 8x8 size
* @param color the color of the "x"
*/
public CloseIcon(boolean isSmall, Color color) {
this.size = isSmall ? 8 : 16;
this.color = color;
this.shape = buildShape();
}
private Shape buildShape() {
GeneralPath path = new GeneralPath();
/*
We use trial and error sizing. This class allows clients to specify the icon size. At
the time of writing, there were only 2 sizes in use: 16 and 8 pixels. If more size
needs arise, we can revisit how the values below are chosen.
*/
double margin = 2;
double shapeSize = 11;
double thickness = 1.7;
if (size == 8) {
margin = 0;
shapeSize = 7;
thickness = 1;
}
double p1x = margin;
double p1y = margin + thickness;
double p2x = margin + thickness;
double p2y = margin;
double p3x = margin + shapeSize;
double p3y = margin + shapeSize - thickness;
double p4x = margin + shapeSize - thickness;
double p4y = margin + shapeSize;
path.moveTo(p1x, p1y);
path.lineTo(p2x, p2y);
path.lineTo(p3x, p3y);
path.lineTo(p4x, p4y);
path.lineTo(p1x, p1y);
p1x = margin + shapeSize - thickness;
p1y = margin;
p2x = margin + shapeSize;
p2y = margin + thickness;
p3x = margin + thickness;
p3y = margin + shapeSize;
p4x = margin;
p4y = margin + shapeSize - thickness;
path.moveTo(p1x, p1y);
path.lineTo(p2x, p2y);
path.lineTo(p3x, p3y);
path.lineTo(p4x, p4y);
path.lineTo(p1x, p1y);
path.closePath();
return path;
}
@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(color);
int xStart = x + margin;
int yStart = y + margin;
int xEnd = x + size - margin;
int yEnd = y + size - margin;
g.drawLine(xStart, yStart, xEnd, yEnd);
g.drawLine(xStart, yEnd, xEnd, yStart);
g.drawLine(xStart + 1, yStart, xEnd + 1, yEnd);
g.drawLine(xStart + 1, yEnd, xEnd + 1, yStart);
g.drawLine(xStart - 1, yStart, xEnd - 1, yEnd);
g.drawLine(xStart - 1, yEnd, xEnd - 1, yStart);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
try {
g2d.translate(x, y);
g2d.setColor(color);
g2d.fill(shape);
}
finally {
g2d.translate(-x, -y);
}
}
@Override

View file

@ -32,8 +32,8 @@ import ghidra.util.task.SwingUpdateManager;
*/
class DockableToolBarManager {
private static final Color BUTTON_COLOR = new GColor("color.fg.button");
private static final Icon CLOSE_ICON = new CloseIcon(16, 4, BUTTON_COLOR);
private static final Icon MENU_ICON = new DropDownMenuIcon(16, 4, 4, BUTTON_COLOR);
private static final Icon CLOSE_ICON = new CloseIcon(false, BUTTON_COLOR);
private Icon MENU_ICON = new DropDownMenuIcon(BUTTON_COLOR);
private GenericHeader dockableHeader;
private ToolBarManager toolBarManager;

View file

@ -16,6 +16,7 @@
package docking;
import java.awt.*;
import java.awt.geom.GeneralPath;
import javax.swing.Icon;
@ -23,49 +24,71 @@ import javax.swing.Icon;
* Icon for a drop down menu button (triangle pointing down)
*/
public class DropDownMenuIcon implements Icon {
private int size;
private int xMargin;
private int yMargin;
private static final int ICON_SIZE = 16;
private Color color;
private Shape shape;
/**
* Creates a drop down menu icon.
* @param size the width and height of the icon
* @param xMargin the margin around triangle base
* @param yMargin the margin around triangle height
* @param color the color of the triangle
*/
public DropDownMenuIcon(int size, int xMargin, int yMargin, Color color) {
this.size = size;
this.xMargin = xMargin;
this.yMargin = yMargin;
public DropDownMenuIcon(Color color) {
this.color = color;
this.shape = buildShape();
}
private Shape buildShape() {
GeneralPath path = new GeneralPath();
double iconSize = 16;
double height = 6;
double width = 10;
double leftMargin = (iconSize - width) / 2;
double topMargin = (iconSize - height) / 2;
// draw a triangle pointing down; p1 is the bottom; p2 is the left
double p1x = leftMargin + (width / 2);
double p1y = topMargin + height;
double p2x = leftMargin;
double p2y = topMargin;
double p3x = leftMargin + width;
double p3y = topMargin;
path.moveTo(p1x, p1y);
path.lineTo(p2x, p2y);
path.lineTo(p3x, p3y);
path.lineTo(p1x, p1y);
path.closePath();
return path;
}
@Override
public void paintIcon(Component c, Graphics g, int x, int y) {
g.setColor(color);
// draw a triangle pointing down
int p1x = x + size / 2;
int p1y = y + size - yMargin;
int p2x = x + xMargin;
int p2y = y + yMargin;
int p3x = x + size - xMargin + 1;
int p3y = y + yMargin;
int xPoints[] = { p1x, p2x, p3x };
int yPoints[] = { p1y, p2y, p3y };
g.fillPolygon(xPoints, yPoints, 3);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
try {
g2d.translate(x, y);
g2d.setColor(color);
g2d.fill(shape);
}
finally {
g2d.translate(-x, -y);
}
}
@Override
public int getIconWidth() {
return size;
return ICON_SIZE;
}
@Override
public int getIconHeight() {
return size;
return ICON_SIZE;
}
}

View file

@ -50,7 +50,7 @@ public class DockingApplicationConfiguration extends ApplicationConfiguration {
super.initializeApplication();
Gui.initialize();
LookAndFeelUtils.platformSpecificFixups();
LookAndFeelUtils.performPlatformSpecificFixups();
if (showSplashScreen) {
SplashScreen.showSplashScreen();

View file

@ -133,12 +133,6 @@ public class IconPropertyEditor extends PropertyEditorSupport {
return panel;
}
// private void iconChanged() {
// Icon icon = dropDown.getSelectedValue();
// Msg.debug(this, "action listener: icon changed " + icon);
// dropDown.getSelectedValue();
// }
private void iconChanged(Icon icon) {
boolean isDropDownWindowShowing = dropDown.isMatchingListShowing();
if (!isDropDownWindowShowing) {
@ -216,10 +210,8 @@ public class IconPropertyEditor extends PropertyEditorSupport {
previewLabel = new GDLabel("");
previewLabel.setIcon(ResourceManager.getDefaultIcon());
// previewLabel.setPreferredSize(new Dimension(350, 50));
previewLabel.setHorizontalAlignment(SwingConstants.CENTER);
previewLabel.setVerticalAlignment(SwingConstants.CENTER);
// previewLabel.setMinimumSize(new Dimension(300, 50));
panel.add(previewLabel, BorderLayout.CENTER);
panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
return panel;

View file

@ -23,11 +23,12 @@ import docking.widgets.tree.GTreeLazyNode;
import docking.widgets.tree.GTreeNode;
import generic.theme.GIcon;
import ghidra.framework.options.Options;
import resources.Icons;
class OptionsTreeNode extends GTreeLazyNode {
private final static Icon OPEN_FOLDER_ICON = new GIcon("icon.folder.open");
private final static Icon CLOSED_FOLDER_ICON = new GIcon("icon.folder.closed");
private final static Icon PROPERTIES_ICON = new GIcon("icon.options.node.leaf");
private final static Icon OPEN_FOLDER_ICON = Icons.OPEN_FOLDER_ICON;
private final static Icon CLOSED_FOLDER_ICON = Icons.CLOSED_FOLDER_ICON;
private final static Icon PROPERTIES_ICON = new GIcon("icon.properties");
private final Options options;
private final String name;

View file

@ -107,7 +107,7 @@ public class ThemeColorTable extends JPanel implements ActionContextProvider {
@Override
public ActionContext getActionContext(MouseEvent e) {
if (e.getSource() == table) {
if (e != null && e.getSource() == table) {
ColorValue currentValue = filterTable.getSelectedRowObject();
if (currentValue == null) {
return null;

View file

@ -79,7 +79,7 @@ public class ThemeDialog extends DialogComponentProvider {
.enabledWhen(c -> c.isChanged())
.popupWhen(c -> true)
.helpLocation(new HelpLocation("Theming", "Restore_Value"))
.onAction(c -> c.getThemeValue().makeCurrentValue())
.onAction(c -> c.getThemeValue().installValue())
.build();
addAction(resetValueAction);
}

View file

@ -25,7 +25,7 @@ import docking.DockingWindowManager;
import generic.theme.ThemeValue;
/**
* Base class for Theme properties (Colors, Fonts, and Icons)
* Base class for Theme property Editors (Colors, Fonts, and Icons)
*
* @param <T> the base property (Color, Font, or Icon)
*/

View file

@ -1152,6 +1152,7 @@ public class FieldPanel extends JPanel
}
private Color blend(Color primary, Color secondary) {
return ColorUtils.blend(primary, secondary, 0.75);
}

View file

@ -32,9 +32,7 @@ import generic.theme.GColor;
public class DockingTabRenderer extends JPanel {
private static final int MAX_TITLE_LENGTH = 25;
private Icon CLOSE_ICON = new CloseIcon(8, 1, new GColor("color.fg.button"));
private Icon EMPTY_ICON = CLOSE_ICON;
//TODO if we don't want the close icon to come and go, then this class can be greatly simplified
private Icon CLOSE_ICON = new CloseIcon(true, new GColor("color.fg.button"));
private JLabel titleLabel;
private JLabel iconLabel;
@ -56,9 +54,9 @@ public class DockingTabRenderer extends JPanel {
setTitle(tabTitle, fullTitle);
closeButton.setToolTipText("Close " + tabTitle);
closeButton.setIcon(EMPTY_ICON); // no icon until we rollover the tab
closeButton.setFocusable(false);
closeButton.addActionListener(closeListener);
closeButton.setIcon(CLOSE_ICON);
closeButton.setRolloverIcon(CLOSE_ICON);
JPanel container = new JPanel();
@ -84,20 +82,10 @@ public class DockingTabRenderer extends JPanel {
titleLabel.addMouseListener(eventForwardingListener);
titleLabel.addMouseMotionListener(eventForwardingListener);
// listeners to know when to hide our close button (from the tabbed pane)
final ButtonIconSwapperMouseListener iconListener =
new ButtonIconSwapperMouseListener(tabbedPane);
installIconListener(container, tabbedPane, iconListener);
// listeners to know when to hide our close button (from this panel)
addMouseListener(iconListener);
addMouseMotionListener(iconListener);
installMouseForwardingListenerWorkaround(tabbedPane, iconListener);
installMouseForwardingListenerWorkaround(tabbedPane);
}
private void installMouseForwardingListenerWorkaround(final JTabbedPane tabbedPane,
final ButtonIconSwapperMouseListener iconListener) {
private void installMouseForwardingListenerWorkaround(final JTabbedPane tabbedPane) {
forwardingListener = new TabContainerForwardingMouseListener(tabbedPane);
@ -114,20 +102,14 @@ public class DockingTabRenderer extends JPanel {
boolean isDisplayable = isDisplayable();
if (isDisplayable) {
// remove and add in order to prevent duplicate adding
myParent.removeMouseListener(iconListener);
myParent.removeMouseMotionListener(iconListener);
myParent.removeMouseListener(forwardingListener);
myParent.removeMouseMotionListener(forwardingListener);
myParent.addMouseListener(iconListener);
myParent.addMouseMotionListener(iconListener);
myParent.addMouseListener(forwardingListener);
myParent.addMouseMotionListener(forwardingListener);
hierarchyListener = this;
}
else if (hierarchyListener != null) {
myParent.removeMouseListener(iconListener);
myParent.removeMouseMotionListener(iconListener);
myParent.removeMouseListener(forwardingListener);
myParent.removeMouseMotionListener(forwardingListener);
@ -145,20 +127,6 @@ public class DockingTabRenderer extends JPanel {
return title;
}
// add listeners to the tabbed pane so that the icon for closing appears (and disappears) as
// needed
private void installIconListener(Container container, JTabbedPane tabbedPane,
ButtonIconSwapperMouseListener iconListener) {
Component[] components = container.getComponents();
for (Component component : components) {
component.addMouseListener(iconListener);
}
tabbedPane.addMouseListener(iconListener);
// we need this due to the gaps between the renderer and the tabbed pane
tabbedPane.addMouseMotionListener(iconListener);
}
public void installRenameAction(MouseListener listener) {
this.renameListener = listener;
}
@ -193,57 +161,6 @@ public class DockingTabRenderer extends JPanel {
// Inner Classes
//==================================================================================================
/**
* A class to hide/show the close button's icon to make it appear that the button is hidden
* and removed.
*/
private class ButtonIconSwapperMouseListener extends MouseAdapter {
private final JTabbedPane tabbedPane;
ButtonIconSwapperMouseListener(JTabbedPane tabbedPane) {
this.tabbedPane = tabbedPane;
}
private void updateButton(MouseEvent e) {
Point point = e.getPoint();
Point tabbedPaneRelativePoint =
SwingUtilities.convertPoint(e.getComponent(), point, tabbedPane);
int x = tabbedPaneRelativePoint.x;
int y = tabbedPaneRelativePoint.y;
int tabIndex = tabbedPane.indexAtLocation(x, y);
if (tabIndex < 0) {
// no tab for the given point (can happen when over the tabbed pane, but not
// over any tab)
closeButton.setIcon(EMPTY_ICON);
return;
}
Component tabComponent = tabbedPane.getTabComponentAt(tabIndex);
if (SwingUtilities.isDescendingFrom(closeButton, tabComponent)) {
closeButton.setIcon(CLOSE_ICON);
}
else {
closeButton.setIcon(EMPTY_ICON);
}
}
@Override
public void mouseMoved(MouseEvent e) {
updateButton(e);
}
@Override
public void mouseEntered(MouseEvent e) {
updateButton(e);
}
@Override
public void mouseExited(MouseEvent e) {
closeButton.setIcon(EMPTY_ICON);
}
}
/**
* A class designed to listen for mouse events on this renderer component which it will then
* forward on to the given component.

View file

@ -72,7 +72,7 @@ public class LookAndFeelUtils {
}
}
public static void platformSpecificFixups() {
public static void performPlatformSpecificFixups() {
// Set the dock icon for macOS
if (Taskbar.isTaskbarSupported()) {
Taskbar taskbar = Taskbar.getTaskbar();

View file

@ -204,8 +204,8 @@ public class ThemeUtilsTest extends AbstractDockingTest {
}
@Test
public void testParseGroupingsParseError() {
String source = "(ab (cd))(ef)( gh))";
public void testParseGroupingsWithUnbalancedGroups() {
String source = "(ab (cd))(ef)( gh))"; // note the groupings are unbalanced
try {
ThemeValueUtils.parseGroupings(source, '(', ')');
fail("Expected parse Exception");
@ -216,8 +216,8 @@ public class ThemeUtilsTest extends AbstractDockingTest {
}
@Test
public void testParseGroupingsParseError2() {
String source = " xx";
public void testParseGroupingsWhenNoGroupingsExist() {
String source = "xx yy"; // note there are no grouping chars
try {
ThemeValueUtils.parseGroupings(source, '(', ')');
fail("Expected parse Exception");