diff --git a/gemsfx-demo/src/main/java/com/dlsc/gemsfx/demo/EnhancedPasswordFieldApp.java b/gemsfx-demo/src/main/java/com/dlsc/gemsfx/demo/EnhancedPasswordFieldApp.java index 43a164e8..4e1faee1 100644 --- a/gemsfx-demo/src/main/java/com/dlsc/gemsfx/demo/EnhancedPasswordFieldApp.java +++ b/gemsfx-demo/src/main/java/com/dlsc/gemsfx/demo/EnhancedPasswordFieldApp.java @@ -20,7 +20,7 @@ public class EnhancedPasswordFieldApp extends Application { @Override public void start(Stage primaryStage) throws Exception { - EnhancedPasswordField passwordField1 = EnhancedPasswordField.createSimplePasswordField(); + EnhancedPasswordField passwordField1 = new EnhancedPasswordField(); passwordField1.setPromptText("Enter your password"); passwordField1.setEchoChar('★'); passwordField1.setText("1234567890"); @@ -38,7 +38,7 @@ public void start(Stage primaryStage) throws Exception { passwordField2.setLeft(createIconNode(MaterialDesign.MDI_KEY)); passwordField2.setStyle("-fx-echo-char: '■';"); - EnhancedPasswordField passwordField3 = EnhancedPasswordField.createSimplePasswordField(); + EnhancedPasswordField passwordField3 = new EnhancedPasswordField(); passwordField3.setText("1234567890"); passwordField3.setShowPassword(true); diff --git a/gemsfx/src/main/java/com/dlsc/gemsfx/EnhancedPasswordField.java b/gemsfx/src/main/java/com/dlsc/gemsfx/EnhancedPasswordField.java index 1fb90e35..2d2f2cb7 100644 --- a/gemsfx/src/main/java/com/dlsc/gemsfx/EnhancedPasswordField.java +++ b/gemsfx/src/main/java/com/dlsc/gemsfx/EnhancedPasswordField.java @@ -2,21 +2,22 @@ import com.dlsc.gemsfx.skins.EnhancedPasswordFieldSkin; import com.dlsc.gemsfx.util.EchoCharConverter; +import com.dlsc.gemsfx.util.UIUtil; import javafx.beans.property.BooleanProperty; import javafx.beans.property.ObjectProperty; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.css.CssMetaData; +import javafx.css.PseudoClass; import javafx.css.Styleable; import javafx.css.StyleableObjectProperty; import javafx.css.StyleableProperty; import javafx.scene.Node; import javafx.scene.control.PasswordField; import javafx.scene.control.Skin; -import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.Region; import javafx.scene.layout.StackPane; -import org.kordamp.ikonli.javafx.FontIcon; -import org.kordamp.ikonli.materialdesign.MaterialDesign; import java.util.ArrayList; import java.util.Collections; @@ -54,45 +55,37 @@ public class EnhancedPasswordField extends PasswordField { public static final char DEFAULT_ECHO_CHAR = '●'; - private static final boolean DEFAULT_SHOW_PASSWORD = false; + private static final String DEFAULT_STYLE_CLASS = "enhanced-password-field"; + private static final boolean DEFAULT_SHOW_PASSWORD = false; + private static final PseudoClass SHOWING_PASSWORD_PSEUDO_CLASS = PseudoClass.getPseudoClass("showing-password"); + private final Logger LOG = Logger.getLogger(EnhancedPasswordField.class.getName()); public EnhancedPasswordField() { super(); getStyleClass().add(DEFAULT_STYLE_CLASS); - } - - public EnhancedPasswordField(String text) { - this(); - setText(text); - } - /** - * Creates a simple password field with an eye icon on the right side. - *
- * This method creates a simple password field with an eye icon on the right side. The eye icon
- * can be clicked to toggle the visibility of the password.
- *
- * @return a simple password field with an eye icon on the right side
- */
- public static EnhancedPasswordField createSimplePasswordField() {
- EnhancedPasswordField passwordField = new EnhancedPasswordField();
+ showPasswordProperty().subscribe(showing -> pseudoClassStateChanged(SHOWING_PASSWORD_PSEUDO_CLASS, showing));
//set right node
- FontIcon fontIcon = new FontIcon();
- fontIcon.iconCodeProperty().bind(passwordField.showPasswordProperty().map(it -> it ? MaterialDesign.MDI_EYE : MaterialDesign.MDI_EYE_OFF));
-
- StackPane right = new StackPane(fontIcon);
- right.getStyleClass().add("right-icon-wrapper");
- right.setOnMouseClicked(event -> {
- if (event.getButton() == MouseButton.PRIMARY) {
- passwordField.setShowPassword(!passwordField.isShowPassword());
+ Region rightIcon = new Region();
+ rightIcon.getStyleClass().add("right-icon");
+
+ StackPane rightWrapper = new StackPane(rightIcon);
+ rightWrapper.getStyleClass().add("right-icon-wrapper");
+ rightWrapper.addEventHandler(MouseEvent.MOUSE_PRESSED, event -> {
+ if (UIUtil.clickOnNode(event)) {
+ setShowPassword(!isShowPassword());
+ event.consume();
}
});
+ setRight(rightWrapper);
+ }
- passwordField.setRight(right);
- return passwordField;
+ public EnhancedPasswordField(String text) {
+ this();
+ setText(text);
}
@Override
diff --git a/gemsfx/src/main/java/com/dlsc/gemsfx/util/UIUtil.java b/gemsfx/src/main/java/com/dlsc/gemsfx/util/UIUtil.java
index b9a43456..04d6345d 100644
--- a/gemsfx/src/main/java/com/dlsc/gemsfx/util/UIUtil.java
+++ b/gemsfx/src/main/java/com/dlsc/gemsfx/util/UIUtil.java
@@ -84,7 +84,7 @@ public static void toggleClassOnCondition(Styleable node, String styleClass, boo
* If the observable value is false, the style class is removed.
*
* @param node The node to toggle the style on.
- * @param styleClass The style class to add or remove.
+ * @param styleClass The style class to add or remove.
* @param booleanObservableValue The observable value that determines whether to add or remove the style.
*/
public static void toggleClassBasedOnObservable(Styleable node, String styleClass, ObservableValue This method checks if the mouse event satisfies the following conditions:
* This method checks if the mouse event satisfies the following conditions:
+ *
*
*
@@ -209,7 +208,27 @@ public static void copyToClipboard(String copyContent) {
* @throws NullPointerException if the event is null.
*/
public static boolean clickOnNode(MouseEvent event) {
- return event.getButton() == MouseButton.PRIMARY && event.getClickCount() == 1 && event.isStillSincePress();
+ return clickOnNode(event, false);
+ }
+
+ /**
+ * Determines if the given mouse event is a primary button click
+ * that hasn't moved since it was pressed.
+ *
+ *
+ *
+ *
+ * @param event The mouse event to check. Must not be null.
+ * @param isSingleClick {@code true} if the event must be a single click, {@code false} otherwise.
+ * @return {@code true} if the event is a stable primary button click, {@code false} otherwise.
+ * @throws NullPointerException if the event is null.
+ */
+ public static boolean clickOnNode(MouseEvent event, boolean isSingleClick) {
+ return event.getButton() == MouseButton.PRIMARY && event.isStillSincePress() && (!isSingleClick || event.getClickCount() == 1);
}
}
\ No newline at end of file
diff --git a/gemsfx/src/main/resources/com/dlsc/gemsfx/enhanced-password-field.css b/gemsfx/src/main/resources/com/dlsc/gemsfx/enhanced-password-field.css
index d4334daa..5a003e73 100644
--- a/gemsfx/src/main/resources/com/dlsc/gemsfx/enhanced-password-field.css
+++ b/gemsfx/src/main/resources/com/dlsc/gemsfx/enhanced-password-field.css
@@ -1,8 +1,16 @@
.enhanced-password-field .right-icon-wrapper {
- -fx-padding: 0 5px;
-fx-cursor: hand;
+ -fx-max-height: 1.25em;
+ -fx-min-width: 1.25em;
}
-.enhanced-password-field .right-icon-wrapper .ikonli-font-icon {
- -fx-icon-size: 15px;
+.enhanced-password-field .right-icon-wrapper .right-icon {
+ -fx-shape: "M12,9c-0.8,0-1.5,0.3-2.1,0.9C9.3,10.5,9,11.2,9,12s0.3,1.5,0.8,2.1c0.6,0.6,1.3,0.8,2.1,0.8c0.8,0,1.5-0.3,2.1-0.8 c0.6-0.6,0.8-1.3,0.8-2.1c0-0.8-0.3-1.5-0.8-2.1C13.5,9.3,12.8,9,12,9z M12,17c-1.4,0-2.6-0.5-3.5-1.5C7.5,14.6,7,13.4,7,12 c0-1.4,0.5-2.6,1.5-3.5c1-1,2.1-1.5,3.5-1.5c1.4,0,2.6,0.5,3.5,1.5c1,0.9,1.5,2.1,1.5,3.5c0,1.4-0.5,2.6-1.5,3.5 C14.6,16.5,13.4,17,12,17z M12,4.5c-2.5,0-4.8,0.7-6.7,2.1C3.3,8,1.9,9.8,1,12c0.9,2.2,2.3,4,4.3,5.4c2,1.4,4.2,2.1,6.7,2.1 c2.5,0,4.8-0.7,6.7-2.1c2-1.4,3.4-3.2,4.3-5.4c-0.9-2.2-2.3-4-4.3-5.4C16.8,5.2,14.5,4.5,12,4.5z";
+ -fx-max-height: 0.852em;
+ -fx-background-color: black;
+}
+
+.enhanced-password-field:showing-password .right-icon-wrapper .right-icon {
+ -fx-shape: "M11.8,8.5l3.2,3.1v-0.1c0-0.8-0.3-1.5-0.9-2.1c-0.6-0.6-1.3-0.9-2.1-0.9H11.8z M7.5,9.3l1.5,1.5C9,11.1,9,11.3,9,11.5 c0,0.8,0.3,1.5,0.9,2.1c0.6,0.6,1.3,0.9,2.1,0.9c0.2,0,0.4,0,0.7-0.1l1.5,1.5c-0.7,0.3-1.4,0.5-2.2,0.6c-1.4,0-2.6-0.5-3.5-1.5 c-0.9-1-1.4-2.1-1.5-3.5C7,10.7,7.2,10,7.5,9.3z M2,3.8l2.3,2.3l0.5,0.4c-1.7,1.3-2.9,3-3.8,5c0.9,2.2,2.3,4,4.3,5.4 c2,1.4,4.2,2.1,6.7,2.1c1.6,0,3-0.3,4.4-0.8l3.4,3.3l1.3-1.3L3.3,2.5L2,3.8z M12,6.5c1.4,0,2.6,0.5,3.5,1.5c1,0.9,1.5,2.1,1.5,3.5 c0,0.7-0.1,1.3-0.4,1.8l2.9,2.9c1.5-1.3,2.7-2.9,3.5-4.7c-0.9-2.2-2.3-4-4.3-5.4C16.8,4.7,14.5,4,12,4c-1.4,0-2.7,0.2-4,0.7 l2.2,2.2C10.7,6.6,11.3,6.5,12,6.5z";
+ -fx-max-height: 1.079em;
}
\ No newline at end of file