Search in sources :

Example 1 with Cell

use of org.fxmisc.flowless.Cell in project RichTextFX by FXMisc.

the class GenericStyledArea method createCell.

/* ********************************************************************** *
     *                                                                        *
     * Private methods                                                        *
     *                                                                        *
     * ********************************************************************** */
private Cell<Paragraph<PS, SEG, S>, ParagraphBox<PS, SEG, S>> createCell(Paragraph<PS, SEG, S> paragraph, BiConsumer<TextFlow, PS> applyParagraphStyle, Function<StyledSegment<SEG, S>, Node> nodeFactory) {
    ParagraphBox<PS, SEG, S> box = new ParagraphBox<>(paragraph, applyParagraphStyle, nodeFactory);
    box.highlightTextFillProperty().bind(highlightTextFill);
    box.wrapTextProperty().bind(wrapTextProperty());
    box.graphicFactoryProperty().bind(paragraphGraphicFactoryProperty());
    box.graphicOffset.bind(virtualFlow.breadthOffsetProperty());
    EventStream<Integer> boxIndexValues = box.indexProperty().values().filter(i -> i != -1);
    Subscription firstParPseudoClass = boxIndexValues.subscribe(idx -> box.pseudoClassStateChanged(FIRST_PAR, idx == 0));
    Subscription lastParPseudoClass = EventStreams.combine(boxIndexValues, getParagraphs().sizeProperty().values()).subscribe(in -> in.exec((i, n) -> box.pseudoClassStateChanged(LAST_PAR, i == n - 1)));
    // set up caret
    Function<CaretNode, Subscription> subscribeToCaret = caret -> {
        EventStream<Integer> caretIndexStream = EventStreams.nonNullValuesOf(caret.paragraphIndexProperty());
        // a new event stream needs to be created for each caret added, so that it will immediately
        // fire the box's current index value as an event, thereby running the code in the subscribe block
        // Reusing boxIndexValues will not fire its most recent event, leading to a caret not being added
        // Thus, we'll call the new event stream "fresh" box index values
        EventStream<Integer> freshBoxIndexValues = box.indexProperty().values().filter(i -> i != -1);
        return EventStreams.combine(caretIndexStream, freshBoxIndexValues).subscribe(t -> {
            int caretParagraphIndex = t.get1();
            int boxIndex = t.get2();
            if (caretParagraphIndex == boxIndex) {
                box.caretsProperty().add(caret);
            } else {
                box.caretsProperty().remove(caret);
            }
        });
    };
    Subscription caretSubscription = caretSet.addSubscriber(subscribeToCaret);
    // TODO: how should 'hasCaret' be handled now?
    Subscription hasCaretPseudoClass = EventStreams.combine(boxIndexValues, Val.wrap(currentParagraphProperty()).values()).map(t -> t.get1().equals(t.get2())).subscribe(value -> box.pseudoClassStateChanged(HAS_CARET, value));
    Function<Selection<PS, SEG, S>, Subscription> subscribeToSelection = selection -> {
        EventStream<Integer> startParagraphValues = EventStreams.nonNullValuesOf(selection.startParagraphIndexProperty());
        EventStream<Integer> endParagraphValues = EventStreams.nonNullValuesOf(selection.endParagraphIndexProperty());
        // see comment in caret section about why a new box index EventStream is needed
        EventStream<Integer> freshBoxIndexValues = box.indexProperty().values().filter(i -> i != -1);
        return EventStreams.combine(startParagraphValues, endParagraphValues, freshBoxIndexValues).subscribe(t -> {
            int startPar = t.get1();
            int endPar = t.get2();
            int boxIndex = t.get3();
            if (startPar <= boxIndex && boxIndex <= endPar) {
                // So that we don't add multiple paths for the same selection,
                // which leads to not removing the additional paths when selection is removed,
                // this is a `Map#putIfAbsent(Key, Value)` implementation that creates the path lazily
                SelectionPath p = box.selectionsProperty().get(selection);
                if (p == null) {
                    // create & configure path
                    Val<IndexRange> range = Val.create(() -> boxIndex != -1 ? getParagraphSelection(selection, boxIndex) : EMPTY_RANGE, selection.rangeProperty());
                    SelectionPath path = new SelectionPath(range);
                    selection.configureSelectionPath(path);
                    box.selectionsProperty().put(selection, path);
                }
            } else {
                box.selectionsProperty().remove(selection);
            }
        });
    };
    Subscription selectionSubscription = selectionSet.addSubscriber(subscribeToSelection);
    return new Cell<Paragraph<PS, SEG, S>, ParagraphBox<PS, SEG, S>>() {

        @Override
        public ParagraphBox<PS, SEG, S> getNode() {
            return box;
        }

        @Override
        public void updateIndex(int index) {
            box.setIndex(index);
        }

        @Override
        public void dispose() {
            box.highlightTextFillProperty().unbind();
            box.wrapTextProperty().unbind();
            box.graphicFactoryProperty().unbind();
            box.graphicOffset.unbind();
            firstParPseudoClass.unsubscribe();
            lastParPseudoClass.unsubscribe();
            caretSubscription.unsubscribe();
            hasCaretPseudoClass.unsubscribe();
            selectionSubscription.unsubscribe();
        }
    };
}
Also used : EventHandler(javafx.event.EventHandler) NamedArg(javafx.beans.NamedArg) SuspendableNo(org.reactfx.SuspendableNo) IntUnaryOperator(java.util.function.IntUnaryOperator) PseudoClass(javafx.css.PseudoClass) Cell(org.fxmisc.flowless.Cell) BiFunction(java.util.function.BiFunction) TextOps(org.fxmisc.richtext.model.TextOps) SuspendableEventStream(org.reactfx.SuspendableEventStream) PlainTextChange(org.fxmisc.richtext.model.PlainTextChange) StyleConverter(javafx.css.StyleConverter) ContextMenu(javafx.scene.control.ContextMenu) GenericEditableStyledDocument(org.fxmisc.richtext.model.GenericEditableStyledDocument) Duration(java.time.Duration) TwoDimensional(org.fxmisc.richtext.model.TwoDimensional) Point2D(javafx.geometry.Point2D) UndoManager(org.fxmisc.undo.UndoManager) VirtualFlowHit(org.fxmisc.flowless.VirtualFlowHit) SubscribeableContentsObsSet(org.fxmisc.richtext.util.SubscribeableContentsObsSet) Guard(org.reactfx.Guard) ObservableSet(javafx.collections.ObservableSet) UndoUtils(org.fxmisc.richtext.util.UndoUtils) LiveList(org.reactfx.collection.LiveList) CssMetaData(javafx.css.CssMetaData) Event(javafx.event.Event) Virtualized(org.fxmisc.flowless.Virtualized) List(java.util.List) BooleanProperty(javafx.beans.property.BooleanProperty) Region(javafx.scene.layout.Region) TwoLevelNavigator(org.fxmisc.richtext.model.TwoLevelNavigator) Subscription(org.reactfx.Subscription) Tuple2(org.reactfx.util.Tuple2) Paint(javafx.scene.paint.Paint) EventStreams(org.reactfx.EventStreams) Optional(java.util.Optional) SimpleDoubleProperty(javafx.beans.property.SimpleDoubleProperty) Suspendable(org.reactfx.Suspendable) Styleable(javafx.css.Styleable) Bounds(javafx.geometry.Bounds) CornerRadii(javafx.scene.layout.CornerRadii) Val(org.reactfx.value.Val) BoundingBox(javafx.geometry.BoundingBox) MouseEvent(javafx.scene.input.MouseEvent) StyleSpans(org.fxmisc.richtext.model.StyleSpans) FXCollections(javafx.collections.FXCollections) Codec(org.fxmisc.richtext.model.Codec) DoubleProperty(javafx.beans.property.DoubleProperty) TextFlow(javafx.scene.text.TextFlow) Function(java.util.function.Function) MouseOverTextEvent(org.fxmisc.richtext.event.MouseOverTextEvent) ArrayList(java.util.ArrayList) IndexRange(javafx.scene.control.IndexRange) Paragraph(org.fxmisc.richtext.model.Paragraph) Insets(javafx.geometry.Insets) BackgroundFill(javafx.scene.layout.BackgroundFill) BiConsumer(java.util.function.BiConsumer) IntSupplier(java.util.function.IntSupplier) IntFunction(java.util.function.IntFunction) Color(javafx.scene.paint.Color) ObjectProperty(javafx.beans.property.ObjectProperty) ReadOnlyStyledDocument(org.fxmisc.richtext.model.ReadOnlyStyledDocument) Node(javafx.scene.Node) RichTextChange(org.fxmisc.richtext.model.RichTextChange) Replacement(org.fxmisc.richtext.model.Replacement) Tuples(org.reactfx.util.Tuples) Background(javafx.scene.layout.Background) Consumer(java.util.function.Consumer) StyledDocument(org.fxmisc.richtext.model.StyledDocument) SimpleBooleanProperty(javafx.beans.property.SimpleBooleanProperty) StyleableObjectProperty(javafx.css.StyleableObjectProperty) VirtualizedScrollPane(org.fxmisc.flowless.VirtualizedScrollPane) StyledSegment(org.fxmisc.richtext.model.StyledSegment) SimpleObjectProperty(javafx.beans.property.SimpleObjectProperty) SuspendableList(org.reactfx.collection.SuspendableList) ObservableValue(javafx.beans.value.ObservableValue) EditableStyledDocument(org.fxmisc.richtext.model.EditableStyledDocument) VirtualFlow(org.fxmisc.flowless.VirtualFlow) Var(org.reactfx.value.Var) EventStream(org.reactfx.EventStream) Collections(java.util.Collections) Val(org.reactfx.value.Val) SuspendableEventStream(org.reactfx.SuspendableEventStream) EventStream(org.reactfx.EventStream) Subscription(org.reactfx.Subscription) Cell(org.fxmisc.flowless.Cell)

Aggregations

Duration (java.time.Duration)1 ArrayList (java.util.ArrayList)1 Collections (java.util.Collections)1 List (java.util.List)1 Optional (java.util.Optional)1 BiConsumer (java.util.function.BiConsumer)1 BiFunction (java.util.function.BiFunction)1 Consumer (java.util.function.Consumer)1 Function (java.util.function.Function)1 IntFunction (java.util.function.IntFunction)1 IntSupplier (java.util.function.IntSupplier)1 IntUnaryOperator (java.util.function.IntUnaryOperator)1 NamedArg (javafx.beans.NamedArg)1 BooleanProperty (javafx.beans.property.BooleanProperty)1 DoubleProperty (javafx.beans.property.DoubleProperty)1 ObjectProperty (javafx.beans.property.ObjectProperty)1 SimpleBooleanProperty (javafx.beans.property.SimpleBooleanProperty)1 SimpleDoubleProperty (javafx.beans.property.SimpleDoubleProperty)1 SimpleObjectProperty (javafx.beans.property.SimpleObjectProperty)1 ObservableValue (javafx.beans.value.ObservableValue)1