blob: 756e1a03cb2ee816a0f2aa850d2e22301a1234f2 [file] [log] [blame]
package org.eclipse.fx.ui.controls.styledtext_ng.internal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.fx.core.Subscription;
import org.eclipse.fx.core.geom.Size;
import org.eclipse.fx.core.text.TextUtil;
import org.eclipse.fx.ui.controls.Util;
import org.eclipse.fx.ui.controls.styledtext_ng.StyledLineRenderer;
import com.google.common.collect.Range;
import com.google.common.collect.RangeSet;
import com.google.common.collect.TreeRangeSet;
import javafx.scene.paint.Paint;
import javafx.scene.text.Font;
import javafx.scene.text.FontPosture;
import javafx.scene.text.FontWeight;
public abstract class BaseStyledLineRenderer implements StyledLineRenderer {
char[] originalText = new char[0];
char[] displayedText = new char[0];
char[] tabReplace = new char[4];
Font normal;
Font bold;
Font italic;
Font boldItalic;
double w;
double h;
private RangeSet<Integer> boldRange = TreeRangeSet.create();
private RangeSet<Integer> italicRange = TreeRangeSet.create();
private List<PaintRange> paintRanges = new ArrayList<>();
int flag = 0;
boolean combinedAction;
static final int FONTS = 1;
static final int FILL = 1 << 1;
static final int TEXT = 1 << 2;
public BaseStyledLineRenderer() {
Arrays.fill(tabReplace, ' ');
}
protected RangeSet<Integer> getNormalRange() {
TreeRangeSet<Integer> set = TreeRangeSet.create();
set.add(Range.closed(0, this.originalText.length));
set.removeAll(this.boldRange);
set.removeAll(this.italicRange);
return set;
}
protected RangeSet<Integer> getBoldRange() {
if( this.italicRange.isEmpty() ) {
return this.boldRange;
}
RangeSet<Integer> onlyBold = TreeRangeSet.create(this.boldRange);
onlyBold.removeAll(this.italicRange);
return onlyBold;
}
protected RangeSet<Integer> getItalicRange() {
if( this.boldRange.isEmpty() ) {
return this.italicRange;
}
RangeSet<Integer> onlyItalic = TreeRangeSet.create(this.italicRange);
onlyItalic.removeAll(this.boldRange);
return onlyItalic;
}
protected RangeSet<Integer> getBoldItalicRange() {
if( this.italicRange.isEmpty() && this.boldRange.isEmpty() ) {
RangeSet<Integer> italicBoldRange = TreeRangeSet.create(boldRange);
italicBoldRange.removeAll(italicRange.complement());
return italicBoldRange;
}
return TreeRangeSet.create();
}
protected List<PaintRange> getPaintRanges() {
return paintRanges;
}
@Override
public void setFont(String family, double size) {
this.normal = Font.font(family, size);
this.bold = Font.font(family, FontWeight.BOLD, size);
this.italic = Font.font(family, FontPosture.ITALIC, size);
this.boldItalic = Font.font(family, FontWeight.BOLD, FontPosture.ITALIC, size);
Size dim = Util.getSize(this.normal, 'A');
this.w = dim.width;
this.h = dim.height;
rebuildFonts();
}
@Override
public Subscription setBold(org.eclipse.fx.core.Range r) {
Range<Integer> range = Range.closed(r.start, r.end-1);
this.boldRange.add(range);
rebuildFonts();
return () -> {
this.boldRange.remove(range);
rebuildFonts();
};
}
@Override
public Subscription setItalic(org.eclipse.fx.core.Range r) {
Range<Integer> range = Range.closed(r.start, r.end-1);
this.italicRange.add(range);
rebuildFonts();
return () -> {
this.italicRange.remove(range);
rebuildFonts();
};
}
@Override
public Subscription setForeground(Paint paint, org.eclipse.fx.core.Range r) {
Range<Integer> closed = Range.closed(r.start, r.end-1);
for( PaintRange pr : paintRanges ) {
if( pr.range.equals(closed) ) {
pr.paint = paint;
rebuildFill();
return null;
}
}
PaintRange range = new PaintRange(paint, closed);
this.paintRanges.add(range);
rebuildFill();
return () -> {
this.paintRanges.remove(range);
rebuildFill();
};
}
@Override
public void setText(char[] text) {
this.originalText = text;
this.displayedText = TextUtil.replaceAll(this.originalText, '\t', this.tabReplace);
rebuildText();
}
static class PaintRange {
Paint paint;
final Range<Integer> range;
public PaintRange(Paint paint, Range<Integer> range) {
this.paint = paint;
this.range = range;
}
}
public void combinedAction(Runnable r) {
this.combinedAction = true;
try {
r.run();
} finally {
this.combinedAction = false;
}
if( (this.flag & FONTS) == FONTS ) {
rebuildFonts();
}
if( (this.flag & FILL) == FILL ) {
rebuildFill();
}
if( (this.flag & TEXT) == TEXT ) {
rebuildText();
}
}
protected abstract void rebuildFill();
protected abstract void rebuildFonts();
protected abstract void rebuildText();
}