diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/table/HexBigIntegerTableCellEditor.java b/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/table/HexBigIntegerTableCellEditor.java
index a5b685e578..2b1edec06b 100644
--- a/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/table/HexBigIntegerTableCellEditor.java
+++ b/Ghidra/Debug/ProposedUtils/src/main/java/docking/widgets/table/HexBigIntegerTableCellEditor.java
@@ -51,7 +51,7 @@ public class HexBigIntegerTableCellEditor extends AbstractCellEditor implements
input.getComponent().setBorder(UIManager.getBorder("Table.focusCellHighlightBorder"));
input.setMinValue(null); // allow negative numbers
input.setFormat(IntegerFormat.HEX);
- input.setUseNumberPrefix(false);
+ input.setAutoSwitchMode(false);
input.setShowNumberMode(true);
input.setHorizontalAlignment(SwingConstants.RIGHT);
diff --git a/Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/gui/search/dialog/BSimSearchDialog.java b/Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/gui/search/dialog/BSimSearchDialog.java
index 89f1389d7f..6178e308f2 100644
--- a/Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/gui/search/dialog/BSimSearchDialog.java
+++ b/Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/gui/search/dialog/BSimSearchDialog.java
@@ -17,16 +17,18 @@ package ghidra.features.bsim.gui.search.dialog;
import java.awt.BorderLayout;
import java.awt.Component;
-import java.math.BigInteger;
import java.util.List;
import java.util.Set;
+import java.util.function.Predicate;
import javax.swing.*;
import docking.DialogComponentProvider;
import docking.DockingWindowManager;
import docking.widgets.EmptyBorderButton;
-import docking.widgets.textfield.IntegerTextField;
+import docking.widgets.numberformat.IntegerFormatter;
+import docking.widgets.numberformat.IntegerFormatterFactory;
+import docking.widgets.textfield.GFormattedTextField;
import generic.theme.GIcon;
import ghidra.app.services.GoToService;
import ghidra.features.bsim.gui.BSimSearchPlugin;
@@ -49,7 +51,7 @@ public class BSimSearchDialog extends AbstractBSimSearchDialog {
private BSimFilterPanel filterPanel;
// Query Settings
- private IntegerTextField maxResultsField;
+ private GFormattedTextField maxResultsField;
public BSimSearchDialog(PluginTool tool, BSimSearchService service,
BSimServerManager serverManager, Set
++ Go to Offset is available from the popup menu. It allows you to jump to the row with + the given offset. +
+
+ * Auto-switching is on by default.
+ *
+ * @param newAutoSwitch true to auto-switch; false requires user to change modes manually
*/
- public void setUseNumberPrefix(boolean usePrefix) {
- BigInteger value = getValue();
- this.usePrefix = usePrefix;
- setValue(value);
+ public void setAutoSwitchMode(boolean newAutoSwitch) {
+ this.autoSwitch = newAutoSwitch;
+ textField.repaint();
}
/**
@@ -358,13 +394,35 @@ public class AbstractIntegerTextField {
return new ArrayList<>(allFormats);
}
+ /**
+ * Sets the minimum value. The given value must be less than or equal to 0.
+ * @param minValue the value
+ */
protected void setMinValue(BigInteger minValue) {
+
+ if (minValue != null) {
+ if (minValue.compareTo(BigInteger.ZERO) > 0) {
+ throw new IllegalArgumentException("Min value must be <= 0");
+ }
+ }
+
BigInteger value = getValue();
this.minValue = minValue;
setValue(value);
}
+ /**
+ * Sets the maximum value. The given value must be greater than 0.
+ * @param maxValue the value
+ */
protected void setMaxValue(BigInteger maxValue) {
+
+ if (maxValue != null) {
+ if (maxValue.compareTo(BigInteger.ZERO) <= 0) {
+ throw new IllegalArgumentException("Max value must be > 0");
+ }
+ }
+
BigInteger value = getValue();
this.maxValue = maxValue;
setValue(value);
@@ -381,6 +439,9 @@ public class AbstractIntegerTextField {
}
protected boolean isInBounds(BigInteger value) {
+ if (value == null) {
+ return false;
+ }
if (minValue != null && minValue.compareTo(value) > 0) {
return false;
}
@@ -391,21 +452,41 @@ public class AbstractIntegerTextField {
if (text.equals("0") || text.equals("-0")) {
return BigInteger.ZERO;
}
+
String prefix = format.getPrefix();
- if (usePrefix && !prefix.isBlank()) {
- if (text.startsWith(prefix)) {
- text = text.substring(prefix.length());
- }
- else if (text.startsWith("-" + prefix)) {
- text = "-" + text.substring(prefix.length() + 1);
- }
- else {
- return null;
- }
+ if (prefix.isBlank()) {
+ return format.parse(text);
}
+
+ // auto-switching requires a prefix so we know when we should switch formats
+ boolean requiresPrefix = autoSwitch;
+ boolean hasPrefix = hasPrefix(text, prefix);
+ if (requiresPrefix && !hasPrefix) {
+ return null;
+ }
+
+ text = text.replaceFirst(prefix, "");
return format.parse(text);
}
+ private boolean hasPrefix(String text, String prefix) {
+ return text.startsWith(prefix) || text.startsWith("-" + prefix);
+ }
+
+ private boolean hasFormatPrefix(String text, IntegerFormat format) {
+ if (text.startsWith("-")) {
+ if (!allowsNegative()) {
+ return false;
+ }
+ if (text.length() == 1) {
+ return true;
+ }
+ text = text.substring(1);
+ }
+
+ return format.getPrefix().startsWith(text);
+ }
+
private boolean isValidPrefix(String text, IntegerFormat format) {
if (text.startsWith("-")) {
if (!allowsNegative()) {
@@ -416,12 +497,13 @@ public class AbstractIntegerTextField {
}
text = text.substring(1);
}
- if (!usePrefix) {
- return false;
- }
- return usePrefix && format.getPrefix().startsWith(text);
+ return format.getPrefix().startsWith(text);
}
+//=================================================================================================
+// Inner Classes
+//=================================================================================================
+
/**
* DocumentFilter that prevents users from entering invalid data into the field.
*/
@@ -473,8 +555,9 @@ public class AbstractIntegerTextField {
if (text.isEmpty()) {
return true;
}
+
if (isValidPrefix(text, currentFormat)) {
- return true;
+ return true; // just a prefix and is valid
}
BigInteger value = parse(text, currentFormat);
@@ -482,8 +565,8 @@ public class AbstractIntegerTextField {
return isInBounds(value);
}
- if (usePrefix) {
- // only allow auto switching if using number prefix
+ // only allow auto switching if using number prefix
+ if (autoSwitch) {
return autoSwitchFormat(text);
}
return false;
@@ -491,11 +574,12 @@ public class AbstractIntegerTextField {
private boolean autoSwitchFormat(String text) {
for (IntegerFormat format : allFormats) {
- if (isValidPrefix(text, format)) {
+ if (hasFormatPrefix(text, format)) {
currentFormat = format;
textField.setFormat(format);
return true;
}
+
BigInteger value = parse(text, format);
if (value != null && isInBounds(value)) {
currentFormat = format;
@@ -515,4 +599,30 @@ public class AbstractIntegerTextField {
}
}
+ private class CustomHintMultiFormatTextField extends MultiFormatTextField {
+
+ public CustomHintMultiFormatTextField(int columns) {
+ super(columns, allFormats, m -> AbstractIntegerTextField.this.setFormat(m));
+ }
+
+ @Override
+ protected String getHintToolTipText() {
+ String superText = super.getHintToolTipText();
+ if (autoSwitch) {
+ return superText;
+ }
+
+ return superText + "
*Auto-switch mode disabled";
+ }
+
+ @Override
+ protected String getHint() {
+ String superHint = super.getHint();
+ if (autoSwitch) {
+ return superHint;
+ }
+
+ return superHint + "*";
+ }
+ }
}
diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/textfield/integer/MultiFormatTextField.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/textfield/integer/MultiFormatTextField.java
index fbd6a27083..cd8b68693e 100644
--- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/textfield/integer/MultiFormatTextField.java
+++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/textfield/integer/MultiFormatTextField.java
@@ -39,17 +39,18 @@ import utility.function.Callback;
public class MultiFormatTextField extends JTextField {
private static final String FONT_ID = "font.input.hint";
- private int hintWidth;
+
private boolean showFormatHint = true;
private List
+ Press %s-M to cycle input formats.%s
+ """.formatted(format.getDescription(), key, appendix);
+ }
+
/**
- * Sets the {@link IntegerFormat} that will be used to format and parse the text in this
- * field.
+ * Sets the {@link IntegerFormat} that will be used to format and parse the text in this field.
* @param format the number format that will be used to format and parse the text in this field
*/
public void setFormat(IntegerFormat format) {
@@ -127,7 +138,6 @@ public class MultiFormatTextField extends JTextField {
if (indexOf >= 0) {
currentFormatIndex = indexOf;
}
- updateFormatNameWidth();
repaint();
}
@@ -153,6 +163,10 @@ public class MultiFormatTextField extends JTextField {
g.setFont(Gui.getFont(FONT_ID));
g.setColor(Messages.HINT);
+ String hint = getHint();
+ FontMetrics fontMetrics = getFontMetrics(Gui.getFont(FONT_ID));
+ int hintWidth = fontMetrics.stringWidth(hint);
+
Dimension size = getSize();
Insets insets = getInsets();
int x;
@@ -163,8 +177,7 @@ public class MultiFormatTextField extends JTextField {
x = size.width - insets.right - hintWidth;
}
int y = size.height - insets.bottom - 1;
- IntegerFormat format = formats.get(currentFormatIndex);
- GraphicsUtils.drawString(this, g, format.getName(), x, y);
+ GraphicsUtils.drawString(this, g, hint, x, y);
g.setFont(savedFont);
}
diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/values/IntValue.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/values/IntValue.java
index 039b208a14..83b8e613d3 100644
--- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/values/IntValue.java
+++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/values/IntValue.java
@@ -70,7 +70,7 @@ public class IntValue extends AbstractValue