Skip to content

Commit

Permalink
Merge pull request #501 from JordanMartinez/exposeVisiblePars
Browse files Browse the repository at this point in the history
Expose visible paragraphs
  • Loading branch information
JordanMartinez authored Jun 7, 2017
2 parents 64c7d58 + 088fac7 commit b604c26
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 31 deletions.
77 changes: 46 additions & 31 deletions richtextfx/src/main/java/org/fxmisc/richtext/GenericStyledArea.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@
import org.reactfx.SuspendableEventStream;
import org.reactfx.SuspendableNo;
import org.reactfx.collection.LiveList;
import org.reactfx.collection.SuspendableList;
import org.reactfx.util.Tuple2;
import org.reactfx.value.SuspendableVal;
import org.reactfx.value.SuspendableVar;
Expand Down Expand Up @@ -497,6 +498,9 @@ public Optional<Tuple2<Codec<PS>, Codec<SEG>>> getStyleCodecs() {
// paragraphs
@Override public LiveList<Paragraph<PS, SEG, S>> getParagraphs() { return content.getParagraphs(); }

private final SuspendableList<Paragraph<PS, SEG, S>> visibleParagraphs;
@Override public final LiveList<Paragraph<PS, SEG, S>> getVisibleParagraphs() { return visibleParagraphs; }

// beingUpdated
private final SuspendableNo beingUpdated = new SuspendableNo();
public ObservableBooleanValue beingUpdatedProperty() { return beingUpdated; }
Expand Down Expand Up @@ -683,17 +687,6 @@ public GenericStyledArea(
() -> content.getText(internalSelection.getValue()),
internalSelection, content.getParagraphs()).suspendable();

final Suspendable omniSuspendable = Suspendable.combine(
beingUpdated, // must be first, to be the last one to release

caretPosition,
anchor,
selection,
selectedText,
currentParagraph,
caretColumn);
manageSubscription(omniSuspendable.suspendWhen(content.beingUpdatedProperty()));

// when content is updated by an area, update the caret
// and selection ranges of all the other
// clones that also share this document
Expand Down Expand Up @@ -769,6 +762,20 @@ public GenericStyledArea(
});
getChildren().add(virtualFlow);

visibleParagraphs = LiveList.map(virtualFlow.visibleCells(), c -> c.getNode().getParagraph()).suspendable();

final Suspendable omniSuspendable = Suspendable.combine(
beingUpdated, // must be first, to be the last one to release

visibleParagraphs,
caretPosition,
anchor,
selection,
selectedText,
currentParagraph,
caretColumn);
manageSubscription(omniSuspendable.suspendWhen(content.beingUpdatedProperty()));

// initialize navigator
IntSupplier cellCount = () -> getParagraphs().size();
IntUnaryOperator cellLength = i -> virtualFlow.getCell(i).getNode().getLineCount();
Expand Down Expand Up @@ -1140,62 +1147,62 @@ public Position offsetToPosition(int charOffset, Bias bias) {

@Override
public void scrollXToPixel(double pixel) {
virtualFlow.scrollXToPixel(pixel);
suspendVisibleParsWhile(() -> virtualFlow.scrollXToPixel(pixel));
}

@Override
public void scrollYToPixel(double pixel) {
virtualFlow.scrollYToPixel(pixel);
suspendVisibleParsWhile(() -> virtualFlow.scrollYToPixel(pixel));
}

@Override
public void scrollXBy(double deltaX) {
virtualFlow.scrollXBy(deltaX);
suspendVisibleParsWhile(() -> virtualFlow.scrollXBy(deltaX));
}

@Override
public void scrollYBy(double deltaY) {
virtualFlow.scrollYBy(deltaY);
suspendVisibleParsWhile(() -> virtualFlow.scrollYBy(deltaY));
}

@Override
public void scrollBy(Point2D deltas) {
virtualFlow.scrollBy(deltas);
suspendVisibleParsWhile(() -> virtualFlow.scrollBy(deltas));
}

void show(double y) {
virtualFlow.show(y);
suspendVisibleParsWhile(() -> virtualFlow.show(y));
}

@Override
public void showParagraphInViewport(int paragraphIndex) {
virtualFlow.show(paragraphIndex);
suspendVisibleParsWhile(() -> virtualFlow.show(paragraphIndex));
}

@Override
public void showParagraphAtTop(int paragraphIndex) {
virtualFlow.showAsFirst(paragraphIndex);
suspendVisibleParsWhile(() -> virtualFlow.showAsFirst(paragraphIndex));
}

@Override
public void showParagraphAtBottom(int paragraphIndex) {
virtualFlow.showAsLast(paragraphIndex);
suspendVisibleParsWhile(() -> virtualFlow.showAsLast(paragraphIndex));
}

void showCaretAtBottom() {
int parIdx = getCurrentParagraph();
Cell<Paragraph<PS, SEG, S>, ParagraphBox<PS, SEG, S>> cell = virtualFlow.getCell(parIdx);
Bounds caretBounds = cell.getNode().getCaretBounds();
double y = caretBounds.getMaxY();
virtualFlow.showAtOffset(parIdx, getViewportHeight() - y);
suspendVisibleParsWhile(() -> virtualFlow.showAtOffset(parIdx, getViewportHeight() - y));
}

void showCaretAtTop() {
int parIdx = getCurrentParagraph();
Cell<Paragraph<PS, SEG, S>, ParagraphBox<PS, SEG, S>> cell = virtualFlow.getCell(parIdx);
Bounds caretBounds = cell.getNode().getCaretBounds();
double y = caretBounds.getMinY();
virtualFlow.showAtOffset(parIdx, -y);
suspendVisibleParsWhile(() -> virtualFlow.showAtOffset(parIdx, -y));
}

@Override
Expand All @@ -1204,6 +1211,7 @@ public void requestFollowCaret() {
requestLayout();
}

/** Assumes this method is called within a {@link #suspendVisibleParsWhile(Runnable)} block */
private void followCaret() {
int parIdx = getCurrentParagraph();
Cell<Paragraph<PS, SEG, S>, ParagraphBox<PS, SEG, S>> cell = virtualFlow.getCell(parIdx);
Expand Down Expand Up @@ -1344,16 +1352,19 @@ public void dispose() {
@Override
protected void layoutChildren() {
Insets ins = getInsets();
virtualFlow.resizeRelocate(
ins.getLeft(), ins.getTop(),
getWidth() - ins.getLeft() - ins.getRight(),
getHeight() - ins.getTop() - ins.getBottom());
if(followCaretRequested) {
followCaretRequested = false;
try (Guard g = viewportDirty.suspend()) {
followCaret();
visibleParagraphs.suspendWhile(() -> {
virtualFlow.resizeRelocate(
ins.getLeft(), ins.getTop(),
getWidth() - ins.getLeft() - ins.getRight(),
getHeight() - ins.getTop() - ins.getBottom());

if(followCaretRequested) {
followCaretRequested = false;
try (Guard g = viewportDirty.suspend()) {
followCaret();
}
}
}
});

// position popup
layoutPopup();
Expand Down Expand Up @@ -1589,6 +1600,10 @@ private Guard suspend(Suspendable... suspendables) {
return Suspendable.combine(beingUpdated, Suspendable.combine(suspendables)).suspend();
}

private void suspendVisibleParsWhile(Runnable runnable) {
Suspendable.combine(beingUpdated, visibleParagraphs).suspendWhile(runnable);
}

void clearTargetCaretOffset() {
targetCaretOffset = Optional.empty();
}
Expand Down
7 changes: 7 additions & 0 deletions richtextfx/src/main/java/org/fxmisc/richtext/ViewActions.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import javafx.scene.input.MouseEvent;
import javafx.scene.text.TextFlow;
import org.fxmisc.richtext.model.NavigationActions;
import org.fxmisc.richtext.model.Paragraph;
import org.reactfx.collection.LiveList;
import org.reactfx.value.Val;
import org.reactfx.value.Var;

Expand Down Expand Up @@ -252,6 +254,11 @@ public static enum CaretVisibility {
double getTotalHeightEstimate();
Val<Double> totalHeightEstimateProperty();

/**
* Gets the visible paragraphs, even the ones that are barely displayed.
*/
LiveList<Paragraph<PS, SEG, S>> getVisibleParagraphs();

/**
* Gets the style applicator.
*/
Expand Down

0 comments on commit b604c26

Please sign in to comment.