Merge remote-tracking branch 'origin/GP-3866_ghidragon_fieldpanel_scroll_bug' into Ghidra_11.0

This commit is contained in:
ghidra1 2023-12-05 14:19:58 -05:00
commit fda9c1f35e
4 changed files with 139 additions and 59 deletions

View file

@ -250,7 +250,7 @@ public class ByteViewerPanel extends JPanel
startField.setText(start);
ByteBlock lastBlock = blocks[blocks.length - 1];
endField.setText(lastBlock
.getLocationRepresentation(lastBlock.getLength().subtract(BigInteger.ONE)));
.getLocationRepresentation(lastBlock.getLength().subtract(BigInteger.ONE)));
indexPanelWidth = getIndexPanelWidth(blocks);
int center = indexPanelWidth / 2;
@ -1172,6 +1172,11 @@ class CompositePanel extends JPanel implements IndexedScrollable, IndexScrollLis
// handled by indexPanel
}
@Override
public void mouseWheelMoved(double preciseWheelRotation, boolean isHorizontal) {
indexPanel.mouseWheelMoved(preciseWheelRotation, isHorizontal);
}
@Override
public void indexRangeChanged(BigInteger startIndex, BigInteger endIndex, int yStart,
int yEnd) {

View file

@ -110,7 +110,17 @@ public class FieldPanel extends JPanel
addKeyListener(new FieldPanelKeyAdapter());
addMouseListener(new FieldPanelMouseAdapter());
addMouseMotionListener(new FieldPanelMouseMotionAdapter());
addMouseWheelListener(new BigFieldPanelMouseWheelListener());
// This the default scroll wheel listener. Note: to work around a bug in the scroll pane,
// this component will not expand to entirely fill the parent scroll pane (See the
// IndexedScrollPane). This listener will handle scroll wheel events that happen over
// field panel. There is a similar listener to handle events that happen over the
// IndexScrollPane
addMouseWheelListener(e -> {
mouseWheelMoved(e.getPreciseWheelRotation(), e.isShiftDown());
e.consume();
});
addFocusListener(new FieldPanelFocusListener());
setDoubleBuffered(false);
@ -1387,6 +1397,46 @@ public class FieldPanel extends JPanel
return accessibleFieldPanel;
}
public void mouseWheelMoved(double preciseWheelRotation, boolean horizontal) {
Layout firstLayout = model.getLayout(BigInteger.ZERO);
if (firstLayout == null) {
return; // nothing to scroll
}
int scrollUnit = firstLayout.getScrollableUnitIncrement(0, 1);
int scrollAmount = (int) (preciseWheelRotation * scrollUnit * MOUSEWHEEL_LINES_TO_SCROLL);
if (hoverHandler.isHoverShowing()) {
hoverHandler.scroll(scrollAmount);
}
else {
hoverHandler.stopHover();
if (horizontal && horizontalScrollingEnabled) {
scrollViewHorizontally(scrollAmount);
}
else {
scrollView(scrollAmount);
}
}
}
private void scrollViewHorizontally(int scrollAmount) {
JViewport vp = getViewport();
if (vp == null) {
// this will happen for Field Panels not placed inside of scroll panes
return;
}
Point pos = vp.getViewPosition();
// don't allow new x position to go negative or else you can scroll left past the beginning
int x = Math.max(0, pos.x + scrollAmount);
vp.setViewPosition(new Point(x, pos.y));
}
//==================================================================================================
// Inner Classes
//==================================================================================================
@ -1753,50 +1803,6 @@ public class FieldPanel extends JPanel
}
}
private class BigFieldPanelMouseWheelListener implements MouseWheelListener {
@Override
public void mouseWheelMoved(MouseWheelEvent e) {
double wheelRotation = e.getPreciseWheelRotation();
Layout firstLayout = model.getLayout(BigInteger.ZERO);
int layoutScrollHt = firstLayout != null //
? firstLayout.getScrollableUnitIncrement(0, 1)
: 0;
int scrollAmount = (int) (wheelRotation * layoutScrollHt * MOUSEWHEEL_LINES_TO_SCROLL);
if (scrollAmount == 0) {
return;
}
if (hoverHandler.isHoverShowing()) {
hoverHandler.scroll(scrollAmount);
}
else {
hoverHandler.stopHover();
if (e.isShiftDown() && horizontalScrollingEnabled) {
scrollViewHorizontally(scrollAmount);
}
else {
scrollView(scrollAmount);
}
}
e.consume();
}
private void scrollViewHorizontally(int scrollAmount) {
JViewport vp = getViewport();
if (vp == null) {
// this will happen for Field Panels not placed inside of scroll panes
return;
}
// horizontal scroll (only move viewport)
Point pos = vp.getViewPosition();
vp.setViewPosition(new Point(Math.max(0, pos.x + scrollAmount), pos.y));
}
}
private class MouseHandler implements ActionListener {
private Timer scrollTimer; // used to generate auto scroll
private int mouseDownX;

View file

@ -50,6 +50,14 @@ public class IndexedScrollPane extends JPanel implements IndexScrollListener {
add(scrollPane);
viewport = scrollPane.getViewport();
// This scroll pane does not have the view component track the width. This is to
// prevent a text clipping issue caused by the scroll pane not compensating for the
// scroll bars. Since the component may not occupy the full width of this scroll pane,
// we need to process any scroll wheel events that happen outside of that component.
viewport.addMouseWheelListener(e -> {
scrollable.mouseWheelMoved(e.getPreciseWheelRotation(), e.isShiftDown());
});
viewport.setBackground(comp.getBackground());
viewport.addChangeListener(e -> viewportStateChanged());
viewport.setScrollMode(JViewport.SIMPLE_SCROLL_MODE);
@ -191,6 +199,7 @@ public class IndexedScrollPane extends JPanel implements IndexScrollListener {
ScrollView(JComponent component) {
setLayout(new ScrollViewLayout());
add(component);
}
@Override

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,29 +17,90 @@ package docking.widgets.indexedscrollpane;
import java.math.BigInteger;
/**
* Interface for scrolling a FieldPanel or container of a group of FieldPanels which displays
* a list of displayable items (layouts)
*/
public interface IndexedScrollable {
BigInteger getIndexCount();
/**
* Returns the number individually addressable items displayed.
* @return the number individually addressable items displayed
*/
public BigInteger getIndexCount();
boolean isUniformIndex();
/**
* Returns true if all the items are the same vertical size.
* @return true if all the items are the same vertical size
*/
public boolean isUniformIndex();
int getHeight(BigInteger index);
/**
* Returns the height of the n'th item.
* @param index the index of the time to get height for
* @return the height of the n'th item.
*/
public int getHeight(BigInteger index);
void showIndex(BigInteger index, int verticalOffset);
/**
* Makes the item at the given index be visible on the screen at the given vertical offset
* @param index the index of the item to show
* @param verticalOffset the number of pixels from the top of the screen to show the item
*/
public void showIndex(BigInteger index, int verticalOffset);
BigInteger getIndexAfter(BigInteger index);
/**
* Returns the index of the next non-null item. Not all indexes have items. Some items span
* multiple indexes
* @param index the index to start searching for the next non-null item
* @return the index of the next non-null item, or -1 if there is none
*/
public BigInteger getIndexAfter(BigInteger index);
BigInteger getIndexBefore(BigInteger index);
/**
* Returns the index of the previous non-null item. Not all indexes have items. Some items span
* multiple indexes
* @param index the index to start searching backwards for the previous non-null item
* @return the index of the previous non-null item, or -1 if there is none
*/
public BigInteger getIndexBefore(BigInteger index);
void scrollLineUp();
/**
* Scrolls the displayed items up by the height of one line of text
*/
public void scrollLineUp();
void scrollLineDown();
/**
* Scrolls the displayed items down by the height of one line of text
*/
public void scrollLineDown();
void scrollPageUp();
/**
* Scrolls the displayed items up by the height of one screen of text
*/
public void scrollPageUp();
void scrollPageDown();
/**
* Scrolls the displayed items down by the height of one screen of text
*/
public void scrollPageDown();
void addIndexScrollListener(IndexScrollListener listener);
/**
* Adds a listener to be notified when the view is scrolled in any way.
* @param listener the listener to be notified when the visible items change
*/
public void addIndexScrollListener(IndexScrollListener listener);
void removeIndexScrollListener(IndexScrollListener listener);
/**
* Removes the given listener from those to be notified when the view changes.
* @param listener the listener to remove
*/
public void removeIndexScrollListener(IndexScrollListener listener);
/**
* Notify the scrollable that the mouse wheel was moved.
* @param preciseWheelRotation the amount of rotation of the wheel
* @param isHorizontal true if the rotation was horizontal, false for vertical
*/
public void mouseWheelMoved(double preciseWheelRotation, boolean isHorizontal);
}