Giter Site home page Giter Site logo

flowless's People

Contributors

fthevenet avatar hwaite avatar jordanmartinez avatar jugen avatar neilccbrown avatar satsen avatar shoaniki avatar strangenoises avatar tchudyk avatar tomasmikula avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flowless's Issues

Optional<Double> avgLen is present but is 0.0, resulting in dividing by zero, big numbers, and out of bounds error

In the 0.6 release and also in master:

Optional<Double> avgLen = sizeTracker.getAverageLengthEstimate();
int itemsBefore = avgLen.map(l -> spaceBefore/l).orElse(5.0).intValue();
int itemsAfter = avgLen.map(l -> spaceAfter/l).orElse(5.0).intValue();

I think we should check whether avgLen.isPresent() and Math.abs(avgLen.get()) < 1e-6, and if that's the case just set itemsBefore and itemsAfter to 5, same as what we do when avgLen is not present.

Otherwise, during layout, under some circumstances, avgLen is 0.0, itemsBefore is roughly 2^31, itemIndex - itemsBefore is a big negative number, after several function calls, the values are checked in reactfx and exception is thrown.

Maybe we should figure out why sizeTracker returns 0.0 as average length estimate, but that's beyond my knowledge of this project, and doing such a check before doing dividing seems reasonable enough to me.

Make VirtualFlow's scrollBars optional

Coming from FXMisc/RichTextFX#205, allow the option of not showing the horizontal and/or the vertical scrollBars.

Tomas already said in the above issue:

Hard-wiring auto-scrollbars into VirtualFlow didn't feel quite right from the start. On the other hand, the internal architecture of VirtualFlow already very much separates the scrollbar concern: VirtualFlow basically just adds scrollbars onto VirtualFlowContent

Add `focused` pseudo css class to VirtualizedScrollPane when its content is focused

Coming from FXMisc/RichTextFX#507, VirtualizedScrollPane should include a pseudo css class, focused, when its content is focused since the scroll bars are now separated from the content:

import javafx.scene.Node;
import org.fxmisc.flowless.Virtualized;
import org.fxmisc.flowless.VirtualizedScrollPane;

public class VirtualizedScrollPane<T extends Node & Virtualized> extends Region {
    private PseudoClass FOCUSED = PseudoClass.getPseudoClass("focused");

    public VirtualizedScrollPaneExt(T content) {
        super(content);

        content.focusedProperty().addListener((obs, oldVal, newVal) -> {
            pseudoClassStateChanged(FOCUSED, newVal);
        });
    }
}

Make VirtualFlow's gravity styleable via CSS

I propose that the Gravity of VirtualFlow should be made styleable via CSS (and thus mutable). If you're happy with the justification to add and the implementation strategy, I'm happy to write the code and submit a pull request.

Justification:

