-
Notifications
You must be signed in to change notification settings - Fork 236
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Restyling large portions of the document causes area to scroll when it shouldn't. #390
Comments
Additional information that may help finding the cause: I also noticed that setting the background colour results in a tiny (unexpected) change of the text width - and maybe is part of the problem? Environment of my observations: Windows 7, Java 8u102 |
I modified the java Keywords demo for easy reproduction of the described problem: JavaKeywordsAsync.txt
Reproduction:
Conclusions and sidenotes:
Where could I look to eventually find the cause of the problem? |
Here is a work/hack-around: Double scrollBefore = imTextArea.getEstimatedScrollY();
// set the styles here
textArea.setStyleSpans(...)
if (!scrollBefore.equals(textArea.getEstimatedScrollY()))
{
textArea.setEstimatedScrollY(scrollBefore);
} |
@synth3 I think it'd be easier to find the problem in M2 than in M3 because of the added complexity of M3. Before you say let's implement @synth3's hack into the code by default, let's say that we weren't clearing the style but were changing the font size to be bigger. Would we still want that code to run? It might be better to just override the method in your individual case so that you store and set the method before and after that occurs. |
We've started using RichTextFX for our language project, Avail, at https://github.com/AvailLang/Avail. Because of the complexity of the language, we can't use typical regex-based IDE's for a true Avail environment. We've been using RichTextFX to build out an Avail editor that we hope to make into a full blown IDE. Unfortunately we've bumped up against this bug. It is a show stopper for us as we can't keep the screen from jumping when you start typing. Even with synth3's proposed work-around, we can't keep the screen from visibly reseting itself. We've extended the class Are there any thoughts on when this bug might be addressed? Is there an earlier version that has CodeArea that we maybe able to use that might not have this bug? Do you have any thoughts on what we might do on our end to try and address the bug? I tried to dig into |
Here's one idea. I have no idea whether it'll work. It attempts to determine how far away the first visible line is offset in the viewport before the style change occurs and then seeks to offset the viewport by that same amount.
|
I added a change listener to
The third change is what causes the issue. |
After making ESD the model in #463, the code I ran now displays:
|
@richATavail @synth3 I'll be looking into this issue this week. I won't make any guarantees that it'll be fixed by the end of the week. I simply plan on identifying what's causing the problem. |
@JordanMartinez Thanks! I understand what it is do this sort of work on your free time, so I do greatly appreciate it! |
I've cleaned up the demo to reproduce the code automatically once run: import java.time.Duration;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.fxmisc.flowless.VirtualizedScrollPane;
import org.fxmisc.richtext.StyleClassedTextArea;
import org.reactfx.util.FxTimer;
public class JavaKeywordsAsync extends Application {
public static void main(String[] args) {
launch(args);
}
private StyleClassedTextArea area;
private class IntProp extends SimpleIntegerProperty {
IntProp(int val) {
super(val);
}
public int plusPlus() {
int v = get();
set(v + 1);
return v;
}
}
private void log(String message) {
System.out.println(message);
}
@Override
public void start(Stage primaryStage) {
area = new StyleClassedTextArea();
IntProp scrollChangeCount = new IntProp(0);
area.widthProperty().addListener((obs, ov, nv) -> log("Width changed to: " + nv));
area.heightProperty().addListener((obs, ov, nv) -> log("Height changed to: " + nv));
area.estimatedScrollYProperty().addListener((obs, ov, nv) -> log("Scroll count: " + scrollChangeCount.plusPlus() + " | Changed to: " + nv));
area.totalHeightEstimateProperty().addListener((obs, ov, nv) -> log("Height Estimate changed to: " + nv));
primaryStage.setScene(new Scene(new VirtualizedScrollPane<>(area), 600, 400));
primaryStage.setTitle("Bug Demo");
primaryStage.show();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 200; i++) {
sb.append("a\n");
}
log("\nReplacing text with sample code");
area.replaceText(sb.toString());
FxTimer.runLater(Duration.ofMillis(1500), () -> {
log("\nRestyling entire document");
area.setStyleClass(0, area.getLength() - 1, "red");
Platform.exit();
});
}
} which (along with some other change listeners in RTFX) produces:
|
Found the bug. The code doesn't account for the possibility that a deletion that occurs before the first visible cell in the viewport also deletes part of the visible cells in the viewport. The issue lies in StartOffStart#transformChange: @Override
public TargetPosition transformByChange(
int pos, int removedSize, int addedSize) {
// itemIndex = 176; offset =
// pos = 0; removedSize = 200; addedSize = 200
System.out.println(String.format("Transforming change with parameters pos=%s removedSize=%s addedSize=%s", pos, removedSize, addedSize));
if(itemIndex >= pos + removedSize) {
System.out.println("change before the target item, just update item index");
return new StartOffStart(itemIndex - removedSize + addedSize, offsetFromStart);
// doesn't check whether this deletion may occur
// pos itemIndex (1st visible cell) pos + removedSize
// | ------- | --------------------------------- |
} else if(itemIndex >= pos) {
// so this code gets run, which forces the viewport to display the cell whose index == pos
// or 0 in this case.
System.out.println("target item deleted, show the first inserted at the target offset");
return new StartOffStart(pos, offsetFromStart);
} else {
System.out.println("change after the target item, target position not affected");
return this;
}
} I combined Flowless and RichTextFX into one project so it would be easier to add println statements into Flowless to see what was going on. The key part here is surrounded by
|
@richATavail @synth3 You can get around this issue if you compile a local copy of my PR for Flowless and use it as a dependency in your project because I'm not sure how long it'll be before Tomas merges the code. |
@JordanMartinez Thanks a lot for your work! I'm glad to hear that you found the issue. Until now I didn't manage to get enough understanding of the codebase for being able to find the cause. |
@synth3 It was fun and frustrating. |
I've created a branch in my repo of RichTextFX called MavenAdd the repository <repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories> Add the dependency <dependency>
<groupId>com.github.JordanMartinez</groupId>
<artifactId>RichTextFX</artifactId>
<version>jitpack-master-SNAPSHOT</version>
</dependency> Gradlerepositories {
maven {
url 'https://jitpack.io'
}
}
dependencies {
compile "com.github.JordanMartinez:RichTextFX:jitpack-master-SNAPSHOT"
} Sbtresolvers += "jitpack" at "https://jitpack.io"
libraryDependencies += "com.github.JordanMartinez" % "RichTextFX" % "jitpack-master-SNAPSHOT" |
@RodrigoSantiago Also noted the following in his comment here:
|
The latest |
I am using this code:
codeArea.clearStyle(0, codeArea.getLength() - 1);
Before / After Clear and style
If the area is already clean, the problem does not happen (it is inside a VirtualizedScrollPane)
Obs.: After some tests, I noticed that this happens when the font type is italic
The text was updated successfully, but these errors were encountered: