Skip to content
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

StyledTextArea scrolls to the caret every time span style is changed #101

Closed
mgrabmair opened this issue Dec 6, 2014 · 13 comments · Fixed by #378
Closed

StyledTextArea scrolls to the caret every time span style is changed #101

mgrabmair opened this issue Dec 6, 2014 · 13 comments · Fixed by #378
Labels

Comments

@mgrabmair
Copy link

I have a StyleClassedTextArea and load a String into it. I have a button event which calls setStyleClass a number of times using data external to the document. For some reason, when I call it, the text area always automatically scrolls to the bottom of the document. I have tried all kinds of variations, but it happens. Also, when I make the setStyleClass dependent on the document's content changing and I edit the text in the middle of the text field, it scroll-jumps into a position where the line I am editing becomes the bottom-most line in the view. What am I doing wrong?

Thanks,

Matthias


Minimal Code Example (just paste a lot of text into the field and click the button and provide some stylesheet in the css file defining a 'red' style):


package application;

//imports ...

public class Main extends Application {

private Scene scene;
private StyleClassedTextArea textArea;

@Override
public void start(Stage stage) {

    stage.setTitle("ScrollTest);

    try {
        BorderPane root = new BorderPane();
        textArea = new StyleClassedTextArea();
        textArea.setWrapText(true);

        BorderPane border = new BorderPane();
        HBox topBox = new HBox();

        Button updateButton = new Button("foo");            
        updateButton.setPrefSize(100, 20);
        updateButton.setOnAction(new EventHandler<ActionEvent>() {
            @Override public void handle(ActionEvent e) {
                textArea.setStyleClass(5, 10, "red");
            }
        });


        topBox.getChildren().addAll(updateButton);

        scene = new Scene(border, 600, 400);
        border.setCenter(textArea);

        border.setTop(topBox);
        scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());

        stage.setScene(scene);
        stage.show();

    } catch(Exception e) {
        e.printStackTrace();
    }
}

public static void main(String[] args) {
    launch(args);
}
}
@TomasMikula TomasMikula added the bug label Feb 2, 2015
@TomasMikula TomasMikula changed the title StyleClassedTextArea scrolls down every time span style is changed StyledTextArea scrolls to the caret every time span style is changed Feb 28, 2015
@TomasMikula
Copy link
Member

This is happening because the area automatically scrolls to the current caret position every time there is an edit (e.g. style set). I could fix this by only scrolling to the caret when the edit is made by user interaction (e.g. typing text). But this could break the behavior for other users that expect the automatic scroll to the caret. Currently, there is no viable workaround for them—it is currently not possible to explicitly request to scroll to the caret.

You could probably work around this by calling moveTo or selectRange after setStyleClass.

@lantunes
Copy link

lantunes commented Jun 8, 2016

@TomasMikula could you describe how one might work around the problem in more detail? In my application, I am calling setStyleClass after a key is released, and if the textarea can scroll, it will scroll to the caret every time if the caret is not on the first line of text. I would like for the scroll position to remain the same (unless it is necessary to scroll after moving the caret).

Perhaps this could be fixed by adding a configuration flag to the textarea that enables or disables automatic scrolling to the caret?

@TomasMikula
Copy link
Member

This can now actually be fixed by providing a method like requestScrollToCaret for those who want to scroll to the caret (and for the user actions) and don't scroll automatically on a change done programatically.

It was previously not possible to implement requestScrollToCaret on StyledTextArea, since scrolling was the responsibility of the skin.

@lantunes
Copy link

lantunes commented Jun 9, 2016

@TomasMikula I'd like to implement this method. Can you tell me exactly where in the code the invocation occurs to scroll to the caret when there is an edit?

@TomasMikula
Copy link
Member

TomasMikula commented Jun 9, 2016

@lantunes great! There already is a method requestFollowCaret() that is package private. This method is called every time caret position, selection, or content of the paragraphs are changed. It should be sufficient to:

  1. delete the referenced code;
  2. make the said method public, perhaps rename to requestScrollToCaret();
  3. identify all the event handlers in StyledTextAreaBehavior that require a call to requestScrollToCaret(). By a quick look, these might be edits, verticalNavigation, otherNavigation and keyTypedTemplate. It should be sufficient to add .ifConsumed((b, e) -> b.view.requestScrollToCaret() to each of them.

@mgrabmair
Copy link
Author

@TomasMikula I am happy to see this is being picked up. My project ended up being abandoned, so I did not get back to this, but it is good to hear that this is a possibility. Thanks for the help!

@TomasMikula TomasMikula added this to the 0.7 milestone Sep 16, 2016
@JordanMartinez
Copy link
Contributor

@TomasMikula for this issue and in light of #375, should the referenced code's subscription code still be deleted? Or just changed to layoutPopup()?

@TomasMikula
Copy link
Member

Now that we have access to view, I would do the popup positioning differently. It actually doesn't need special support from StyledTextArea, we just need to expose a property that reflects current caret position on screen. User code can do the rest. Storing a popup window and positioning properties inside StyledTextArea was weird, but was necessary so that skin could pick it up and position it during its own layout. All of that is a separate issue from this one.

@JordanMartinez
Copy link
Contributor

we just need to expose a property that reflects current caret position on screen.

So an ObjectProperty<Point2D> caretScreenPositionProperty (or a Val as I've never understood when you use the first instead of the latter or vice versa)? Shouldn't we also add some other base Popup class (or perhaps a demo now) that shows how to implement the various places to position the popup in relation to the caret to make the migration process easier?

@TomasMikula
Copy link
Member

It might be something else than Point2D, to account for the case when the caret is out of view (and in that case indicates whether it is before or after the currently displayed text). Also, it would be more like Bounds than Point2D anyway.

@TomasMikula
Copy link
Member

Not sure what you mean by "base Popup class", but we already have a PopupDemo.

@JordanMartinez
Copy link
Contributor

Not sure what you mean by "base Popup class", but we already have a PopupDemo.

Meaning a class that already has PopupAlignment and PopupOffset. I'm guessing not because they might choose a Window or some other item rather than a Popup.
We'd have to update the demo to show how to calculate where to put the caret based on the alignment given. Anything beyond that can be figured out by the user.

@JordanMartinez
Copy link
Contributor

It might be something else than Point2D, to account for the case when the caret is out of view (and in that case indicates whether it is before or after the currently displayed text). Also, it would be more like Bounds than Point2D anyway.

I forgot that sometimes the position of the anchor can change as well (is it in relation to the caret? Or the end of the selection?) Yeah, Bounds makes more sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants