blob: 001216a1e249b6efc37aec3702e977641482d626 [file] [log] [blame]
package org.eclipse.fx.ui.controls.styledtext_ng.internal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.eclipse.fx.core.text.TextUtil;
import org.eclipse.fx.ui.controls.Util;
import com.google.common.collect.RangeSet;
import com.google.common.collect.TreeRangeSet;
import javafx.collections.ObservableList;
import javafx.scene.Node;
import javafx.scene.layout.Region;
import javafx.scene.paint.Paint;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
public class SingleTextStyledLineRenderer extends BaseStyledLineRenderer {
private final LayoutPane node;
public SingleTextStyledLineRenderer() {
this.node = new LayoutPane();
}
@Override
public void setVisibleRange(double minX, double width) {
// TODO Auto-generated method stub
}
@Override
public void clearStyles() {
// TODO Auto-generated method stub
}
@Override
public Node getNode() {
return node;
}
@Override
protected void rebuildFill() {
rebuildText();
}
@Override
protected void rebuildFonts() {
rebuildText();
}
@Override
protected void rebuildText() {
if( this.combinedAction ) {
this.flag |= TEXT;
return;
}
this.node.requestLayout();
}
private void refreshLayout() {
if( this.flag == 0 ) {
return;
}
this.flag = 0;
RangeSet<Integer> normalFont = getNormalRange();
RangeSet<Integer> boldRange = getBoldRange();
RangeSet<Integer> italicRange = getItalicRange();
RangeSet<Integer> boldItalicRange = getBoldItalicRange();
Map<Paint, RangeSet<Integer>> normalTextColors = new HashMap<>();
Map<Paint, RangeSet<Integer>> boldTextColors = new HashMap<>();
Map<Paint, RangeSet<Integer>> italicTextColors = new HashMap<>();
Map<Paint, RangeSet<Integer>> italicBoldTextColors = new HashMap<>();
for( PaintRange r : getPaintRanges() ) {
if( ! normalFont.subRangeSet(r.range).isEmpty() ) {
RangeSet<Integer> set = normalTextColors.computeIfAbsent(r.paint, p -> TreeRangeSet.create());
set.addAll(normalFont.subRangeSet(r.range));
} else {
if( ! boldItalicRange.isEmpty() && ! boldItalicRange.subRangeSet(r.range).isEmpty() ) {
RangeSet<Integer> set = italicBoldTextColors.computeIfAbsent(r.paint, p -> TreeRangeSet.create());
set.addAll(boldItalicRange.subRangeSet(r.range));
} else if( ! italicRange.subRangeSet(r.range).isEmpty() ) {
RangeSet<Integer> set = italicTextColors.computeIfAbsent(r.paint, p -> TreeRangeSet.create());
set.addAll(italicRange.subRangeSet(r.range));
} else if( ! boldRange.subRangeSet(r.range).isEmpty() ) {
RangeSet<Integer> set = boldTextColors.computeIfAbsent(r.paint, p -> TreeRangeSet.create());
set.addAll(boldRange.subRangeSet(r.range));
}
}
}
Arrays.fill(this.tabReplace, ' ');
List<Node> l = new ArrayList<>();
l.addAll(createTextNodes(normalTextColors, this.originalText, this.tabReplace, this.normal));
l.addAll(createTextNodes(boldTextColors, this.originalText, this.tabReplace, this.bold));
l.addAll(createTextNodes(italicTextColors, this.originalText, this.tabReplace, this.italic));
l.addAll(createTextNodes(italicBoldTextColors, this.originalText, this.tabReplace, this.boldItalic));
l.stream().forEach( n -> System.err.println(n));
this.node.getChildren().setAll(l);
}
private static List<Text> createTextNodes(Map<Paint, RangeSet<Integer>> textColorRanges, char[] text, char[] tabReplace, Font font) {
List<Text> nodes = new ArrayList<>();
for( Entry<Paint, RangeSet<Integer>> e : textColorRanges.entrySet() ) {
char[] txt = TextUtil.replace(text, ' ', ( idx, ch ) -> {
return ch != '\t' && ! e.getValue().contains(idx);
});
Text tNode = new Text(String.valueOf(TextUtil.replaceAll(txt, '\r', tabReplace)));
tNode.setFont(font);
tNode.setFill(e.getKey());
nodes.add(tNode);
}
return nodes;
}
class LayoutPane extends Region {
@Override
protected ObservableList<Node> getChildren() {
return super.getChildren();
}
@Override
protected void layoutChildren() {
refreshLayout();
getChildren().forEach( c -> c.resizeRelocate(0, 0, c.prefWidth(-1), c.prefHeight(-1)));
}
@Override
protected double computeMinHeight(double width) {
return Util.getSize(normal, ' ').height;
}
@Override
protected double computePrefHeight(double width) {
return super.computeMinHeight(width);
}
@Override
protected double computeMaxHeight(double width) {
return super.computeMinHeight(width);
}
@Override
protected double computeMinWidth(double height) {
return Util.getSize(SingleTextStyledLineRenderer.this.normal, ' ').width * SingleTextStyledLineRenderer.this.displayedText.length;
}
@Override
protected double computePrefWidth(double height) {
return super.computeMinWidth(height);
}
@Override
protected double computeMaxWidth(double height) {
return super.computeMinWidth(height);
}
}
}