remove TextFlower
This commit is contained in:
@@ -1,334 +0,0 @@
|
||||
package com.imyeyu.fx.ui.components;
|
||||
|
||||
import com.imyeyu.fx.icon.TimiFXIcon;
|
||||
import com.imyeyu.fx.ui.TimiFXUI;
|
||||
import com.imyeyu.java.TimiJava;
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.paint.Paint;
|
||||
import javafx.scene.text.Text;
|
||||
import javafx.scene.text.TextFlow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 文本流组件,支持插入超链文本,解析富文本:{@link #matcher(String)}
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2022-09-05 10:41
|
||||
*/
|
||||
public class TextFlower extends TextFlow implements TimiFXUI {
|
||||
|
||||
/** 默认构造器 */
|
||||
public TextFlower() {
|
||||
getStyleClass().add(CSS.MINECRAFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 文本开始,添加一个制表符
|
||||
*
|
||||
* @return 本实例
|
||||
*/
|
||||
public TextFlower textStart() {
|
||||
getChildren().add(new Text("\t"));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加文本,左侧补充一个制表符,通常是段落开始
|
||||
*
|
||||
* @param text 文本
|
||||
* @return 本实例
|
||||
*/
|
||||
public TextFlower textStart(String text) {
|
||||
getChildren().add(new Text("\t" + text));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加文本
|
||||
*
|
||||
* @param text 文本
|
||||
* @return 本实例
|
||||
*/
|
||||
public TextFlower text(String text) {
|
||||
getChildren().add(new Text(text));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加文本,左侧补充空格
|
||||
*
|
||||
* @param text 文本
|
||||
* @return 本实例
|
||||
*/
|
||||
public TextFlower textLSP(String text) {
|
||||
getChildren().add(new Text(" " + text));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加文本,右侧补充空格
|
||||
*
|
||||
* @param text 文本
|
||||
* @return 本实例
|
||||
*/
|
||||
public TextFlower textRSP(String text) {
|
||||
getChildren().add(new Text(text + " "));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加链接文本
|
||||
*
|
||||
* @param text 显示文本
|
||||
* @param link 访问链接
|
||||
* @return 本实例
|
||||
*/
|
||||
public TextFlower link(String text, String link) {
|
||||
getChildren().add(new XHyperlink(text, link));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加链接文本
|
||||
*
|
||||
* @param icon 图标
|
||||
* @param text 显示文本
|
||||
* @param link 访问链接
|
||||
* @return 本实例
|
||||
*/
|
||||
public TextFlower link(Node icon, String text, String link) {
|
||||
getChildren().add(new XHyperlink(icon, text, link));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加链接,显示文本为链接
|
||||
*
|
||||
* @param value 内容
|
||||
* @return 本实例
|
||||
*/
|
||||
public TextFlower syncLink(String value) {
|
||||
getChildren().add(new XHyperlink(value, value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置最后一个文本节点为链接
|
||||
*
|
||||
* @param link 链接
|
||||
* @return 本实例
|
||||
*/
|
||||
public TextFlower asLink(String link) {
|
||||
Node text = getChildren().removeLast();
|
||||
if (text instanceof Text t) {
|
||||
getChildren().add(new XHyperlink(t.getText(), link));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 富文本匹配解析字符串,转义使用 '\'
|
||||
* <br>
|
||||
* <p>格式标准:
|
||||
* <ul>
|
||||
* <li>超链:[可选文本,连接]</li>
|
||||
* <li>图标:<可选颜色, timi-fx-icon 图标名称></li>
|
||||
* <li>重点:`[可选样式,内容]`</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param value 字符串
|
||||
* @return 本实例
|
||||
*/
|
||||
public TextFlower matcher(String value) {
|
||||
if (TimiJava.isNotEmpty(value)) {
|
||||
getChildren().addAll(RichMatcher.parse(value));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 富文本匹配
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2022-10-10 11:23
|
||||
*/
|
||||
private static class RichMatcher {
|
||||
|
||||
/**
|
||||
* 匹配正则
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2022-10-10 11:58
|
||||
*/
|
||||
private enum Regex {
|
||||
|
||||
LINK("\\[(.*?)]"),
|
||||
|
||||
ICON("<(.*?)>"),
|
||||
|
||||
SPAN("`(.*?)`");
|
||||
|
||||
final Pattern pattern;
|
||||
|
||||
Regex(String regex) {
|
||||
this.pattern = Pattern.compile(regex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重点内容样式
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2022-10-10 11:58
|
||||
*/
|
||||
private enum Style {
|
||||
|
||||
UNDERLINE("u", "underline");
|
||||
|
||||
private final String[] matches;
|
||||
|
||||
Style(String... matches) {
|
||||
this.matches = matches;
|
||||
}
|
||||
|
||||
static Style fromMatcher(String matcher) {
|
||||
Style[] values = values();
|
||||
for (Style value : values) {
|
||||
String[] matches = value.matches;
|
||||
for (String match : matches) {
|
||||
if (match.equalsIgnoreCase(matcher)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析富文本匹配
|
||||
*
|
||||
* @param data 文本内容
|
||||
* @return 匹配节点列表
|
||||
*/
|
||||
static List<Node> parse(String data) {
|
||||
List<Node> result = new ArrayList<>();
|
||||
|
||||
Regex[] regexes = Regex.values();
|
||||
|
||||
Map<String, Node> nodeMap = new HashMap<>();
|
||||
|
||||
int[] insertI = {0};
|
||||
String value = data;
|
||||
Matcher matcher;
|
||||
for (int i = 0; i < regexes.length; i++) {
|
||||
final int j = i;
|
||||
matcher = regexes[i].pattern.matcher(value);
|
||||
|
||||
value = matcher.replaceAll(matchResult -> {
|
||||
if (matchResult.start() - 1 != -1) {
|
||||
if (data.charAt(matchResult.start() - 1) == '\\') {
|
||||
return matchResult.group();
|
||||
}
|
||||
}
|
||||
nodeMap.put(String.valueOf(insertI[0]), node(regexes[j], value(regexes[j], matchResult.group())));
|
||||
return "[" + insertI[0]++ + "]";
|
||||
});
|
||||
}
|
||||
|
||||
// 二次解析
|
||||
matcher = Pattern.compile("\\[(.*?)]").matcher(value);
|
||||
int end = 0;
|
||||
while (matcher.find()) {
|
||||
if (matcher.start() - 1 != -1) {
|
||||
if (data.charAt(matcher.start() - 1) == '\\') {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (end != matcher.start()) {
|
||||
result.add(new Text(value.substring(end, matcher.start())));
|
||||
}
|
||||
result.add(nodeMap.get(value(Regex.LINK, matcher.group())));
|
||||
end = matcher.end();
|
||||
}
|
||||
result.add(new Text(value.substring(end)));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析正则匹配值
|
||||
*
|
||||
* @param regex 匹配正则
|
||||
* @param matcherResult 匹配结果
|
||||
* @return 匹配值
|
||||
*/
|
||||
private static String value(Regex regex, String matcherResult) {
|
||||
return switch (regex) {
|
||||
case LINK, ICON, SPAN -> matcherResult.substring(1, matcherResult.length() - 1);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析节点
|
||||
*
|
||||
* @param regex 匹配正则
|
||||
* @param value 匹配值
|
||||
* @return 节点
|
||||
*/
|
||||
private static Node node(Regex regex, String value) {
|
||||
return switch (regex) {
|
||||
// 超链
|
||||
case LINK -> {
|
||||
int sp = value.indexOf(",");
|
||||
if (sp == -1) {
|
||||
yield new XHyperlink(value.trim());
|
||||
} else {
|
||||
while (value.charAt(sp - 1) == '\\') {
|
||||
sp = value.indexOf(",", sp + 1);
|
||||
}
|
||||
yield new XHyperlink(value.substring(0, sp).trim(), value.substring(sp + 1).trim());
|
||||
}
|
||||
}
|
||||
// 图标
|
||||
case ICON -> {
|
||||
Text icon;
|
||||
int sp = value.lastIndexOf(",");
|
||||
if (sp == -1) {
|
||||
icon = TimiFXIcon.fromName(value);
|
||||
} else {
|
||||
icon = TimiFXIcon.fromName(value.substring(sp + 1).trim());
|
||||
icon.setFill(Paint.valueOf(value.substring(0, sp).trim()));
|
||||
}
|
||||
yield icon;
|
||||
}
|
||||
// 重点内容
|
||||
case SPAN -> {
|
||||
int sp = value.indexOf(",");
|
||||
if (sp == -1) {
|
||||
yield new Text(value);
|
||||
} else {
|
||||
Text text = new Text(value.substring(sp + 1).trim());
|
||||
String[] styles = value.substring(0, sp).trim().split(" ");
|
||||
for (String s : styles) {
|
||||
Style style = Style.fromMatcher(s);
|
||||
if (style == null) {
|
||||
text.setFill(Paint.valueOf(s));
|
||||
} else {
|
||||
if (style == Style.UNDERLINE) {
|
||||
text.setUnderline(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
yield text;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user