Skip to content

Commit

Permalink
Merge pull request #185 from dlsc-software-consulting-gmbh/enhancment…
Browse files Browse the repository at this point in the history
…-password-field

Update EnhancedPasswordField functionality and styling
  • Loading branch information
dlemmermann authored Jun 10, 2024
2 parents d004774 + 9285159 commit b978584
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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);

Expand Down
53 changes: 23 additions & 30 deletions gemsfx/src/main/java/com/dlsc/gemsfx/EnhancedPasswordField.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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.
* <p>
* 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
Expand Down
27 changes: 23 additions & 4 deletions gemsfx/src/main/java/com/dlsc/gemsfx/util/UIUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -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<Boolean> booleanObservableValue) {
Expand Down Expand Up @@ -194,13 +194,12 @@ public static void copyToClipboard(String copyContent) {
}

/**
* Determines if the given mouse event is a single primary button click
* Determines if the given mouse event is a primary button click
* that hasn't moved since it was pressed.
*
* <p>This method checks if the mouse event satisfies the following conditions:
* <ul>
* <li>The mouse button is the primary button (usually the left button).</li>
* <li>The click count is exactly one.</li>
* <li>The mouse has not moved since it was pressed.</li>
* </ul>
*
Expand All @@ -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.
*
* <p>This method checks if the mouse event satisfies the following conditions:
* <ul>
* <li>The mouse button is the primary button (usually the left button).</li>
* <li>The mouse has not moved since it was pressed.</li>
* <li>If {@code isSingleClick} is {@code true}, the event must be a single click.</li>
* </ul>
*
* @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);
}

}
Original file line number Diff line number Diff line change
@@ -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;
}

0 comments on commit b978584

Please sign in to comment.