阻止在 JFXCustomColorPickerDialog 输入非法颜色信息 (#5368)
Co-authored-by: Glavo <zjx001202@gmail.com>
This commit is contained in:
@@ -34,14 +34,17 @@ import javafx.geometry.Insets;
|
||||
import javafx.geometry.Rectangle2D;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Tab;
|
||||
import javafx.scene.control.TextFormatter;
|
||||
import javafx.scene.input.KeyEvent;
|
||||
import javafx.scene.layout.*;
|
||||
import javafx.scene.paint.Color;
|
||||
import javafx.stage.*;
|
||||
import javafx.util.Duration;
|
||||
import org.jackhuang.hmcl.setting.StyleSheets;
|
||||
import org.jackhuang.hmcl.util.StringUtils;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* @author Shadi Shaheen
|
||||
@@ -95,14 +98,17 @@ public class JFXCustomColorPickerDialog extends StackPane {
|
||||
|
||||
rgbField.getStyleClass().add("custom-color-field");
|
||||
rgbField.setPromptText("RGB Color");
|
||||
rgbField.setTextFormatter(colorCharFormatter());
|
||||
rgbField.textProperty().addListener((o, oldVal, newVal) -> updateColorFromUserInput(newVal));
|
||||
|
||||
hsbField.getStyleClass().add("custom-color-field");
|
||||
hsbField.setPromptText("HSB Color");
|
||||
hsbField.setTextFormatter(colorCharFormatter());
|
||||
hsbField.textProperty().addListener((o, oldVal, newVal) -> updateColorFromUserInput(newVal));
|
||||
|
||||
hexField.getStyleClass().add("custom-color-field");
|
||||
hexField.setPromptText("#HEX Color");
|
||||
hexField.setTextFormatter(colorCharFormatter());
|
||||
hexField.textProperty().addListener((o, oldVal, newVal) -> updateColorFromUserInput(newVal));
|
||||
|
||||
StackPane tabContent = new StackPane();
|
||||
@@ -404,4 +410,20 @@ public class JFXCustomColorPickerDialog extends StackPane {
|
||||
dialog.setMinWidth(minWidth);
|
||||
dialog.setMinHeight(minHeight);
|
||||
}
|
||||
|
||||
private static final Pattern COLOR_CHAR_PATTERN = Pattern.compile("[0-9a-zA-Z#(),%.\\s]*");
|
||||
|
||||
private static TextFormatter<String> colorCharFormatter() {
|
||||
return new TextFormatter<>(change -> {
|
||||
if (!change.isContentChange()) return change;
|
||||
|
||||
String ins = StringUtils.toHalfWidth(change.getText());
|
||||
if (!COLOR_CHAR_PATTERN.matcher(ins).matches()) return null;
|
||||
String full = StringUtils.toHalfWidth(change.getControlNewText());
|
||||
long h = full.chars().filter(c -> c == '#').count();
|
||||
if (h > 1 || (h == 1 && full.indexOf('#') != 0)) return null;
|
||||
change.setText(ins);
|
||||
return change;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,6 +276,58 @@ public final class StringUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Check if the code point is a full-width character.
|
||||
public static boolean isFullWidth(int codePoint) {
|
||||
return codePoint >= '\uff10' && codePoint <= '\uff19' // full-width digits
|
||||
|| codePoint >= '\uff21' && codePoint <= '\uff3a' // full-width uppercase letters
|
||||
|| codePoint >= '\uff41' && codePoint <= '\uff5a' // full-width lowercase letters
|
||||
|| codePoint == '\uff08' // full-width left parenthesis
|
||||
|| codePoint == '\uff09' // full-width right parenthesis
|
||||
|| codePoint == '\uff0c' // full-width comma
|
||||
|| codePoint == '\uff05' // full-width percent sign
|
||||
|| codePoint == '\uff0e' // full-width period
|
||||
|| codePoint == '\u3000' // full-width ideographic space
|
||||
|| codePoint == '\uff03'; // full-width number sign
|
||||
}
|
||||
|
||||
/// Convert full-width characters to half-width characters.
|
||||
public static String toHalfWidth(String str) {
|
||||
int i = 0;
|
||||
while (i < str.length()) {
|
||||
int cp = str.codePointAt(i);
|
||||
|
||||
if (isFullWidth(cp)) {
|
||||
break;
|
||||
}
|
||||
|
||||
i += Character.charCount(cp);
|
||||
}
|
||||
|
||||
if (i == str.length())
|
||||
return str;
|
||||
|
||||
var builder = new StringBuilder(str.length());
|
||||
builder.append(str, 0, i);
|
||||
while (i < str.length()) {
|
||||
int c = str.codePointAt(i);
|
||||
|
||||
if (c >= '\uff10' && c <= '\uff19') builder.append((char) (c - 0xfee0));
|
||||
else if (c >= '\uff21' && c <= '\uff3a') builder.append((char) (c - 0xfee0));
|
||||
else if (c >= '\uff41' && c <= '\uff5a') builder.append((char) (c - 0xfee0));
|
||||
else if (c == '\uff08') builder.append('(');
|
||||
else if (c == '\uff09') builder.append(')');
|
||||
else if (c == '\uff0c') builder.append(',');
|
||||
else if (c == '\uff05') builder.append('%');
|
||||
else if (c == '\uff0e') builder.append('.');
|
||||
else if (c == '\u3000') builder.append(' ');
|
||||
else if (c == '\uff03') builder.append('#');
|
||||
else builder.appendCodePoint(c);
|
||||
|
||||
i += Character.charCount(c);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private static boolean isVarNameStart(char ch) {
|
||||
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user