/*
* 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.JFXRippler;
import com.jfoenix.controls.JFXRippler.RipplerMask;
import com.jfoenix.controls.JFXRippler.RipplerPos;
import com.jfoenix.controls.JFXToggleButton;
import com.jfoenix.effects.JFXDepthManager;
import com.sun.javafx.scene.control.skin.ToggleButtonSkin;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.geometry.Insets;
import javafx.scene.Cursor;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.scene.shape.Line;
import javafx.scene.shape.StrokeLineCap;
import javafx.util.Duration;
/**
* <h1>Material Design ToggleButton Skin</h1>
*
* @author Shadi Shaheen
* @version 1.0
* @since 2016-03-09
*/
public class JFXToggleButtonSkin extends ToggleButtonSkin {
private Line line;
private Circle circle;
private final int circleRadius = 10;
private StackPane circleContainer = new StackPane();
private JFXRippler rippler;
private Timeline transition;
private Runnable releaseManualRippler = null;
public JFXToggleButtonSkin(JFXToggleButton toggleButton) {
super(toggleButton);
// hide the toggle button
toggleButton.setBackground(new Background(new BackgroundFill(Color.TRANSPARENT, null, null)));
final int startY = 0;
final int endX = 22;
final int startX = 0;
line = new Line(startX, startY, endX, startY);
line.setStroke(toggleButton.getUnToggleLineColor());
line.setStrokeWidth(14);
line.setStrokeLineCap(StrokeLineCap.ROUND);
circle = new Circle(startX - circleRadius, startY, circleRadius);
circle.setFill(toggleButton.getUnToggleColor());
circle.setSmooth(true);
JFXDepthManager.setDepth(circle, 1);
StackPane circlePane = new StackPane();
circlePane.getChildren().add(circle);
circlePane.setPadding(new Insets(14));
rippler = new JFXRippler(circlePane, RipplerMask.CIRCLE, RipplerPos.BACK) {
@Override
protected void initListeners() {
ripplerPane.setOnMousePressed((event) -> {
if (releaseManualRippler != null) {
releaseManualRippler.run();
}
releaseManualRippler = null;
createRipple(event.getX(), event.getY());
});
}
};
rippler.setRipplerFill(toggleButton.getUnToggleLineColor());
circleContainer.getChildren().add(rippler);
circleContainer.setTranslateX(-(line.getLayoutBounds().getWidth() / 2) + circleRadius);
final StackPane main = new StackPane();
main.getChildren().add(line);
main.getChildren().add(circleContainer);
main.setCursor(Cursor.HAND);
// show focus traversal effect
getSkinnable().armedProperty().addListener((o, oldVal, newVal) -> {
if (newVal) {
releaseManualRippler = rippler.createManualRipple();
} else if (releaseManualRippler != null) {
releaseManualRippler.run();
}
});
toggleButton.focusedProperty().addListener((o, oldVal, newVal) -> {
if (newVal) {
if (!getSkinnable().isPressed()) {
rippler.showOverlay();
}
} else {
rippler.hideOverlay();
}
});
toggleButton.pressedProperty().addListener((o, oldVal, newVal) -> rippler.hideOverlay());
// add change listener to selected property
getSkinnable().selectedProperty().addListener((o, oldVal, newVal) -> {
rippler.setRipplerFill(newVal ? toggleButton.getToggleColor() : toggleButton.getUnToggleLineColor());
transition.setRate(newVal ? 1 : -1);
transition.play();
});
getSkinnable().setGraphic(main);
updateToggleTransition();
toggleButton.toggleColorProperty().addListener((o, oldVal, newVal) -> {
updateToggleTransition();
udpateCricle();
});
toggleButton.unToggleColorProperty().addListener((o, oldVal, newVal) -> {
updateToggleTransition();
udpateCricle();
});
toggleButton.toggleLineColorProperty().addListener((o, oldVal, newVal) -> {
updateToggleTransition();
updateLine();
});
toggleButton.unToggleLineColorProperty().addListener((o, oldVal, newVal) -> {
updateToggleTransition();
updateLine();
});
// init selected state
rippler.setRipplerFill(getSkinnable().isSelected() ? toggleButton.getToggleColor() : toggleButton.getUnToggleLineColor());
if (getSkinnable().isSelected()) {
circleContainer.setTranslateX((line.getLayoutBounds().getWidth() / 2) - circleRadius);
line.setStroke(((JFXToggleButton) getSkinnable()).getToggleLineColor());
circle.setFill(((JFXToggleButton) getSkinnable()).getToggleColor());
}
}
private void udpateCricle() {
circle.setFill(getSkinnable().isSelected() ? ((JFXToggleButton) getSkinnable()).getToggleColor() : ((JFXToggleButton) getSkinnable())
.getUnToggleColor());
}
private void updateLine() {
line.setStroke(getSkinnable().isSelected() ? ((JFXToggleButton) getSkinnable()).getToggleLineColor() : ((JFXToggleButton) getSkinnable())
.getUnToggleLineColor());
}
private void updateToggleTransition() {
transition = new Timeline(
new KeyFrame(
Duration.ZERO,
new KeyValue(circleContainer.translateXProperty(),
-(line.getLayoutBounds().getWidth() / 2) + circleRadius,
Interpolator.EASE_BOTH),
new KeyValue(line.strokeProperty(),
((JFXToggleButton) getSkinnable()).getUnToggleLineColor(),
Interpolator.EASE_BOTH),
new KeyValue(circle.fillProperty(),
((JFXToggleButton) getSkinnable()).getUnToggleColor(),
Interpolator.EASE_BOTH)
),
new KeyFrame(
Duration.millis(100),
new KeyValue(circleContainer.translateXProperty(),
(line.getLayoutBounds().getWidth() / 2) - circleRadius,
Interpolator.EASE_BOTH),
new KeyValue(line.strokeProperty(),
((JFXToggleButton) getSkinnable()).getToggleLineColor(),
Interpolator.EASE_BOTH),
new KeyValue(circle.fillProperty(),
((JFXToggleButton) getSkinnable()).getToggleColor(),
Interpolator.EASE_BOTH)
)
);
}
}