mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-2978: Rename StateEditing to Control. Disable selection of control modes by context.
This commit is contained in:
parent
16d80129b8
commit
f1c060d378
43 changed files with 589 additions and 555 deletions
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
package docking.action;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -281,6 +282,21 @@ public interface DockingActionIf extends HelpDescriptor {
|
|||
*/
|
||||
public JMenuItem createMenuItem(boolean isPopup);
|
||||
|
||||
/**
|
||||
* Returns a component to represent this action in the menu.
|
||||
* <p>
|
||||
* Typically, this is the menu item that triggers the action. However, some actions may wish to
|
||||
* use components other than menu items. For example, they may produce component for helping to
|
||||
* organize the menu visually.
|
||||
* @param isPopup true if the action should use its Popup MenuData, else it uses the MenuBar
|
||||
* MenuData.
|
||||
* @return the component
|
||||
* @see #createMenuItem(boolean)
|
||||
*/
|
||||
public default Component createMenuComponent(boolean isPopup) {
|
||||
return createMenuItem(isPopup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this action should be added to a window (either the main window or a
|
||||
* secondary detached window). By default, this method will return true for the main window
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
/* ###
|
||||
* 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.menu;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.DockingUtils;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.MenuData;
|
||||
import docking.widgets.label.GDHtmlLabel;
|
||||
import generic.theme.GThemeDefaults.Colors.Palette;
|
||||
import ghidra.util.HTMLUtilities;
|
||||
|
||||
/**
|
||||
* An action that can be added to a menu in order to separate menu items into groups
|
||||
*/
|
||||
public class HorizontalRuleAction extends DockingAction {
|
||||
private static final String PADDING = " ";
|
||||
|
||||
private static int idCount = 0;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param owner the action owner
|
||||
* @param topName the name that will appear above the separator bar
|
||||
* @param bottomName the name that will appear below the separator bar
|
||||
*/
|
||||
public HorizontalRuleAction(String owner, String topName, String bottomName) {
|
||||
super("HorizontalRuleAction: " + ++idCount, owner, false);
|
||||
setEnabled(false);
|
||||
|
||||
markHelpUnnecessary();
|
||||
|
||||
MenuData menuData = new MenuData(new String[] { "" });
|
||||
// The menu name is both names, one over the other, in a small, light grayish font.
|
||||
String topHtml = HTMLUtilities.escapeHTML(topName);
|
||||
String bottomHtml = HTMLUtilities.escapeHTML(bottomName);
|
||||
menuData.setMenuItemNamePlain(String.format("""
|
||||
<HTML><CENTER><FONT SIZE=2 COLOR="%s">%s<BR>%s</FONT></CENTER>
|
||||
""", Palette.SILVER, topHtml, bottomHtml));
|
||||
setMenuBarData(menuData);
|
||||
|
||||
// the description is meant to be used for the tooltip and is larger
|
||||
setDescription(String.format("""
|
||||
<HTML><CENTER><B>%s</B><HR><B>%s</B></CENTER>
|
||||
""", PADDING + topHtml + PADDING, PADDING + bottomHtml + PADDING));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
// this does't actually do anything
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSeparator createMenuComponent(boolean isPopup) {
|
||||
String[] menuPath = getMenuBarData().getMenuPath();
|
||||
String name = menuPath[menuPath.length - 1];
|
||||
String description = getDescription();
|
||||
return new LabeledSeparator(name, description);
|
||||
}
|
||||
|
||||
private static class LabeledSeparator extends JSeparator {
|
||||
|
||||
private final int EMTPY_SEPARATOR_HEIGHT = 10;
|
||||
private final int TEXT_SEPARATOR_HEIGHT = 32;
|
||||
private JLabel renderer = new GDHtmlLabel();
|
||||
|
||||
private int separatorHeight = EMTPY_SEPARATOR_HEIGHT;
|
||||
|
||||
private LabeledSeparator(String name, String description) {
|
||||
setBorder(BorderFactory.createEmptyBorder(20, 0, 20, 0));
|
||||
renderer.setText(name);
|
||||
DockingUtils.setTransparent(renderer);
|
||||
renderer.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
renderer.setVisible(true);
|
||||
|
||||
if (!StringUtils.isBlank(name)) {
|
||||
separatorHeight = TEXT_SEPARATOR_HEIGHT;
|
||||
}
|
||||
|
||||
// IF WE CHOOSE TO SHOW TOOLTIPS (and below too)...
|
||||
// setToolTipText( description );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
Dimension d = getSize();
|
||||
|
||||
// some edge padding, for classiness
|
||||
int pad = 10;
|
||||
int center = separatorHeight >> 1;
|
||||
int x = 0 + pad;
|
||||
int y = center;
|
||||
int w = d.width - pad;
|
||||
g.setColor(getForeground());
|
||||
g.drawLine(x, y, w, y);
|
||||
|
||||
// drop-shadow
|
||||
g.setColor(getBackground());
|
||||
g.drawLine(x, (y + 1), w, (y + 1));
|
||||
|
||||
// now add our custom text
|
||||
renderer.setSize(getSize());
|
||||
renderer.paint(g);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
// assume horizontal
|
||||
return new Dimension(0, separatorHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize() {
|
||||
return new Dimension(0, separatorHeight);
|
||||
}
|
||||
|
||||
//
|
||||
// USE THE CODE BELOW IF WE WANT TOOLTIPS
|
||||
//
|
||||
// @Override
|
||||
// public String getToolTipText( MouseEvent event ) {
|
||||
// // We only want to show the tooltip when the user is over the label. Since the label
|
||||
// // is not on the screen, we cannot ask it if the mouse location is within its bounds.
|
||||
// Dimension labelSize = renderer.getPreferredSize();
|
||||
// if ( labelSize.height == 0 && labelSize.width == 0 ) {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// Dimension mySize = getSize();
|
||||
// int centerX = mySize.width >> 1;
|
||||
//
|
||||
// int labelMidPoint = labelSize.width >> 1;
|
||||
// int labelStartX = centerX - labelMidPoint;
|
||||
// int labelEndX = centerX + labelMidPoint;
|
||||
//
|
||||
// Point mousePoint = event.getPoint();
|
||||
// boolean insideLabel = (mousePoint.x >= labelStartX) && (mousePoint.x <= labelEndX);
|
||||
// if ( !insideLabel ) {
|
||||
// return null;
|
||||
// }
|
||||
// return getToolTipText();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Point getToolTipLocation( MouseEvent event ) {
|
||||
// Rectangle bounds = getBounds();
|
||||
// bounds.x += bounds.width;
|
||||
// bounds.y = 0;
|
||||
// return bounds.getLocation();
|
||||
// }
|
||||
}
|
||||
}
|
|
@ -146,6 +146,16 @@ public abstract class MultiStateDockingAction<T> extends DockingAction {
|
|||
actionStates.addAll(newStates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given state can be selected
|
||||
*
|
||||
* @param state the state to check
|
||||
* @return true (the default) if selectable, false to disable
|
||||
*/
|
||||
protected boolean isStateEnabled(ActionState<T> state) {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected List<DockingActionIf> getStateActions() {
|
||||
updateStates();
|
||||
List<DockingActionIf> actions = new ArrayList<>(actionStates.size());
|
||||
|
@ -154,6 +164,8 @@ public abstract class MultiStateDockingAction<T> extends DockingAction {
|
|||
DockingActionIf a = useCheckboxForIcons
|
||||
? new ActionStateToggleAction(actionState, isSelected)
|
||||
: new ActionStateAction(actionState, isSelected);
|
||||
boolean isEnabled = isStateEnabled(actionState);
|
||||
a.setEnabled(isEnabled);
|
||||
actions.add(a);
|
||||
}
|
||||
return actions;
|
||||
|
|
|
@ -24,12 +24,9 @@ import javax.swing.*;
|
|||
import javax.swing.border.Border;
|
||||
import javax.swing.event.*;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import docking.*;
|
||||
import docking.action.*;
|
||||
import docking.widgets.EmptyBorderButton;
|
||||
import docking.widgets.label.GDHtmlLabel;
|
||||
import generic.theme.GThemeDefaults.Colors;
|
||||
import ghidra.util.Swing;
|
||||
import resources.ResourceManager;
|
||||
|
@ -150,8 +147,9 @@ public class MultipleActionDockingToolbarButton extends EmptyBorderButton {
|
|||
return manager.getActiveComponentProvider();
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* Show a popup containing all the actions below the button
|
||||
*
|
||||
* @return the popup menu that was shown
|
||||
*/
|
||||
JPopupMenu showPopup() {
|
||||
|
@ -181,19 +179,13 @@ public class MultipleActionDockingToolbarButton extends EmptyBorderButton {
|
|||
List<DockingActionIf> actionList = multipleAction.getActionList(getActionContext());
|
||||
for (DockingActionIf dockingAction : actionList) {
|
||||
|
||||
String[] menuPath = dockingAction.getMenuBarData().getMenuPath();
|
||||
String name = menuPath[menuPath.length - 1];
|
||||
|
||||
// this is a special signal to say we should insert a separator and not a real menu item
|
||||
if (!dockingAction.isEnabled()) {
|
||||
String description = dockingAction.getDescription();
|
||||
JSeparator separator = new ProgramNameSeparator(name, description);
|
||||
menu.add(separator);
|
||||
Component component = dockingAction.createMenuComponent(false);
|
||||
if (!(component instanceof JMenuItem item)) {
|
||||
// not an actual item, e.g., a separator as in HorizontalRuleAction
|
||||
menu.add(component);
|
||||
continue;
|
||||
}
|
||||
|
||||
JMenuItem item = dockingAction.createMenuItem(false);
|
||||
|
||||
// a custom Ghidra UI that handles alignment issues and allows for tabulating presentation
|
||||
item.setUI((DockingMenuItemUI) DockingMenuItemUI.createUI(item));
|
||||
final DockingActionIf delegateAction = dockingAction;
|
||||
|
@ -415,95 +407,4 @@ public class MultipleActionDockingToolbarButton extends EmptyBorderButton {
|
|||
|
||||
}
|
||||
|
||||
private static class ProgramNameSeparator extends JSeparator {
|
||||
|
||||
private final int EMTPY_SEPARATOR_HEIGHT = 10;
|
||||
private final int TEXT_SEPARATOR_HEIGHT = 32;
|
||||
private JLabel renderer = new GDHtmlLabel();
|
||||
|
||||
private int separatorHeight = EMTPY_SEPARATOR_HEIGHT;
|
||||
|
||||
private ProgramNameSeparator(String name, String description) {
|
||||
setBorder(BorderFactory.createEmptyBorder(20, 0, 20, 0));
|
||||
renderer.setText(name);
|
||||
DockingUtils.setTransparent(renderer);
|
||||
renderer.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
renderer.setVisible(true);
|
||||
|
||||
if (!StringUtils.isBlank(name)) {
|
||||
separatorHeight = TEXT_SEPARATOR_HEIGHT;
|
||||
}
|
||||
|
||||
// IF WE CHOOSE TO SHOW TOOLTIPS (and below too)...
|
||||
// setToolTipText( description );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintComponent(Graphics g) {
|
||||
Dimension d = getSize();
|
||||
|
||||
// some edge padding, for classiness
|
||||
int pad = 10;
|
||||
int center = separatorHeight >> 1;
|
||||
int x = 0 + pad;
|
||||
int y = center;
|
||||
int w = d.width - pad;
|
||||
g.setColor(getForeground());
|
||||
g.drawLine(x, y, w, y);
|
||||
|
||||
// drop-shadow
|
||||
g.setColor(getBackground());
|
||||
g.drawLine(x, (y + 1), w, (y + 1));
|
||||
|
||||
// now add our custom text
|
||||
renderer.setSize(getSize());
|
||||
renderer.paint(g);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
// assume horizontal
|
||||
return new Dimension(0, separatorHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dimension getMinimumSize() {
|
||||
return new Dimension(0, separatorHeight);
|
||||
}
|
||||
|
||||
//
|
||||
// USE THE CODE BELOW IF WE WANT TOOLTIPS
|
||||
//
|
||||
// @Override
|
||||
// public String getToolTipText( MouseEvent event ) {
|
||||
// // We only want to show the tooltip when the user is over the label. Since the label
|
||||
// // is not on the screen, we cannot ask it if the mouse location is within its bounds.
|
||||
// Dimension labelSize = renderer.getPreferredSize();
|
||||
// if ( labelSize.height == 0 && labelSize.width == 0 ) {
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// Dimension mySize = getSize();
|
||||
// int centerX = mySize.width >> 1;
|
||||
//
|
||||
// int labelMidPoint = labelSize.width >> 1;
|
||||
// int labelStartX = centerX - labelMidPoint;
|
||||
// int labelEndX = centerX + labelMidPoint;
|
||||
//
|
||||
// Point mousePoint = event.getPoint();
|
||||
// boolean insideLabel = (mousePoint.x >= labelStartX) && (mousePoint.x <= labelEndX);
|
||||
// if ( !insideLabel ) {
|
||||
// return null;
|
||||
// }
|
||||
// return getToolTipText();
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public Point getToolTipLocation( MouseEvent event ) {
|
||||
// Rectangle bounds = getBounds();
|
||||
// bounds.x += bounds.width;
|
||||
// bounds.y = 0;
|
||||
// return bounds.getLocation();
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue