/******************************************************************************* * Copyright (c) 2014, 2017 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: * Matthias Wienand (itemis AG) - initial API and implementation * *******************************************************************************/ package org.eclipse.gef.mvc.fx.behaviors; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.eclipse.gef.mvc.fx.models.HoverModel; import org.eclipse.gef.mvc.fx.parts.AbstractFeedbackPart; import org.eclipse.gef.mvc.fx.parts.AbstractHandlePart; import org.eclipse.gef.mvc.fx.parts.IFeedbackPart; import org.eclipse.gef.mvc.fx.parts.IFeedbackPartFactory; import org.eclipse.gef.mvc.fx.parts.IHandlePart; import org.eclipse.gef.mvc.fx.parts.IHandlePartFactory; import org.eclipse.gef.mvc.fx.parts.IVisualPart; import org.eclipse.gef.mvc.fx.viewer.IViewer; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.scene.Node; import javafx.scene.effect.DropShadow; import javafx.scene.effect.Effect; /** * The {@link HoverBehavior} can be registered on an {@link IVisualPart} in * order to react to {@link HoverModel} changes. It generates * {@link AbstractFeedbackPart}s and {@link AbstractHandlePart}s. * * @author mwienand * */ public class HoverBehavior extends AbstractBehavior { /** * The adapter role for the {@link IFeedbackPartFactory} that is used to * generate hover feedback parts. */ public static final String HOVER_FEEDBACK_PART_FACTORY = "HOVER_FEEDBACK_PART_FACTORY"; /** * The adapter role for the {@link IHandlePartFactory} that is used to * generate hover handle parts. */ public static final String HOVER_HANDLE_PART_FACTORY = "HOVER_HANDLE_PART_FACTORY"; private ChangeListener<IVisualPart<? extends Node>> hoverObserver = new ChangeListener<IVisualPart<? extends Node>>() { @Override public void changed( ObservableValue<? extends IVisualPart<? extends Node>> observable, IVisualPart<? extends Node> oldValue, IVisualPart<? extends Node> newValue) { onHoverChange(oldValue, newValue); } }; private final Map<IVisualPart<? extends Node>, Effect> effects = new HashMap<>(); @Override protected void doActivate() { // create feedback and handles if we are already hovered HoverModel hoverModel = getHoverModel(); IVisualPart<? extends Node> hover = hoverModel.getHover(); if (hover != null) { onHoverChange(null, hover); } // register HoverModel observer hoverModel.hoverProperty().addListener(hoverObserver); } @Override protected void doDeactivate() { // unregister HoverModel observer HoverModel hoverModel = getHoverModel(); hoverModel.hoverProperty().removeListener(hoverObserver); // remove any pending feedback and handles IVisualPart<? extends Node> hover = hoverModel.getHover(); if (hover != null) { onHoverChange(hover, null); } } @Override protected IFeedbackPartFactory getFeedbackPartFactory(IViewer viewer) { return getFeedbackPartFactory(viewer, HOVER_FEEDBACK_PART_FACTORY); } /** * Returns the {@link Effect} that is applied to {@link IHandlePart}s as a * replacement for {@link IFeedbackPart}s which are created for normal * parts. * * @param contextMap * A map with context information that might be needed to * identify the concrete creation context. * @return The {@link Effect} that is applied to {@link IHandlePart}s as a * replacement for {@link IFeedbackPart}s which are created for * normal parts. */ public Effect getHandleHoverFeedbackEffect(Map<Object, Object> contextMap) { DropShadow effect = new DropShadow(); effect.setRadius(5); return effect; } @Override protected IHandlePartFactory getHandlePartFactory(IViewer viewer) { return getHandlePartFactory(viewer, HOVER_HANDLE_PART_FACTORY); } /** * Returns the {@link HoverModel} in the context of the {@link #getHost() * host}. * * @return The {@link HoverModel} in the context of the {@link #getHost() * host}. */ protected HoverModel getHoverModel() { IViewer viewer = getHost().getRoot().getViewer(); HoverModel hoverModel = viewer.getAdapter(HoverModel.class); return hoverModel; } private void onHoverChange(IVisualPart<? extends Node> oldHovered, IVisualPart<? extends Node> newHovered) { if (oldHovered != null) { if (oldHovered instanceof IHandlePart) { // unhovering a handle part // remove feedback effect if (effects.containsKey(oldHovered)) { oldHovered.getVisual() .setEffect(effects.remove(oldHovered)); } else { throw new IllegalStateException( "Cannot unhover/restore effect <" + oldHovered + ">."); } } else { removeHandles(oldHovered); removeFeedback(oldHovered); } } if (newHovered != null) { if (newHovered instanceof IHandlePart) { // hovering a handle part // add feedback effect effects.put(newHovered, newHovered.getVisual().getEffect()); newHovered.getVisual().setEffect( getHandleHoverFeedbackEffect(Collections.emptyMap())); } else { addFeedback(newHovered); addHandles(newHovered); } } } }