Skip to content

Commit

Permalink
[Sticky Scrolling] Dispatch scrolling to source viewer
Browse files Browse the repository at this point in the history
Scrolling on the sticky lines control is dispatched to the linked source viewer. With this change the source viewer's scrolling behavior remains consistent, regardless of whether sticky scrolling is enalbed or not.

Follow up for #1894
  • Loading branch information
Christopher-Hermann authored and BeckerWdf committed Jun 14, 2024
1 parent c06713f commit c1f4567
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.ScrollBar;

import org.eclipse.core.runtime.ICoreRunnable;
import org.eclipse.core.runtime.jobs.Job;
Expand Down Expand Up @@ -98,11 +101,15 @@ public class StickyScrollingControl {

private final static int BOTTOM_SEPARATOR_SPACING= 2;

private StickyScrollingHandler stickyScrollingHandler;

public StickyScrollingControl(ISourceViewer sourceViewer, StickyScrollingControlSettings settings) {
this(sourceViewer, null, settings);
this(sourceViewer, null, settings, null);
}

public StickyScrollingControl(ISourceViewer sourceViewer, IVerticalRuler verticalRuler, StickyScrollingControlSettings settings) {
public StickyScrollingControl(ISourceViewer sourceViewer, IVerticalRuler verticalRuler,
StickyScrollingControlSettings settings, StickyScrollingHandler stickyScrollingHandler) {
this.stickyScrollingHandler= stickyScrollingHandler;
this.stickyLines= new ArrayList<>();
this.sourceViewer= sourceViewer;
this.verticalRuler= verticalRuler;
Expand Down Expand Up @@ -441,6 +448,10 @@ public void mouseExit(MouseEvent e) {
stickyLineText.setLineBackground(0, getNumberStickyLines(), null);
}
});

ScrollingDispatchingListener scrollingDispatchingListener= new ScrollingDispatchingListener();
canvas.addListener(SWT.MouseHorizontalWheel, scrollingDispatchingListener);
canvas.addListener(SWT.MouseVerticalWheel, scrollingDispatchingListener);
}

