/******************************************************************************* * Copyright (c) 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.ui.actions; import org.eclipse.gef.fx.nodes.InfiniteCanvas; import org.eclipse.gef.mvc.fx.viewer.IViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.CoolBar; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Scale; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.ToolItem; import javafx.beans.value.ChangeListener; import javafx.scene.Parent; /** * The {@link ZoomScaleContributionItem} is an * {@link AbstractViewerContributionItem} that contributes a zoom {@link Scale} * to the tool bar. The zoom scale can be used to set the zoom factor by * dragging its thumb. Per default, the minimal zoom factor is * <code>3.125%</code> * * @author mwienand * */ public class ZoomScaleContributionItem extends AbstractViewerContributionItem { /** * The ID (see {@link #setId(String)}) for this * {@link ZoomScaleContributionItem}. */ public static final String ZOOM_SCALE_CONTRIBUTION_ITEM_ID = "ZoomScaleContributionItem"; private static final int SCALE_MINIMUM = 1; // 0.03125 zoom private static final int SCALE_MAXIMUM = 10000; // 32.0 zoom private static final double SCALE_TO_ZOOM_COEFF_BASE = 0.0312283;// 0.474357; private static final double SCALE_TO_ZOOM_COEFF_EXPO = 0.000693217; // 0.000421363; private static final double ZOOM_TO_SCALE_COEFF_BASE = 1442.55; // 2373.25; private static final double ZOOM_TO_SCALE_COEFF_EXPO = 32.0222; // 2.10812; // controls private ToolItem toolItem; private Scale zoomScale; // listeners private ChangeListener<? super Number> zoomListener; // zoom action private AbstractZoomAction zoomAction = createZoomAction(); /** * Constructs a new {@link ZoomScaleContributionItem}. */ public ZoomScaleContributionItem() { setId(ZOOM_SCALE_CONTRIBUTION_ITEM_ID); } /** * Returns the scale value that corresponds to the given zoom factor. * * @param zoomFactor * The zoom factor that is converted. * @return The corresponding scale value. */ protected int computeScaleValue(double zoomFactor) { return (int) Math.round(ZOOM_TO_SCALE_COEFF_BASE * Math.log(ZOOM_TO_SCALE_COEFF_EXPO * zoomFactor)); } /** * Returns the zoom factor that corresponds to the given scale value. * * @param scaleValue * The scale value that is converted. * @return The corresponding zoom factor. */ protected double computeZoomFactor(int scaleValue) { return SCALE_TO_ZOOM_COEFF_BASE * Math.pow(Math.E, SCALE_TO_ZOOM_COEFF_EXPO * scaleValue); } /** * Returns an {@link AbstractZoomAction} that is used to carry out zooming. * The zoom factor is passed on to the action using the {@link Event#data} * field of the {@link Event} that is given to * {@link AbstractZoomAction#determineZoomFactor(double, Event)}. * * @return The {@link AbstractZoomAction} that is used to carry out zooming. */ protected AbstractZoomAction createZoomAction() { return new AbstractZoomAction("Zoom") { @Override protected double determineZoomFactor(double currentZoomFactor, Event event) { return ((double) event.data) * 1d / currentZoomFactor; } }; } @Override public void dispose() { if (getViewer() != null) { init(null); } if (toolItem != null && !toolItem.isDisposed()) { toolItem.dispose(); } } @Override public void fill(Composite parent) { throw new UnsupportedOperationException(); } @Override public void fill(CoolBar parent, int index) { throw new UnsupportedOperationException(); } @Override public void fill(Menu menu, int index) { throw new UnsupportedOperationException(); } @Override public void fill(ToolBar tb, int index) { toolItem = new ToolItem(tb, SWT.SEPARATOR, index); zoomScale = new Scale(tb, SWT.HORIZONTAL); zoomScale.setMinimum(SCALE_MINIMUM); zoomScale.setMaximum(SCALE_MAXIMUM); zoomScale.setSelection(SCALE_MAXIMUM / 2 + SCALE_MINIMUM / 2); zoomScale.setSize(75, 100); toolItem.setWidth(zoomScale.getSize().x); toolItem.setControl(zoomScale); zoomScale.addSelectionListener(new SelectionListener() { @Override public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } @Override public void widgetSelected(SelectionEvent e) { int sel = zoomScale.getSelection(); double zoom = computeZoomFactor(sel); if (zoom > 0) { Event event = new Event(); event.data = zoom; zoomAction.runWithEvent(event); } else { throw new IllegalStateException("Illegal zoom factor."); } } }); if (isEnabled()) { double mxx = ((InfiniteCanvas) getViewer().getCanvas()) .getContentTransform().getMxx(); updateScaleValue(mxx); } } @Override public void init(IViewer viewer) { super.init(viewer); zoomAction.init(viewer); } @Override protected void register() { if (zoomListener != null) { throw new IllegalStateException( "Zoom listener is already registered."); } Parent canvas = getViewer().getCanvas(); if (canvas instanceof InfiniteCanvas) { InfiniteCanvas infiniteCanvas = (InfiniteCanvas) canvas; zoomListener = (a, o, n) -> { updateScaleValue(n.doubleValue()); }; infiniteCanvas.getContentTransform().mxxProperty() .addListener(zoomListener); updateScaleValue(infiniteCanvas.getContentTransform().getMxx()); } } @Override protected void unregister() { if (zoomListener == null) { throw new IllegalStateException( "Zoom listener not yet registered."); } Parent canvas = getViewer().getCanvas(); if (canvas instanceof InfiniteCanvas) { ((InfiniteCanvas) canvas).getContentTransform().mxxProperty() .removeListener(zoomListener); zoomListener = null; } } /** * Updates the scale value that is shown in the GUI so that it corresponds * to the given zoom factor. * * @param zoomFactor * The zoom factor to show in the scale. */ protected void updateScaleValue(double zoomFactor) { if (zoomScale != null) { zoomScale.setSelection(computeScaleValue(zoomFactor)); } } }