Use case 1: I have a RichTextFX control where I want the lines to be at the bottom (it's a history view of a terminal-like display, where the entry is underneath, and history should appear at the bottom and be bumped upwards as more is added). Because the Gravity of the VirtualFlow is a constructor parameter, I can't actually alter it unless I patch RichTextFX to allow it, and even then, it's a bit odd to have to pass a style attribute as an unchangeable constructor parameter. The VirtualFlow isn't public and we don't want to make it so, but if we could set the gravity parameter by CSS then it would solve the whole issue.

Use case 2: I am thinking of using VirtualFlow for a code-completion like popup window. It will appear below the line if there's room (with items at the top), or above the line otherwise (with items at the bottom). If Gravity is unchangeable then I can't dynamically move it from below to above without creating a new VirtualFlow.

Implementation:

I've had a look at the code and I don't think it will be a difficult change. VirtualFlow's constructor takes the gravity parameter, but only uses it to pass to Navigator's constructor. Navigator stores it as a field but only uses it in the utility methods at the bottom of the class. In turn these are only used by the method fillViewportFrom. Assuming IntelliJ's call hierarchy is complete, this all leads back to Navigator.layoutChildren():

image

I think this means that we can make a styleable property (with accessor and mutator) for gravity in VirtualFlow, which is passed as a reference to Navigator, and add a change listener to the property that calls VirtualFlow.requestLayout (or just Navigator.requestLayout?). Let me know if I've missed anything on the implementation side.

TextFlow not displayed with formatting

Hi,

Nice projects you've got here. I'm trying to use Flowless because using ListView + Textflow in Java 8u45 somehow makes the TextFlows on the list lose or change formatting when I add a new item. I'm not sure if I got the concept of TextFlow right, but I'm using a new instance for each item, because my ListView is meant to hold Nodes other than TextFlow e.g. WebView.

Anyway, I switched to test Flowless, because I was suspecting a layout issue with ListView, but I found that my TextFlows lose some formatting such as bold highlighting; though other stuff, like underline, still works.

The abstract class of my list item is just an extension of AnchorPane where I add the content after instantiation:

        // content is an arbitrary node
        AnchorPane.setTopAnchor(content, 0.0);
        AnchorPane.setBottomAnchor(content, 0.0);
        AnchorPane.setLeftAnchor(content, 0.0);
        AnchorPane.setRightAnchor(content, 0.0);

        getChildren().add(content);

Checking the TextFlow properties, everything seems as it should be:

[Text[text="Me:
", x=0.0, y=0.0, alignment=LEFT, origin=BASELINE, boundsType=LOGICAL, font=Font[name=System Bold, family=System, style=Bold, size=14.0], fontSmoothingType=GRAY, underline, fill=0x000000ff], Text[text="test", x=0.0, y=0.0, alignment=LEFT, origin=BASELINE, boundsType=LOGICAL, font=Font[name=System Regular, family=System, style=Regular, size=15.0], fontSmoothingType=GRAY, fill=0x000000ff]]

Would you have any ideas on what's going on?

Thanks :)

Edit 1: Agh. Sorry for the bother, it seems the same issue is happening as in ListView, so it might be an issue with TextFlow itself? It seems the only time certain formatting becomes active or works, is if ALL children have the format e.g. bold.

Edit 2: I didn't know where to ask, but how do you force the VirtualFlow to scroll to the very bottom? ListView had the convenient scrollTo(index), but VirtualFlow doesn't have that. I've tried VirtualFlow.scrollY(Double.MAX) and VirtualFlow.show(index), but they work erratically.

Keyboard paging computation error while paging up

This is from RichTextFX issue 935

Replicate

  1. Run the following JavaFX application, which uses RichTextFX:
    import javafx.application.Application;
    import javafx.scene.Scene;
    import javafx.scene.control.ScrollPane;
    import javafx.stage.Stage;
    import org.fxmisc.flowless.VirtualizedScrollPane;
    import org.fxmisc.richtext.StyleClassedTextArea;
    
    public class Pagination extends Application {
      public static void main( final String[] args ) {
        launch( args );
      }
    
      @Override
      public void start( final Stage stage ) {
        final var editor = new StyleClassedTextArea( false );
        final var scrollbars = new VirtualizedScrollPane<>( editor );
    
        scrollbars.setVbarPolicy( ScrollPane.ScrollBarPolicy.ALWAYS );
        editor.setWrapText( true );
    
        stage.setScene( new Scene(scrollbars) );
        stage.show();
      }
    }
  2. Copy multiple text paragraphs (e.g., https://www.lipsum.com/feed/html).
  3. Paste the text 5 times (to ensure the scrollbar extends).
  4. Do not resize the window (you can, but it'll mean more steps; if you did, start over):
    small-window
  5. Press Ctrl+Home to navigate to the top of the document.
  6. Press Ctrl+End to navigate to the bottom of the document.
  7. Press and hold Page Up to navigate upwards.

Expected Results

The view port navigates back one page for as long as the key is held, or the top is reached.

Actual Results

The computation for the new caret position goes awry in a variety of ways, depending on how much text is pasted and the view port size, resulting in one of the following behaviours:

  • Nothing happens.
  • View port scrolls up several times, but eventually stops, as though running into an asymptote.
  • View port scrolls up a few times, then scrolls to the same page within an infinite loop.

VirtualFlow GridPane

Thanks for this great library.
I was wondering if there are similar projects or if it would be easy to implement a GridPane in a virtualFlow. Given we have a List and we could specify that we want two columns and distribute space equally between the cells.

Do you know of any project that achieves this or is it rather simple to implement?

Cheers
Robin

Suspend VirtualFlow's scroll-related values until after fully rendered

The VirtualFlow's scroll-related values (estimated & total) are calculated based on the average height/width of a given cell's node. When the VirtualFlow is rendering its children, sometimes these averages get recalculated to a different value than they were before the rendering began. After rendering, these values are often set back to what they were before the rendering started.

However, since there is nothing stopping these values from propagating to their public end points (estimated & total scroll X/Y values), anything listening to them or subscribed to them will be updated immediately as well. As a result, one cannot use the scroll values to trigger some change when they are updated, as the layout process itself will always trigger such a change even when one doesn't ultimately occur.

Can't Get Clicked Item in List

I Have A Virtual ScrollPane
Displays All I want, except I cant Click Any Items.
Ima Currently Using Gridpane as the node in virtual flow,is that the way to Go ?
Screenshot (1505)

Changing styles of rows

This is really a question (I think), but I don't see any place to make those :).

For reusable cells, I change the classes associated with some of the elements when I reuse them. For example, my cell can be an HBox that contains a few Label elements. I try to change the classes on the labels, but when I scroll, Flowless applies the classes randomly (I'm changing colors with those classes).

Is there anything I can do to make this work, or is this a bug?

Add API for getting and showing a TargetPosition

Per the end of my comment in #32:

As a side note, I think there should be a way to get the navigator's current position, so that one could use that to determine what to display after some change occurs (e.g. scroll from the current position or display an item 10 indexes higher, etc.) via VirtualFlow's show method. In order to support that functionality, there would need to be more view-related API methods that returned a TargetPosition of a specific cell.

Issue with irregular size cell rendering

Hi, I am facing an issue with implementing Flowless with irregular sized cells. Basically it doesn't populate a cell with data even if a part of it is visible in the viewport. This can be seen in the image below:
scroll render issue

This goes away if I scroll a few ticks down as seen below:
scroll render issue 2

Another issue that I have is that it does not update the cell if the underlying data has been modified by the user. For example in the last image above the thumbnails should loose their borders once a user double clicks on them, but this does not happen with Flowless. It works fine if I use a ListView.

Smooth scrolling

VirtualFlow calculates a reasonable jump size when using the mouse wheel or scroll bar increment/decrement buttons. This leads to reasonable scrolling behaviour but with large content (e.g. a many page PDF) the scroll amount can be quite large, like 20 pixels or so, and this leads to a jerky feeling when scrolling.

Seeing as how ReactFX has the nice Val.animate() method it would probably be quite easy to fix this. I had a quick go at doing so without hacking Flowless itself but it seems the methods I'd need are all (package) private. Perhaps there's a simple trick to get this; I guess inserting a simple animated val with short duration between the desired scroll position and the actual position is sufficient.

Cell positioning

Is there a way to position the cells manually?
I'm trying to create a tree structure. In a tree structure the children of a node are positioned slightly to the right of the parent.
How can I tell Flowless to position the cell like that? Also, the space from the right depends on the level of the node, so it should be dynamic

VirtualFlow doesn't resize cells properly when layout bounds changes depending on the Orientation.

import java.util.Arrays;
import java.util.Random;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

public class VirtualFlowTest2 extends Application{

	// Attributes
	private static final Random RANDOM = new Random();

	// Start Methods
	public static void main(String[] args){
		launch(args);
	}

	@Override
	public void start(Stage stage) throws Exception{
		StackPane contentPane = new StackPane();
		VirtualFlow<String, Cell<String, ?>> virtualFlow = VirtualFlow
			.createHorizontal(FXCollections.observableArrayList(Arrays.asList("A", "B", "C", "D")), (value) -> {
				Button button = new Button();
				button.prefHeightProperty().bind(contentPane.heightProperty());
				button.prefWidthProperty().bind(contentPane.widthProperty().multiply(.1));
				button.setText(value);
				button.setBackground(new Background(
					new BackgroundFill(new Color(RANDOM.nextDouble(), RANDOM.nextDouble(), RANDOM.nextDouble(), 1),
						CornerRadii.EMPTY, Insets.EMPTY)));
				return Cell.wrapNode(button);
			});

		contentPane.getChildren().add(virtualFlow);
		max(virtualFlow);
		stage.setScene(new Scene(contentPane, 500, 500));
		stage.show();
	}

	public static Node[] max(Region... nodes){
		for(Region region : nodes){
			region.setMinSize(0, 0);
			region.setMaxSize(Double.MAX_VALUE, Double.MAX_VALUE);
		}
		return nodes;
	}
	// End Methods

}

As you can see I created a Horizontal VirtualFlow with cells 10% of the width of the parent. Now when resizing using only the width of the stage, which is also resizing the parent, you can see that the cells don't resize to 10% of the parent. This is due to SizeTracker lengthFN:

Val<Function<Cell<?, ?>, Double>> lengthFn =
	avoidFalseInvalidations(breadthForCells).map(breadth -> cell -> {
		return orientation.prefLength(cell, breadth);
	});

That static avoid false invalidation method I'm not 100% sure the purpose of it but essentially in this cause eats up the event that would cause the cells to be resized. This is just for the width. When you change the height of the VirtualFlow you can see that the cells height also change with it.

When you delete the call to avoidFalseInvalidations it will now properly resize the cells regarding resizing the stage's width.

Val<Function<Cell<?, ?>, Double>> lengthFn =
	breadthForCells.map(breadth -> cell -> {
		return orientation.prefLength(cell, breadth);
	});

Now say you make a Vertical VirtualFlow. With my same code you would have to make the cell's height take 10% of its parent and max width. Now when changing the height of the stage the VirtualFlow doesn't resize its cells while if you change the width it does. The same fix above works.

Now I know I provided a solution but I don't exactly know what that avoid false invalidation method exact purpose is. Maybe it is trying to prevent like an infinite loop of invalidating I don't know.

Exception during layout pass (seems to cause unresponsive GUI)

This exception is from a use of RichTextFX, but the stack trace is solely from Flowless so I'm reporting it here:

Exception in thread "JavaFX Application Thread" java.util.NoSuchElementException: No value present
	at java.util.Optional.get(Optional.java:135)
	at org.fxmisc.flowless.CellListManager.getPresentCell(CellListManager.java:56)
	at org.fxmisc.flowless.CellPositioner.getVisibleCell(CellPositioner.java:28)
	at org.fxmisc.flowless.Navigator.fillForwardFrom0(Navigator.java:231)
	at org.fxmisc.flowless.Navigator.fillForwardFrom0(Navigator.java:217)
	at org.fxmisc.flowless.Navigator.fillTowardsSkyFrom0(Navigator.java:323)
	at org.fxmisc.flowless.Navigator.fillViewportFrom(Navigator.java:284)
	at org.fxmisc.flowless.Navigator.visit(Navigator.java:161)
	at org.fxmisc.flowless.MinDistanceTo.accept(TargetPosition.java:148)
	at org.fxmisc.flowless.Navigator.layoutChildren(Navigator.java:67)
	at javafx.scene.Parent.layout(Parent.java:1087)
	at org.fxmisc.flowless.VirtualFlow.layoutChildren(VirtualFlow.java:165)
        at javafx.scene.Parent.layout(Parent.java:1087)
	at javafx.scene.Parent.layout(Parent.java:1093)
	...
	at javafx.scene.Scene.doLayoutPass(Scene.java:552)

The method getPresentCell does warn that it can throw, but I can't spot a relevant catch anywhere in the hierarchy. What's particularly problematic is that after this exception, the GUI stopped updating or responding. (That may be due to our surrounding code or something RichTextFX does, though -- it's hard to say.) I haven't yet been able to reproduce it consistently, unfortunately, but I've seen it twice now.

JavaFX 17 breaks scrollbar behaviours in VirtualizedScrollPane

Starting with javaFX 17-ea+11 I noticed that scrolling a StyledTextArea (from RichTextFX) no longer worked properly: when clicking the scroll bar elements, the text scrolls for the first couple of clicks and then entirely stop responding to clicks on these elements.
It does respond to using the mouse wheel of keyboard arrows however.

broken_scrolling.mp4

Since it did work with previous early access of jfx (up to 17-ea-9, actually), I did manage to pinpoint that change responsible: openjdk/jfx#454

The above PR changes the type of listener used internally by the built-in bi-directional bindings, from ChangeListeners<T> to InvalidationListeners.
This should be transparent to most if not all applications, but because Flowless relies on ReactFX, which interacts with bindings and events in a very intimate way, something was broken by that change.

I managed to workaround the issue in the VirtualizedScrollPane by replacing the affect bi-directional bindings by a couple of mirrored ChangeListeners.

I will submit a PR illustrating this workaround for your consideration.

Make overriding VirtualizedScrollpane's layoutChildren() more developer-friendly

Coming from FXMisc/RichTextFX#205 and relating to #9, provide more access to VirtualizedScrollPane's objects so that layoutChildren can be better overridden.

There's a few ways this could be done:

  • Complete freedom: make the (currently private) content, hbar, and vbar protected. Then the developer can fully layout the children as they desire.
  • Restrict to content layout: since a developer will need to rewrite the scroll bar implementation each time he/she extends VirtualizedScrollPane (or more probably, screw up how the scroll bars get laid out), use a protected method to layout the content which developers can override:
protected void layoutChildren() {
    // normal layout code...

    // instead of "content.resize(w, h)" have
    layoutContent(w, h);

   // rest of method's code.
}

protected void layoutContent(double width, double height) {
    content.resize(width, height);
}

JavaFX 16

Hi,

is this library of any use for JavaFX versions >8? The benchmarks in the readme have been performed on very old JavaFX 8 builds, so I was wondering if it still provides performance benefits on newer versions?

Adding items too fast causes scroll when item list is empty

Adding items too fast to item list of a VirtualFlow causes scroll if the item list is empty. Waiting few milliseconds after adding first item fixes the problem. Also calling visibleCells() method after adding first item fixes the problem but I don't know if its about time it takes or something else.

Demo:

public class Main extends Application {
    ObservableList<Integer> items = FXCollections.observableArrayList();
    VBox vbox = new VBox();
    Button add30Buttton = new Button("add 30");
    Button add1Button = new Button("add 1");
    Button removeAllButton = new Button("remove all");

    VirtualFlow<Integer, ?> virtualFlow = VirtualFlow.createVertical(items, i -> Cell.wrapNode(new Label(i.toString())));
    VirtualizedScrollPane<VirtualFlow<Integer, ?>> scrollPane = new VirtualizedScrollPane<>(virtualFlow);

    @Override
    public void start(Stage stage) {
        add30Buttton.setOnAction(event -> {
            items.add(0);
            // virtualFlow.visibleCells(); // uncommenting this fixes the problem
            for (int i = 1; i < 29; i++) { items.add(i); }
        });
        add1Button.setOnAction(event -> items.add(999));
        removeAllButton.setOnAction(event -> items.clear());

        VBox.setVgrow(scrollPane, Priority.ALWAYS);
        vbox.getChildren().addAll(add30Buttton, add1Button, removeAllButton, scrollPane);

        Scene scene = new Scene(vbox, 300, 400);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Scrollbar thumb is too small

Some components in JavaFx, which contains scrollbars, such as TextArea, ListView and ScrollPane, when the content is very long, the scrollbar's thumb become very small.
I kind of hoping this Flowless could provide a solution for this problem. So, is there any suggestion?

VirtualizedScrollPane causes high CPU and GPU on idle with 125% screen scaling

When using a control embedded inside a VirtualizedScrollPane with the upcoming release 16 of JavaFX, then it is possible under specific circumstances that the method layoutChildren() becomes perpetually invoked, causing high CPU and GPU usage even when the application is idle.

These conditions are:

  • Using openJFX 16 or higher at runtime
  • The effective screen scale at which the window is rendered is not a multiple of 100% (i.e. 125%, 150% or 175%, etc...).
  • The horizontal scrollbar is displayed.

The following code sample illustrates the issue, when run under javafx 16, with for instance a 125% scale (you can force it with -Dglass.win.uiScale=1.25 or -Dglass.gtk.uiScale=1.25, on windows or linux, respectively):

public class TextScroll extends Application {
    private final static String LONG_LINE_OF_TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
            "Nulla viverra fringilla dictum. Integer faucibus laoreet nulla eget vehicula. " +
            "Vivamus et arcu eget metus interdum tincidunt ac sed libero. Phasellus vestibulum" ;

    @Override
    public void start(Stage stage) throws Exception {
        var textArea = new CodeArea();
        textArea.replaceText(LONG_LINE_OF_TEXT);
        Scene scene = new Scene(new VirtualizedScrollPane<>(textArea), 800, 600);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

The root cause for this, is that the VirtualizedScrollPane request a layout when the height of the horizontal scroll bar changes but in the course and the layout, the calculated value for this height changes, which in turns triggers a request layout, etc...

This is due to the fact that a bug was fixed in JavaFX 16 (https://bugs.openjdk.java.net/browse/JDK-8211294) where the mechanism which snaps coordinates to actual pixels on screen with a non integer scale factor was broken; this is now fixed in javaFX, but Flowless remains unaware of the need for enforcing snapping, which causes some coordinates calculated in Flowless to be rounded differently that their equivalent in JavaFX; in this case this is what caused the scrollbar height to be different in two nested calls to layoutChildren, and lead to the constant layout.

A solution is to use snapSize() method to ensure height and width are snapped (i.e. ceil'd) to pixels consistently with JavaFX.

(NB: Ideally, we'd want to use snapSizeX() and snapSizeY() instead of the deprecated snapSize() so that we properly support non square screen ratio, but this is not available in JavaFX 8 that Flowless is built against.)

Stack items from bottom

If I'm not mistaken items laid out starting from top, it would be great if we can change to behavior to start stacking from the bottom this is useful for creating a widget for displaying chat messages.

Trackpad scrolling with momentum doesn't work on OS X

The vertical scroll lacks fluidity on OSX 10.11.6, while the horizontal scroll works as expected.
I have this problem with the demos, with juliar, and with my apps that integrate RichTextFx
See attached image for an illustration of the problem

ezgif-4-a6a97b039b

This issue its related to RichTextFX/issues/657 and RichTextFX/issues/265, and the solution proposed by @StrangeNoises works for me on OSX.

The @StrangeNoises code is integrated in the last codebase at #57

Layout-dependent methods need to call layout() first.

A deficiency found in FXMisc/RichTextFX#238.

Basic idea from Tomas:

Methods of VirtualFlow whose result depends on the layout should themselves call layout() as the first thing. [Otherwise, the returned results aren't always valid. (I added this)] Such methods would include getCellIfVisible, visibleCells and hit. The fact that they first call layout() should be documented in their Javadoc.

Gradually make estimated scroll position accurate

See FXMisc/RichTextFX#98

When laying out cells with varied heights, the scroll bar's value is only an estimate of how far the content has been scrolled, not the actual position. Thus, the goal is to turn this estimated value into the accurate value. Since this is only useful in some use cases, this should be an option, not a requirement.

One solution for achieving this thought of by Tomas himself (from above issue):

One could come up with some sophisticated algorithms, where the scroll position starts with an estimate (as it does now), and then in the background gradually improves the estimate. This would result in some flickering of the scrollbars before reaching the exact value, but that might be acceptable.

StackOverflowError

I am using RichTextFX in my project, but I am having an issue which seems to be contained to Flowless:

I use the following code to append a certain message in bold font:

private InlineCssTextArea text;

//....
    //In constructor
    text = new InlineCssTextArea();
    text.setWrapText(true);
//....

public void appendBold(String msg) {
    Platform.runLater(() -> {
        int curPos = text.getText().length(); //The index of the first new character
        int endPos = msg.length() + curPos - 1; //The index of the last new character
        text.appendText(msg);
        text.setStyle(curPos, endPos, "-fx-font-weight: bold;");            
   });
}

(I have two other, similar methods for italic and normal fonts)
This usually works, but sometimes it fails with a StackOverflowError, where the following section of stacktrace repeats continuously:

at org.fxmisc.flowless.VirtualFlow$$Lambda$238/562912964.invalidated(Unknown Source)
    at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:137)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
    at javafx.beans.binding.DoubleBinding.invalidate(DoubleBinding.java:222)
    at com.sun.javafx.binding.BindingHelperObserver.invalidated(BindingHelperObserver.java:51)
    at com.sun.javafx.binding.ExpressionHelper$SingleInvalidation.fireValueChangedEvent(ExpressionHelper.java:137)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
    at javafx.beans.binding.DoubleBinding.invalidate(DoubleBinding.java:222)
    at org.fxmisc.flowless.VirtualFlowContent.setLengthOffset(VirtualFlow.java:1426)
    at org.fxmisc.flowless.VirtualFlowContent.setLengthPosition(VirtualFlow.java:608)
    at org.fxmisc.flowless.VerticalFlowMetrics.setVerticalPosition(VirtualFlow.java:1848)
    at org.fxmisc.flowless.VirtualFlow.lambda$new$3(VirtualFlow.java:217)
    at org.fxmisc.flowless.VirtualFlow$$Lambda$240/1469374270.changed(Unknown Source)
    at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:361)
    at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
    at javafx.beans.property.DoublePropertyBase.fireValueChangedEvent(DoublePropertyBase.java:106)
    at javafx.beans.property.DoublePropertyBase.markInvalid(DoublePropertyBase.java:113)
    at javafx.beans.property.DoublePropertyBase.set(DoublePropertyBase.java:146)
    at javafx.scene.control.ScrollBar.setValue(ScrollBar.java:151)
    at org.fxmisc.flowless.VirtualFlow.lambda$new$1(VirtualFlow.java:211)

I can not find any common factor between the instances where this error occurs, so I'm not sure if you can help me with this, but I would very much appreciate it if you could have a look.

Custom Editor, Multiple Custom Objects, adding HyperlinkSegment and ImageSegment

Expected Behavior

When I added hyperlinks and images to Jugen's StyledSegmentTextArea, I was hoping the hyperlinks would work.

Actual Behavior

The first and third hyperlinks in the demo behave correctly, but the second hyperlink in the demo is somehow corrupted:

  • mouse-hovering over it produces lots of calls to createNode (see stdout of the program)
  • hovering does not cause the hyperlink to become underlined
  • clicking the link does not execute its handler

This Issue began life elsewhere

I first reported this issue here: FXMisc/RichTextFX#807

In there, Jugen said:

So it turns out that the culprit for this behavior is the image, in particular the vertical size of the image.

When the image is very tall, specifically it seems when the image is taller than the view-port, AND the hyperlink is in the same paragraph as the image then the mouse over somehow causes a re-layout to occur which is what you are seeing.

If you replace the image with one that is smaller vertically or put the hyperlink in a different paragraph then the re-layout doesn't occur anymore and the hyperlink behaves as expected.

The origins of this misbehavior is I think inside VirtualFlow in Flowless ?

Reproducible Demo

The source files are here: https://github.com/Kim4444/RichTextFXIssue

Demo Notes: First I downloaded the files at https://github.com/Jugen/StyledSegmentTextArea. I tweaked the source slightly, then added HyperlinkSegment and ImageSegment. I also use ReadOnlyStyledDocumentBuilder so I could build the doc one paragraph at a time. I tried to make as few changes to Jugen's demo as I could. There are more details in the demo file CodeChanges.txt. I am uncertain if it is a bug in my code, or in RichTextFX/supporting classes. Thank you so much for any help!

Environment info:

RichTextFX Version: 0.9.3
Flowless 0.6.1
ReactFX 2.0-M5
UndoFX 2.1.0
WellBehavedFX 0.3.3
Operating System: Windows 10
Java version: 8u181

Expandable cell problem

I'm trying to create list having expandable component inside cell. Everyting works great except from few last items on the list. Sometimes trying to expand/collapse has no effect. ActionEvent is never brought to handler as completly different button seems to be focused.
Is there any chance I can get my feature working correctly?
To reproduce please expand some element in the begining of the list, then scroll down to the bottom of the list and try to expand/collapse item using "Expand" button. Sometimes it takes few tries to reproduce.

import org.fxmisc.flowless.Cell;
import org.fxmisc.flowless.VirtualFlow;
import org.fxmisc.flowless.VirtualizedScrollPane;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class App extends Application {

	public static void main(String[] args) {
		launch(args);
	}

	@Override
	public void start(Stage primaryStage) throws Exception {

		ObservableList<Employee> employees = FXCollections.observableArrayList();
		for (int i = 0; i < 100; i++) {
			employees.add(new Employee("John " + i));
		}

		VirtualFlow<Employee, Cell<Employee, EmployeeView>> virtualFlow = VirtualFlow.createVertical(employees, employee -> Cell.wrapNode(new EmployeeView(employee)));
		VirtualizedScrollPane<VirtualFlow<Employee, Cell<Employee, EmployeeView>>> virtualizedScrollPane = new VirtualizedScrollPane<>(virtualFlow);
		Scene scene = new Scene(virtualizedScrollPane);
		primaryStage.setScene(scene);
		primaryStage.show();
	}

}

class Employee {
	private boolean expanded;
	private final String name;

	public Employee(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public boolean isExpanded() {
		return expanded;
	}

	public void setExpanded(boolean expanded) {
		this.expanded = expanded;
	}
}

class EmployeeView extends VBox {

	private final Button button = new Button("Expand");
	private final TextField textField = new TextField();
	private final HBox headerPane = new HBox(button, textField);

	private final StackPane contentPane = new StackPane();

	{
		contentPane.setStyle("-fx-background-color: red;");
		contentPane.setPrefHeight(100);
		getChildren().addAll(headerPane, contentPane);
	}

	public EmployeeView(Employee employee) {
		textField.setText(employee.getName());
		contentPane.setVisible(employee.isExpanded());
		contentPane.setManaged(employee.isExpanded());

		button.setOnAction(actionEvent -> {
			employee.setExpanded(!employee.isExpanded());
			contentPane.setVisible(employee.isExpanded());
			contentPane.setManaged(employee.isExpanded());
		});
	}
}

VirtualFlow returns incorrect height of first cell when in need of layout pass

I've been experimenting with Flowless in the context of a log-viewer and so far it has suited my needs perfectly, thanks!

I do however have one use-case that I'm struggling to implement. I want the VirtualFlow to vertically resize dynamically to the size of its content up to the point where it's limited by it's parents size. See this gist: https://gist.github.com/oddbjornkvalsund/f232c0f61fdc368d704f

It almost works, but for the rendering of the first cell it seems to get the calculated height wrong when the VirtualFlow is need of a layout pass. See line 90 of the gist.

Modular application cannot find flowless

Environment

  • Liberica JDK 17+35-LTS (w/JavaFX)
  • Gradle 7.2
  • Debian 10.11
  • IntelliJ 2021.2.3

Problem

Created a simple application that works with RichTextFX. Added a VirtualizedScrollPane, but IntelliJ reports the following problems:

  • Module not found: org.fxmisc.flowless
  • Cannot resolve symbol VirtalizedScrollPane

Is there a minimal example showing how to use Flowless + RichTextFX + JDK 17 + Gradle 7.2?

The relevant files are below.

module-info.java

module com.keenwrite.editor {
    requires javafx.controls;
    requires javafx.fxml;
    requires org.fxmisc.richtext;

    // Is this line correct? If not, what module is required?
    requires org.fxmisc.flowless;

    opens com.keenwrite.editor to javafx.fxml;
    exports com.keenwrite.editor;
}

HelloApplication.java

package com.keenwrite.editor;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.fxmisc.richtext.StyleClassedTextArea;

public class HelloApplication extends Application {
    @Override
    public void start(final Stage stage) {
        final var area = new StyleClassedTextArea();
        area.requestFollowCaret();
        area.setWrapText(true);

        // The IDE cannot find the class to import, despite the module being found.
        final var scrollPane = new VirualizedScrollPane(area);

        final var scene = new Scene(area, 400, 400);
        stage.setScene(scene);
        stage.show();
    }

    public static void main(final String[] args) {
        launch();
    }
}

build.gradle

plugins {
    id 'java'
}

repositories {
    mavenLocal()
    mavenCentral()
}

dependencies {
    implementation 'org.fxmisc.richtext:richtextfx:0.10.7'
    implementation 'org.fxmisc.flowless:flowless:0.6.7'

    testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
    testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
}

group = 'com.keenwrite'
version = '1.0-SNAPSHOT'
description = 'editor'
java.sourceCompatibility = JavaVersion.VERSION_17

tasks.withType(JavaCompile) {
    options.encoding = 'UTF-8'
}

settings.gradle

rootProject.name = 'editor'

Dynamically resize viewport based on content

Coming from FXMisc/RichTextFX#171 (and also FXMisc/RichTextFX#77)

It would be great if [the viewport] automatically changes it's height [and by implication, width] based on its content, so that [one] can set a minimum and a maximum and the box just gets bigger as additional content is added [or smaller as content is removed]. This could probably be done using minHeight and maxHeight.

org.fxmisc.flowless.CellListManager#getCellIfPresent

org.fxmisc.flowless.CellListManager#getCellIfPresent

changes the implementation as blow is better.

public Optional<C> getCellIfPresent(int itemIndex) {
    if (itemIndex>=cells.size()||itemIndex<0){
        return Optional.empty();
    }
    return cells.getIfMemoized(itemIndex); // getIfMemoized() may throw
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.