/**
Expand Down Expand Up @@ -479,6 +490,42 @@ public void caretMoved(CaretEvent event) {
ensureSourceViewerLineVisible(line);
});
}
}

/**
* A mouse wheel listener that is dispatching the scrolling on the sticky lines canvas to the
* source viewer. The calculation of the scrolling steps is copied from
* {@link Composite}#scrollWheel.
*/
class ScrollingDispatchingListener implements Listener {

@Override
public void handleEvent(Event event) {
StyledText textWidget= sourceViewer.getTextWidget();

ScrollBar bar= event.type == SWT.MouseHorizontalWheel ? textWidget.getHorizontalBar() : textWidget.getVerticalBar();
if (bar == null) {
return;
}

int deltaY= event.count;
if (-1 < deltaY && deltaY < 0) {
deltaY= -1;
}
if (0 < deltaY && deltaY < 1) {
deltaY= 1;
}

int pixel= Math.max(0, (int) (0.5f + bar.getSelection() - bar.getIncrement() * deltaY));

if (event.type == SWT.MouseHorizontalWheel) {
sourceViewer.getTextWidget().setHorizontalPixel(pixel);
} else {
sourceViewer.getTextWidget().setTopPixel(pixel);
if (stickyScrollingHandler != null) {
stickyScrollingHandler.viewportChanged(pixel);
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public StickyScrollingHandler(ISourceViewer sourceViewer, IVerticalRuler vertica
this.stickyLinesProvider= stickyLinesProvider;

StickyScrollingControlSettings settings= loadAndListenForProperties(preferenceStore);
stickyScrollingControl= new StickyScrollingControl(sourceViewer, verticalRuler, settings);
stickyScrollingControl= new StickyScrollingControl(sourceViewer, verticalRuler, settings, this);

sourceViewer.addViewportListener(this);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.ScrollBar;
import org.eclipse.swt.widgets.Shell;

import org.eclipse.jface.text.Document;
Expand All @@ -59,14 +60,14 @@ public void setup() {
shell.setSize(200, 200);
shell.setLayout(new FillLayout());
ruler = new CompositeRuler();
sourceViewer = new SourceViewer(shell, ruler, SWT.None);
sourceViewer = new SourceViewer(shell, ruler, SWT.V_SCROLL | SWT.H_SCROLL);

lineNumberColor = new Color(0, 0, 0);
hoverColor = new Color(1, 1, 1);
backgroundColor = new Color(2, 2, 2);
StickyScrollingControlSettings settings = new StickyScrollingControlSettings(5, lineNumberColor, hoverColor,
backgroundColor, true);
stickyScrollingControl = new StickyScrollingControl(sourceViewer, ruler, settings);
stickyScrollingControl = new StickyScrollingControl(sourceViewer, ruler, settings, null);
}

@After
Expand Down Expand Up @@ -177,20 +178,20 @@ public void testLayoutStickyLinesCanvasOnResize() {
Canvas stickyControlCanvas = getStickyControlCanvas(shell);
assertEquals(0, stickyControlCanvas.getBounds().x);
assertEquals(0, stickyControlCanvas.getBounds().y);
assertEquals(201, stickyControlCanvas.getBounds().width);
assertEquals(getExpectedWitdh(200), stickyControlCanvas.getBounds().width);
assertThat(stickyControlCanvas.getBounds().height, greaterThan(0));

sourceViewer.getTextWidget().setBounds(0, 0, 150, 200);

stickyControlCanvas = getStickyControlCanvas(shell);
assertEquals(0, stickyControlCanvas.getBounds().x);
assertEquals(0, stickyControlCanvas.getBounds().y);
assertEquals(151, stickyControlCanvas.getBounds().width);
assertEquals(getExpectedWitdh(150), stickyControlCanvas.getBounds().width);
assertThat(stickyControlCanvas.getBounds().height, greaterThan(0));
}

@Test
public void navigateToStickyLine() {
public void testNavigateToStickyLine() {
String text = """
line 1
line 2""";
Expand All @@ -209,6 +210,40 @@ public void navigateToStickyLine() {
assertEquals(0, selectedRange.y);
}

@Test
public void testVerticalScrollingIsDispatched() {
Canvas stickyControlCanvas = getStickyControlCanvas(shell);
String text = """
line 1
line 2""";
sourceViewer.getTextWidget().setText(text);
sourceViewer.getTextWidget().getVerticalBar().setIncrement(10);
assertEquals(0, sourceViewer.getTextWidget().getTopPixel());

Event event = new Event();
event.count = -1;
stickyControlCanvas.notifyListeners(SWT.MouseVerticalWheel, event);

assertEquals(10, sourceViewer.getTextWidget().getTopPixel());
}

@Test
public void testHorizontalScrollingIsDispatched() {
Canvas stickyControlCanvas = getStickyControlCanvas(shell);
String text = """
line 1
line 2""";
sourceViewer.getTextWidget().setText(text);
sourceViewer.getTextWidget().getHorizontalBar().setIncrement(10);
assertEquals(0, sourceViewer.getTextWidget().getHorizontalPixel());

Event event = new Event();
event.count = -1;
stickyControlCanvas.notifyListeners(SWT.MouseHorizontalWheel, event);

assertEquals(10, sourceViewer.getTextWidget().getHorizontalPixel());
}

private Canvas getStickyControlCanvas(Composite composite) {
for (Control control : composite.getChildren()) {
if (control instanceof Canvas canvas) {
Expand All @@ -233,4 +268,13 @@ private StyledText getStickyLineText() {
return (StyledText) canvas.getChildren()[1];
}

private int getExpectedWitdh(int textWidgetWitdth) {
ScrollBar verticalBar = sourceViewer.getTextWidget().getVerticalBar();
if (verticalBar.isVisible()) {
return textWidgetWitdth - verticalBar.getSize().x + 1;
} else {
return textWidgetWitdth + 1;
}
}

}

0 comments on commit c1f4567

Please sign in to comment.