阻止在 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.geometry.Rectangle2D;
|
||||||
import javafx.scene.Scene;
|
import javafx.scene.Scene;
|
||||||
import javafx.scene.control.Tab;
|
import javafx.scene.control.Tab;
|
||||||
|
import javafx.scene.control.TextFormatter;
|
||||||
import javafx.scene.input.KeyEvent;
|
import javafx.scene.input.KeyEvent;
|
||||||
import javafx.scene.layout.*;
|
import javafx.scene.layout.*;
|
||||||
import javafx.scene.paint.Color;
|
import javafx.scene.paint.Color;
|
||||||
import javafx.stage.*;
|
import javafx.stage.*;
|
||||||
import javafx.util.Duration;
|
import javafx.util.Duration;
|
||||||
import org.jackhuang.hmcl.setting.StyleSheets;
|
import org.jackhuang.hmcl.setting.StyleSheets;
|
||||||
|
import org.jackhuang.hmcl.util.StringUtils;
|
||||||
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Shadi Shaheen
|
* @author Shadi Shaheen
|
||||||
@@ -95,14 +98,17 @@ public class JFXCustomColorPickerDialog extends StackPane {
|
|||||||
|
|
||||||
rgbField.getStyleClass().add("custom-color-field");
|
rgbField.getStyleClass().add("custom-color-field");
|
||||||
rgbField.setPromptText("RGB Color");
|
rgbField.setPromptText("RGB Color");
|
||||||
|
rgbField.setTextFormatter(colorCharFormatter());
|
||||||
rgbField.textProperty().addListener((o, oldVal, newVal) -> updateColorFromUserInput(newVal));
|
rgbField.textProperty().addListener((o, oldVal, newVal) -> updateColorFromUserInput(newVal));
|
||||||
|
|
||||||
hsbField.getStyleClass().add("custom-color-field");
|
hsbField.getStyleClass().add("custom-color-field");
|
||||||
hsbField.setPromptText("HSB Color");
|
hsbField.setPromptText("HSB Color");
|
||||||
|
hsbField.setTextFormatter(colorCharFormatter());
|
||||||
hsbField.textProperty().addListener((o, oldVal, newVal) -> updateColorFromUserInput(newVal));
|
hsbField.textProperty().addListener((o, oldVal, newVal) -> updateColorFromUserInput(newVal));
|
||||||
|
|
||||||
hexField.getStyleClass().add("custom-color-field");
|
hexField.getStyleClass().add("custom-color-field");
|
||||||
hexField.setPromptText("#HEX Color");
|
hexField.setPromptText("#HEX Color");
|
||||||
|
hexField.setTextFormatter(colorCharFormatter());
|
||||||
hexField.textProperty().addListener((o, oldVal, newVal) -> updateColorFromUserInput(newVal));
|
hexField.textProperty().addListener((o, oldVal, newVal) -> updateColorFromUserInput(newVal));
|
||||||
|
|
||||||
StackPane tabContent = new StackPane();
|
StackPane tabContent = new StackPane();
|
||||||
@@ -404,4 +410,20 @@ public class JFXCustomColorPickerDialog extends StackPane {
|
|||||||
dialog.setMinWidth(minWidth);
|
dialog.setMinWidth(minWidth);
|
||||||
dialog.setMinHeight(minHeight);
|
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;
|
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) {
|
private static boolean isVarNameStart(char ch) {
|
||||||
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_';
|
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_';
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user