/*******************************************************************************
* Copyright (c) 2014, 2015 itemis AG and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Alexander Nyßen (itemis AG) - initial API and implementation
* Matthias Wienand (itemis AG) - initial API and implementation
*
*******************************************************************************/
package org.eclipse.gef.fx.nodes;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.effect.BlendMode;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.util.Duration;
/**
* A {@link Group} that combines two {@link ImageView}s, realizing an overlay
* effect (by adjusting the respective opacities) upon mouse hover.
*
* @author anyssen
* @author mwienand
*
*/
// TODO: extract magic numbers to properties
public class HoverOverlayImageView extends Group {
private SimpleObjectProperty<Image> baseImageProperty = new SimpleObjectProperty<>();
private SimpleObjectProperty<Image> overlayImageProperty = new SimpleObjectProperty<>();
private ImageView baseImageView;
private ImageView overlayImageView;
/**
* Constructs a new {@link HoverOverlayImageView}.
*/
public HoverOverlayImageView() {
createImageViews();
registerHoverEffect();
registerPropertyListeners();
}
/**
* Returns the {@link SimpleObjectProperty} which stores the base
* {@link Image} of this {@link HoverOverlayImageView}.
*
* @return The {@link SimpleObjectProperty} which stores the base
* {@link Image} of this {@link HoverOverlayImageView}.
*/
public SimpleObjectProperty<Image> baseImageProperty() {
return baseImageProperty;
}
/**
* Creates the {@link ImageView}s for the base and overlay image. Sets the
* opacity of the overlay {@link ImageView} to <code>0%</code> and the
* opacity of the base {@link ImageView} to <code>80%</code>.
*/
protected void createImageViews() {
baseImageView = new ImageView();
overlayImageView = new ImageView();
getChildren().addAll(baseImageView, overlayImageView);
setBlendMode(BlendMode.SRC_OVER);
// hide hover image, and show normal image
overlayImageView.setOpacity(0);
baseImageView.setOpacity(0.8); // 20% transparent
}
/**
* Returns the {@link ImageView} which displays the base {@link Image}.
*
* @return The {@link ImageView} which displays the base {@link Image}.
*/
public ImageView getBaseImageView() {
return baseImageView;
}
/**
* Returns the {@link ImageView} which displays the overlay {@link Image}.
*
* @return The {@link ImageView} which displays the overlay {@link Image}.
*/
public ImageView getOverlayImageView() {
return overlayImageView;
}
/**
* Returns the {@link SimpleObjectProperty} which stores the overlay
* {@link Image} of this {@link HoverOverlayImageView}.
*
* @return The {@link SimpleObjectProperty} which stores the overlay
* {@link Image} of this {@link HoverOverlayImageView}.
*/
public SimpleObjectProperty<Image> overlayImageProperty() {
return overlayImageProperty;
}
/**
* Registers event listeners realizing the overlay effect on mouse hover.
*/
protected void registerHoverEffect() {
setOnMouseEntered(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
new Timeline(new KeyFrame(Duration.millis(150),
new KeyValue(baseImageView.opacityProperty(), 0),
new KeyValue(overlayImageView.opacityProperty(), 1)))
.play();
}
});
setOnMouseExited(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent event) {
new Timeline(new KeyFrame(Duration.millis(150),
new KeyValue(baseImageView.opacityProperty(), 0.8),
new KeyValue(overlayImageView.opacityProperty(), 0)))
.play();
}
});
}
/**
* Registers property listeners for updating the {@link ImageView} s.
*/
protected void registerPropertyListeners() {
baseImageProperty.addListener(new ChangeListener<Image>() {
@Override
public void changed(ObservableValue<? extends Image> observable,
Image oldImage, Image newImage) {
setImage(baseImageView, newImage);
}
});
overlayImageProperty.addListener(new ChangeListener<Image>() {
@Override
public void changed(ObservableValue<? extends Image> observable,
Image oldImage, Image newImage) {
setImage(overlayImageView, newImage);
}
});
}
private void setImage(ImageView imageView, Image image) {
imageView.setImage(image);
// translate to center
imageView.setTranslateX(-image.getWidth() / 2);
imageView.setTranslateY(-image.getHeight() / 2);
}
}