BitFields - additional refinements

This commit is contained in:
ghidra1 2019-07-03 11:17:56 -04:00
parent 286d2a6258
commit 3f1ffb276f
4 changed files with 124 additions and 39 deletions

View file

@ -271,6 +271,10 @@ public class BitFieldEditorPanel extends JPanel {
@Override @Override
public void mousePressed(MouseEvent e) { public void mousePressed(MouseEvent e) {
if (e.isConsumed()) {
return;
}
e.consume();
selectionActive = false; selectionActive = false;
if (e.getButton() == MouseEvent.BUTTON1 && bitOffsetInput.isEnabled()) { if (e.getButton() == MouseEvent.BUTTON1 && bitOffsetInput.isEnabled()) {
bitSizeModel.setValue(1L); // must change size first bitSizeModel.setValue(1L); // must change size first
@ -282,10 +286,12 @@ public class BitFieldEditorPanel extends JPanel {
@Override @Override
public void mouseDragged(MouseEvent e) { public void mouseDragged(MouseEvent e) {
if (!selectionActive) { if (!selectionActive || e.isConsumed()) {
return; return;
} }
e.consume();
Point p = e.getPoint(); Point p = e.getPoint();
int bitOffset = placementComponent.getBitOffset(p); int bitOffset = placementComponent.getBitOffset(p);
if (bitOffset == lastBit) { if (bitOffset == lastBit) {
@ -314,7 +320,10 @@ public class BitFieldEditorPanel extends JPanel {
@Override @Override
public void mouseReleased(MouseEvent e) { public void mouseReleased(MouseEvent e) {
selectionActive = false; if (selectionActive && !e.isConsumed()) {
e.consume();
selectionActive = false;
}
} }
} }
@ -649,22 +658,19 @@ public class BitFieldEditorPanel extends JPanel {
@Override @Override
public void mouseWheelMoved(MouseWheelEvent mwe) { public void mouseWheelMoved(MouseWheelEvent mwe) {
if (!isEnabled()) { if (!isEnabled() || mwe.getModifiersEx() != 0 || mwe.isConsumed()) {
return; return;
} }
if (mwe.getScrollType() != MouseWheelEvent.WHEEL_UNIT_SCROLL) { if (mwe.getScrollType() != MouseWheelEvent.WHEEL_UNIT_SCROLL) {
// TODO: should we handle other modes?
return; return;
} }
mwe.consume();
SpinnerNumberModel m = (SpinnerNumberModel) getModel(); SpinnerNumberModel m = (SpinnerNumberModel) getModel();
if (mwe.getScrollType() != MouseWheelEvent.WHEEL_UNIT_SCROLL) {
// TODO: Handle other mouse wheel modes
return;
}
Long value = Long value =
mwe.getUnitsToScroll() > 0 ? (Long) m.getPreviousValue() : (Long) m.getNextValue(); mwe.getUnitsToScroll() > 0 ? (Long) m.getPreviousValue() : (Long) m.getNextValue();
if (value != null) { if (value != null) {
setValue(value); setValue(value);
mwe.consume();
} }
} }
} }

View file

@ -16,7 +16,7 @@
package ghidra.app.plugin.core.compositeeditor; package ghidra.app.plugin.core.compositeeditor;
import java.awt.*; import java.awt.*;
import java.awt.event.MouseEvent; import java.awt.event.*;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashSet; import java.util.HashSet;
@ -32,11 +32,11 @@ import resources.icons.ColorIcon;
public class BitFieldPlacementComponent extends JPanel { public class BitFieldPlacementComponent extends JPanel {
private static final int CELL_HEIGHT = 25; private static final int CELL_HEIGHT = 25;
private static final int BIT_WIDTH = 10; // private static final int BIT_WIDTHx = 10;
private static final int ZERO_BIT_WIDTH = 3; private static final int ZERO_BIT_WIDTH = 3;
private static final int BIT_SEPARATOR_THICKNESS = 1; private static final int BIT_SEPARATOR_THICKNESS = 1;
private static final int BYTE_SEPARATOR_THICKNESS = 2; private static final int BYTE_SEPARATOR_THICKNESS = 2;
private static final int BYTE_WIDTH = 8 * (BIT_WIDTH + BIT_SEPARATOR_THICKNESS); // private static final int BYTE_WIDTHx = 8 * (BIT_WIDTH + BIT_SEPARATOR_THICKNESS);
private static final int SCROLLBAR_THICKNESS = 10; private static final int SCROLLBAR_THICKNESS = 10;
private static final int MY_HEIGHT = (2 * CELL_HEIGHT) + (3 * BYTE_SEPARATOR_THICKNESS); private static final int MY_HEIGHT = (2 * CELL_HEIGHT) + (3 * BYTE_SEPARATOR_THICKNESS);
@ -52,6 +52,9 @@ public class BitFieldPlacementComponent extends JPanel {
private static final Color NON_BITFIELD_COMPONENT_COLOR = new Color(0xb8b8ff); private static final Color NON_BITFIELD_COMPONENT_COLOR = new Color(0xb8b8ff);
private static final Color INTERIOR_LINE_COLOR = new Color(0xcfcfcf); private static final Color INTERIOR_LINE_COLOR = new Color(0xcfcfcf);
private int bitWidth = 10;
private int byteWidth = getByteWidth(bitWidth);
private final Composite composite; private final Composite composite;
private final boolean bigEndian; private final boolean bigEndian;
@ -116,6 +119,63 @@ public class BitFieldPlacementComponent extends JPanel {
setSize(getPreferredSize()); setSize(getPreferredSize());
setMinimumSize(getPreferredSize()); setMinimumSize(getPreferredSize());
ToolTipManager.sharedInstance().registerComponent(this); ToolTipManager.sharedInstance().registerComponent(this);
addMouseWheelListener(new MyMouseWheelListener());
}
private class MyMouseWheelListener implements MouseWheelListener {
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
if (e.getModifiersEx() != InputEvent.SHIFT_DOWN_MASK || e.isConsumed()) {
return;
}
if (e.getScrollType() != MouseWheelEvent.WHEEL_UNIT_SCROLL) {
// TODO: should we handle other modes?
return;
}
e.consume();
Point p = e.getPoint();
int index = getBitIndex(p.x);
if (index < 0) {
return;
}
int w = bitWidth + e.getWheelRotation();
if (w >= 10) {
Rectangle visibleRect = getVisibleRect();
double offsetX = p.getX() - visibleRect.getX();
setBitWidth(w);
Rectangle bitRec = bitFieldAllocation.bitAttributes[index].rectangle;
int x = (int) (bitRec.getCenterX() - offsetX);
Rectangle r =
new Rectangle(x, visibleRect.y, visibleRect.width, visibleRect.height);
scrollRectToVisible(r);
}
}
}
private static int getByteWidth(int bitWidth) {
return 8 * (bitWidth + BIT_SEPARATOR_THICKNESS);
}
public int getBitWidth() {
return bitWidth;
}
public void setBitWidth(int width) {
bitWidth = width;
byteWidth = getByteWidth(bitWidth);
if (bitFieldAllocation != null) {
bitFieldAllocation.layoutBits();
}
updatePreferredSize();
repaint();
} }
private int getPreferredHeight() { private int getPreferredHeight() {
@ -124,11 +184,10 @@ public class BitFieldPlacementComponent extends JPanel {
private int getPreferredWidth() { private int getPreferredWidth() {
if (bitFieldAllocation == null) { if (bitFieldAllocation == null) {
return 10; return byteWidth;
} }
int extraLineSpace = BYTE_SEPARATOR_THICKNESS - BIT_SEPARATOR_THICKNESS; int extraLineSpace = BYTE_SEPARATOR_THICKNESS - BIT_SEPARATOR_THICKNESS;
return (allocationByteSize * BYTE_WIDTH) + BYTE_SEPARATOR_THICKNESS + extraLineSpace; return (allocationByteSize * byteWidth) + BYTE_SEPARATOR_THICKNESS + extraLineSpace;
} }
public boolean isBigEndian() { public boolean isBigEndian() {
@ -140,7 +199,7 @@ public class BitFieldPlacementComponent extends JPanel {
} }
int getBitOffset(Point point) { int getBitOffset(Point point) {
int bitWidthWithLine = BIT_WIDTH + BIT_SEPARATOR_THICKNESS; int bitWidthWithLine = bitWidth + BIT_SEPARATOR_THICKNESS;
int cellIndex = (point.x - BYTE_SEPARATOR_THICKNESS) / bitWidthWithLine; int cellIndex = (point.x - BYTE_SEPARATOR_THICKNESS) / bitWidthWithLine;
return (8 * allocationByteSize) - cellIndex - 1; return (8 * allocationByteSize) - cellIndex - 1;
} }
@ -321,6 +380,7 @@ public class BitFieldPlacementComponent extends JPanel {
if (bitFieldAllocation == null) { if (bitFieldAllocation == null) {
return null; return null;
} }
// TODO: binary search could be used for very large structures
for (BitAttributes attrs : bitFieldAllocation.bitAttributes) { for (BitAttributes attrs : bitFieldAllocation.bitAttributes) {
if (attrs.rectangle != null && attrs.rectangle.contains(p)) { if (attrs.rectangle != null && attrs.rectangle.contains(p)) {
return attrs; return attrs;
@ -329,6 +389,21 @@ public class BitFieldPlacementComponent extends JPanel {
return null; return null;
} }
int getBitIndex(int x) {
if (bitFieldAllocation == null) {
return -1;
}
// TODO: binary search could be used for very large structures
for (int i = 0; i < bitFieldAllocation.bitAttributes.length; i++) {
BitAttributes attrs = bitFieldAllocation.bitAttributes[i];
if (attrs.rectangle != null && x >= attrs.rectangle.x &&
x < (attrs.rectangle.x + attrs.rectangle.width)) {
return i;
}
}
return 0;
}
/** /**
* Get rectangle which fully encompasses specified component. * Get rectangle which fully encompasses specified component.
* @param dtc data type component * @param dtc data type component
@ -342,7 +417,6 @@ public class BitFieldPlacementComponent extends JPanel {
if (extendToByteBoundary) { if (extendToByteBoundary) {
// compute rectangle which extends to byte boundary // compute rectangle which extends to byte boundary
int byteWidth = 8 * (BIT_WIDTH + BIT_SEPARATOR_THICKNESS);
int offset = (dtc.getOffset() - allocationByteOffset); int offset = (dtc.getOffset() - allocationByteOffset);
if (!bigEndian) { if (!bigEndian) {
offset = allocationByteSize - offset - dtc.getLength(); offset = allocationByteSize - offset - dtc.getLength();
@ -371,7 +445,10 @@ public class BitFieldPlacementComponent extends JPanel {
@Override @Override
public String getToolTipText(MouseEvent e) { public String getToolTipText(MouseEvent e) {
BitAttributes attrs = getBitAttributes(e.getPoint()); BitAttributes attrs = getBitAttributes(e.getPoint());
return attrs != null ? attrs.getTip() : null; String dtcInfo = attrs != null ? (attrs.getTip() + "<BR>") : "";
return "<HTML><div style=\"text-align:center\">" + dtcInfo +
"<div style=\"color: gray;font-style: italic\">(Shift-wheel to zoom)</div></div></HTML>";
} }
@Override @Override
@ -412,12 +489,12 @@ public class BitFieldPlacementComponent extends JPanel {
// start close to the left clip bounds // start close to the left clip bounds
Rectangle clipBounds = g.getClipBounds(); Rectangle clipBounds = g.getClipBounds();
int maxX = clipBounds.x + clipBounds.width - 1; int maxX = clipBounds.x + clipBounds.width - 1;
int startIndex = clipBounds.x / BYTE_WIDTH; int startIndex = clipBounds.x / byteWidth;
x += startIndex * BYTE_WIDTH; x += startIndex * byteWidth;
for (int i = startIndex; i < byteSize; i++) { for (int i = startIndex; i < byteSize; i++) {
// last byte header needs to slightly wider // last byte header needs to slightly wider
int w = BYTE_WIDTH; int w = byteWidth;
if (i == (byteSize - 1)) { if (i == (byteSize - 1)) {
w += BYTE_SEPARATOR_THICKNESS - BIT_SEPARATOR_THICKNESS; w += BYTE_SEPARATOR_THICKNESS - BIT_SEPARATOR_THICKNESS;
} }
@ -433,7 +510,6 @@ public class BitFieldPlacementComponent extends JPanel {
private void paintByte(Graphics g, int x, int y, int width, int byteIndex, int baseOffset) { private void paintByte(Graphics g, int x, int y, int width, int byteIndex, int baseOffset) {
Color curColor = g.getColor(); Color curColor = g.getColor();
Font curFont = g.getFont();
int offset = byteIndex; int offset = byteIndex;
if (!bigEndian) { if (!bigEndian) {
@ -445,8 +521,6 @@ public class BitFieldPlacementComponent extends JPanel {
g.fillRect(x, y, width - BYTE_SEPARATOR_THICKNESS, CELL_HEIGHT); // byte fill g.fillRect(x, y, width - BYTE_SEPARATOR_THICKNESS, CELL_HEIGHT); // byte fill
g.setColor(TEXT_COLOR); g.setColor(TEXT_COLOR);
Font textFont = getFont().deriveFont(Font.BOLD);
g.setFont(textFont);
String offsetStr = Integer.toString(offset); String offsetStr = Integer.toString(offset);
FontMetrics fontMetrics = g.getFontMetrics(); FontMetrics fontMetrics = g.getFontMetrics();
@ -455,7 +529,6 @@ public class BitFieldPlacementComponent extends JPanel {
g.drawString(offsetStr, textX, textY); g.drawString(offsetStr, textX, textY);
g.setColor(curColor); g.setColor(curColor);
g.setFont(curFont);
} }
private void paintBits(Graphics2D g, int y) { private void paintBits(Graphics2D g, int y) {
@ -480,9 +553,9 @@ public class BitFieldPlacementComponent extends JPanel {
// start close to the left clip bounds // start close to the left clip bounds
Rectangle clipBounds = g.getClipBounds(); Rectangle clipBounds = g.getClipBounds();
int maxX = clipBounds.x + clipBounds.width - 1; int maxX = clipBounds.x + clipBounds.width - 1;
int bitWidth = bitAttributes[0].rectangle.width; int width = bitAttributes[0].rectangle.width;
int startIndex = clipBounds.x / (bitAttributes[0].rectangle.width); int startIndex = clipBounds.x / (bitAttributes[0].rectangle.width);
x += startIndex * bitWidth; x += startIndex * width;
int bitIndex; int bitIndex;
for (bitIndex = startIndex; bitIndex < bitAttributes.length; bitIndex++) { for (bitIndex = startIndex; bitIndex < bitAttributes.length; bitIndex++) {
@ -500,16 +573,16 @@ public class BitFieldPlacementComponent extends JPanel {
} }
if (prevDtc == null) { if (prevDtc == null) {
prevDtc = dtc; prevDtc = dtc;
dtcRectangle = new Rectangle(attrs.rectangle); dtcRectangle = new Rectangle(attrs.rectangle.intersection(clipBounds));
} }
dtcRectangle.add(attrs.rectangle); dtcRectangle.add(attrs.rectangle.intersection(clipBounds));
if (attrs.unallocated) { if (attrs.unallocated) {
paintDit(g, attrs.rectangle); paintDit(g, attrs.rectangle);
} }
prevAttrs = attrs; prevAttrs = attrs;
x += bitWidth; x += width;
} }
if (prevDtc != null) { if (prevDtc != null) {
paintComponentLabel(g, prevDtc, dtcRectangle); paintComponentLabel(g, prevDtc, dtcRectangle);
@ -687,7 +760,7 @@ public class BitFieldPlacementComponent extends JPanel {
private void layoutBits() { private void layoutBits() {
int x = BYTE_SEPARATOR_THICKNESS; int x = BYTE_SEPARATOR_THICKNESS;
int y = (2 * BYTE_SEPARATOR_THICKNESS) + CELL_HEIGHT; int y = (2 * BYTE_SEPARATOR_THICKNESS) + CELL_HEIGHT;
int width = BIT_WIDTH + BIT_SEPARATOR_THICKNESS; int width = bitWidth + BIT_SEPARATOR_THICKNESS;
for (BitAttributes attrs : bitAttributes) { for (BitAttributes attrs : bitAttributes) {
attrs.layout(x, y, width, CELL_HEIGHT); attrs.layout(x, y, width, CELL_HEIGHT);
x += width; x += width;
@ -872,7 +945,7 @@ public class BitFieldPlacementComponent extends JPanel {
} }
// little-endian: place strip on right-side of bit // little-endian: place strip on right-side of bit
// big-endian: place strip on left-side of bit // big-endian: place strip on left-side of bit
int xStrip = bigEndian ? rectangle.x : (rectangle.x + BIT_WIDTH - ZERO_BIT_WIDTH); int xStrip = bigEndian ? rectangle.x : (rectangle.x + bitWidth - ZERO_BIT_WIDTH);
int xLine = int xLine =
bigEndian ? (xStrip + ZERO_BIT_WIDTH) : (xStrip - BIT_SEPARATOR_THICKNESS); bigEndian ? (xStrip + ZERO_BIT_WIDTH) : (xStrip - BIT_SEPARATOR_THICKNESS);
g.setColor(c); g.setColor(c);
@ -881,7 +954,7 @@ public class BitFieldPlacementComponent extends JPanel {
g.fillRect(xLine, rectangle.y, BIT_SEPARATOR_THICKNESS, CELL_HEIGHT); g.fillRect(xLine, rectangle.y, BIT_SEPARATOR_THICKNESS, CELL_HEIGHT);
} }
else { else {
g.fillRect(rectangle.x, rectangle.y, BIT_WIDTH, CELL_HEIGHT); g.fillRect(rectangle.x, rectangle.y, bitWidth, CELL_HEIGHT);
if (conflict != null && conflict.dtc.isZeroBitFieldComponent()) { if (conflict != null && conflict.dtc.isZeroBitFieldComponent()) {
conflict.paint(g, null, false); conflict.paint(g, null, false);
} }
@ -901,7 +974,7 @@ public class BitFieldPlacementComponent extends JPanel {
lineColor = INTERIOR_LINE_COLOR; lineColor = INTERIOR_LINE_COLOR;
} }
g.setColor(lineColor); g.setColor(lineColor);
g.fillRect(rectangle.x + BIT_WIDTH, rectangle.y, BIT_SEPARATOR_THICKNESS, g.fillRect(rectangle.x + bitWidth, rectangle.y, BIT_SEPARATOR_THICKNESS,
CELL_HEIGHT); CELL_HEIGHT);
} }
} }

View file

@ -377,13 +377,16 @@ class StructureDB extends CompositeDB implements Structure {
int endIndex = startIndex; int endIndex = startIndex;
if (startIndex < components.size()) { if (startIndex < components.size()) {
// some shifting of components may be required // some shifting of components may be required
int endBitOffset = startBitOffset + effectiveBitSize - 1; int endBitOffset = startBitOffset;
endIndex = Collections.binarySearch(components, new Integer(endBitOffset), if (effectiveBitSize != 0) {
endBitOffset += effectiveBitSize - 1;
}
endIndex = Collections.binarySearch(components, Integer.valueOf(endBitOffset),
bitOffsetComparator); bitOffsetComparator);
if (endIndex < 0) { if (endIndex < 0) {
endIndex = -endIndex - 1; endIndex = -endIndex - 1;
} }
else { else if (effectiveBitSize != 0) {
hasConflict = true; hasConflict = true;
} }
} }

View file

@ -574,13 +574,16 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur
int endIndex = startIndex; int endIndex = startIndex;
if (startIndex < components.size()) { if (startIndex < components.size()) {
// some shifting of components may be required // some shifting of components may be required
int endBitOffset = startBitOffset + effectiveBitSize - 1; int endBitOffset = startBitOffset;
endIndex = Collections.binarySearch(components, new Integer(endBitOffset), if (effectiveBitSize != 0) {
endBitOffset += effectiveBitSize - 1;
}
endIndex = Collections.binarySearch(components, Integer.valueOf(endBitOffset),
bitOffsetComparator); bitOffsetComparator);
if (endIndex < 0) { if (endIndex < 0) {
endIndex = -endIndex - 1; endIndex = -endIndex - 1;
} }
else { else if (effectiveBitSize != 0) {
hasConflict = true; hasConflict = true;
} }
} }