Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.jfoenix.skins.PromptLinesWrapper Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.jfoenix.skins;
import com.jfoenix.controls.base.IFXLabelFloatControl;
import com.jfoenix.transitions.JFXAnimationTimer;
import com.jfoenix.transitions.JFXKeyFrame;
import com.jfoenix.transitions.JFXKeyValue;
import javafx.animation.Interpolator;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Control;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.Border;
import javafx.scene.layout.BorderStroke;
import javafx.scene.layout.BorderStrokeStyle;
import javafx.scene.layout.BorderWidths;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.paint.Paint;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.scene.transform.Scale;
import javafx.util.Duration;
import java.util.function.Supplier;
/**
* this class used to create label-float/focus-lines for all {@link IFXLabelFloatControl}
*
* @author Shadi Shaheen
* @version 1.0
* @since 2018-07-19
*/
public class PromptLinesWrapper {
private final Supplier promptTextSupplier;
private T control;
public StackPane line = new StackPane();
public StackPane focusedLine = new StackPane();
public StackPane promptContainer = new StackPane();
private JFXAnimationTimer focusTimer;
private JFXAnimationTimer unfocusTimer;
private double initScale = 0.05;
public final Scale promptTextScale = new Scale(1, 1, 0, 0);
private final Scale scale = new Scale(initScale, 1);
public final Rectangle clip = new Rectangle();
public ObjectProperty animatedPromptTextFill;
public BooleanBinding usePromptText;
ObjectProperty promptTextFill;
ObservableValue valueProperty;
ObservableValue promptTextProperty;
private boolean animating = false;
private double contentHeight = 0;
public PromptLinesWrapper(T control, ObjectProperty promptTextFill,
ObservableValue valueProperty,
ObservableValue promptTextProperty,
Supplier promptTextSupplier) {
this.control = control;
this.promptTextSupplier = promptTextSupplier;
this.promptTextFill = promptTextFill;
this.valueProperty = valueProperty;
this.promptTextProperty = promptTextProperty;
}
public void init(Runnable createPromptNodeRunnable, Node... cachedNodes) {
animatedPromptTextFill = new SimpleObjectProperty<>(promptTextFill.get());
usePromptText = Bindings.createBooleanBinding(this::usePromptText,
valueProperty,
promptTextProperty,
control.labelFloatProperty(),
promptTextFill);
// draw lines
line.setManaged(false);
line.getStyleClass().add("input-line");
line.setBackground(new Background(
new BackgroundFill(control.getUnFocusColor(), CornerRadii.EMPTY, Insets.EMPTY)));
// focused line
focusedLine.setManaged(false);
focusedLine.getStyleClass().add("input-focused-line");
focusedLine.setBackground(new Background(
new BackgroundFill(control.getFocusColor(), CornerRadii.EMPTY, Insets.EMPTY)));
focusedLine.setOpacity(0);
focusedLine.getTransforms().add(scale);
if (usePromptText.get()) {
createPromptNodeRunnable.run();
}
usePromptText.addListener(observable -> {
createPromptNodeRunnable.run();
control.requestLayout();
});
focusTimer = new JFXAnimationTimer(
new JFXKeyFrame(Duration.millis(1),
JFXKeyValue.builder()
.setTarget(focusedLine.opacityProperty())
.setEndValue(1)
.setInterpolator(Interpolator.EASE_BOTH)
.setAnimateCondition(() -> control.isFocused()).build()),
new JFXKeyFrame(Duration.millis(160),
JFXKeyValue.builder()
.setTarget(scale.xProperty())
.setEndValue(1)
.setInterpolator(Interpolator.EASE_BOTH)
.setAnimateCondition(() -> control.isFocused()).build(),
JFXKeyValue.builder()
.setTarget(animatedPromptTextFill)
.setEndValueSupplier(() -> control.getFocusColor())
.setInterpolator(Interpolator.EASE_BOTH)
.setAnimateCondition(() -> control.isFocused() && control.isLabelFloat()).build(),
JFXKeyValue.builder()
.setTargetSupplier(() -> promptTextSupplier.get() == null ? null : promptTextSupplier.get().translateYProperty())
.setEndValueSupplier(() -> -contentHeight)
.setAnimateCondition(() -> control.isLabelFloat())
.setInterpolator(Interpolator.EASE_BOTH).build(),
JFXKeyValue.builder()
.setTarget(promptTextScale.xProperty())
.setEndValue(0.85)
.setAnimateCondition(() -> control.isLabelFloat())
.setInterpolator(Interpolator.EASE_BOTH).build(),
JFXKeyValue.builder()
.setTarget(promptTextScale.yProperty())
.setEndValue(0.85)
.setAnimateCondition(() -> control.isLabelFloat())
.setInterpolator(Interpolator.EASE_BOTH).build())
);
unfocusTimer = new JFXAnimationTimer(
new JFXKeyFrame(Duration.millis(160),
JFXKeyValue.builder()
.setTargetSupplier(() -> promptTextSupplier.get() == null ? null : promptTextSupplier.get().translateYProperty())
.setEndValue(0)
.setInterpolator(Interpolator.EASE_BOTH).build(),
JFXKeyValue.builder()
.setTarget(promptTextScale.xProperty())
.setEndValue(1)
.setInterpolator(Interpolator.EASE_BOTH).build(),
JFXKeyValue.builder()
.setTarget(promptTextScale.yProperty())
.setEndValue(1)
.setInterpolator(Interpolator.EASE_BOTH).build())
);
promptContainer.setManaged(false);
promptContainer.setMouseTransparent(true);
// clip prompt container
clip.setSmooth(false);
clip.setX(0);
clip.widthProperty().bind(promptContainer.widthProperty());
promptContainer.setClip(clip);
focusTimer.setOnFinished(() -> animating = false);
unfocusTimer.setOnFinished(() -> animating = false);
focusTimer.setCacheNodes(cachedNodes);
unfocusTimer.setCacheNodes(cachedNodes);
// handle animation on focus gained/lost event
control.focusedProperty().addListener(observable -> {
if (control.isFocused()) {
focus();
} else {
unFocus();
}
});
promptTextFill.addListener(observable -> {
if (!control.isLabelFloat() || (control.isLabelFloat() && !control.isFocused())) {
animatedPromptTextFill.set(promptTextFill.get());
}
});
updateDisabled();
}
private void focus() {
unfocusTimer.stop();
animating = true;
runTimer(focusTimer, true);
}
private void unFocus() {
focusTimer.stop();
scale.setX(initScale);
focusedLine.setOpacity(0);
if (control.isLabelFloat()) {
animatedPromptTextFill.set(promptTextFill.get());
Object text = valueProperty.getValue();
text = validateComboBox(text);
if (text == null || text.toString().isEmpty()) {
animating = true;
runTimer(unfocusTimer, true);
}
}
}
public void updateFocusColor() {
Paint paint = control.getFocusColor();
focusedLine.setBackground(paint == null ? Background.EMPTY
: new Background(new BackgroundFill(paint, CornerRadii.EMPTY, Insets.EMPTY)));
}
public void updateUnfocusColor() {
Paint paint = control.getUnFocusColor();
line.setBackground(paint == null ? Background.EMPTY
: new Background(new BackgroundFill(paint, CornerRadii.EMPTY, Insets.EMPTY)));
}
private void updateLabelFloat(boolean animation) {
if (control.isLabelFloat()) {
if (control.isFocused()) {
animateFloatingLabel(true, animation);
} else {
Object text = valueProperty.getValue();
text = validateComboBox(text);
animateFloatingLabel(!(text == null || text.toString().isEmpty()), animation);
}
}
}
private Object validateComboBox(Object text) {
if (control instanceof ComboBox && ((ComboBox) control).isEditable()) {
final String editorText = ((ComboBox) control).getEditor().getText();
text = editorText == null || editorText.isEmpty() ? null : text;
}
return text;
}
/**
* this method is called when the text property is changed when the
* field is not focused (changed in code)
*
* @param up
*/
private void animateFloatingLabel(boolean up, boolean animation) {
if (promptTextSupplier.get() == null) {
return;
}
if (up) {
if (promptTextSupplier.get().getTranslateY() != -contentHeight) {
unfocusTimer.stop();
runTimer(focusTimer, animation);
}
} else {
if (promptTextSupplier.get().getTranslateY() != 0) {
focusTimer.stop();
runTimer(unfocusTimer, animation);
}
}
}
private void runTimer(JFXAnimationTimer timer, boolean animation) {
if (animation) {
if (!timer.isRunning()) {
timer.start();
}
} else {
timer.applyEndValues();
}
}
private boolean usePromptText() {
Object txt = valueProperty.getValue();
txt = validateComboBox(txt);
String promptTxt = promptTextProperty.getValue();
boolean isLabelFloat = control.isLabelFloat();
return isLabelFloat || (promptTxt != null
&& (txt == null || txt.toString().isEmpty())
&& !promptTxt.isEmpty()
&& !promptTextFill.get().equals(Color.TRANSPARENT));
}
public void layoutLines(double x, double y, double w, double h, double controlHeight, double translateY) {
this.contentHeight = translateY;
clip.setY(-contentHeight);
clip.setHeight(controlHeight + contentHeight);
focusedLine.resizeRelocate(x, controlHeight, w, focusedLine.prefHeight(-1));
line.resizeRelocate(x, controlHeight, w, line.prefHeight(-1));
promptContainer.resizeRelocate(x, y, w, h);
scale.setPivotX(w / 2);
}
public void updateLabelFloatLayout() {
if (!animating) {
updateLabelFloat(false);
}
}
public void invalid() {
if (control.isFocused()) {
focus();
}
}
public void updateDisabled() {
final boolean disabled = control.isDisable();
line.setBorder(!disabled ? Border.EMPTY :
new Border(new BorderStroke(control.getUnFocusColor(),
BorderStrokeStyle.DASHED, CornerRadii.EMPTY, new BorderWidths(1))));
line.setBackground(new Background(
new BackgroundFill(disabled ? Color.TRANSPARENT : control.getUnFocusColor(), CornerRadii.EMPTY, Insets.EMPTY)));
}
}