/******************************************************************************* * Copyright (c) 2013, 2014 Ericsson * * 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: * Bernd Hufmann - Initial API and implementation *******************************************************************************/ package org.eclipse.tracecompass.tmf.ui.viewers.xycharts; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseWheelListener; import org.swtchart.IAxis; import org.swtchart.Range; /** * Class for providing zooming and scrolling based on mouse wheel. For zooming, * it centers the zoom on mouse position. For scrolling, it will move the zoom * window to another position while maintaining the window size. It also * notifies the viewer about a change of range. * * @author Bernd Hufmann */ public class TmfMouseWheelZoomProvider extends TmfBaseProvider implements MouseWheelListener { // ------------------------------------------------------------------------ // Constants // ------------------------------------------------------------------------ private static final double ZOOM_FACTOR = 0.8; private static final long MIN_WINDOW_SIZE = 1; // ------------------------------------------------------------------------ // Constructors // ------------------------------------------------------------------------ /** * Standard constructor. * * @param tmfChartViewer * The parent histogram object */ public TmfMouseWheelZoomProvider(ITmfChartTimeProvider tmfChartViewer) { super(tmfChartViewer); register(); } // ------------------------------------------------------------------------ // TmfBaseProvider // ------------------------------------------------------------------------ @Override public void register() { getChart().getPlotArea().addMouseWheelListener(this); } @Override public void deregister() { if ((getChartViewer().getControl() != null) && !getChartViewer().getControl().isDisposed()) { getChart().getPlotArea().removeMouseWheelListener(this); } } @Override public void refresh() { // nothing to do } // ------------------------------------------------------------------------ // MouseWheelListener // ------------------------------------------------------------------------ @Override public synchronized void mouseScrolled(MouseEvent event) { ITmfChartTimeProvider viewer = getChartViewer(); final int count = event.count; if (count != 0) { if ((event.stateMask & SWT.CTRL) != 0) { final int x = event.x; zoom(viewer, count, x); } else if ((event.stateMask & SWT.SHIFT) != 0) { scroll(viewer, count); } } } private void scroll(ITmfChartTimeProvider viewer, int count) { IAxis xAxis = getChart().getAxisSet().getXAxis(0); long windowStartTime = viewer.getWindowStartTime(); long windowsEndTime = viewer.getWindowEndTime(); long startTime = viewer.getStartTime(); long endTime = viewer.getEndTime(); long range = windowsEndTime - windowStartTime; if (range <= 0) { return; } long increment = Math.max(1, range / 2); if (count > 0) { windowStartTime = Math.max(windowStartTime - increment, startTime); windowsEndTime = windowStartTime + range; } else { windowsEndTime = Math.min(windowsEndTime + increment, endTime); windowStartTime = windowsEndTime - range; } viewer.updateWindow(windowStartTime, windowsEndTime); xAxis.setRange(new Range(windowStartTime - viewer.getTimeOffset(), windowsEndTime - viewer.getTimeOffset())); } private void zoom(ITmfChartTimeProvider viewer, final int count, final int x) { // Compute the new time range long newDuration = viewer.getWindowDuration(); if (newDuration == 0 || count == 0) { return; } double ratio = 1.0; if (count > 0) { ratio = ZOOM_FACTOR; newDuration = Math.round(ZOOM_FACTOR * newDuration); } else { ratio = 1.0 / ZOOM_FACTOR; newDuration = (long) Math.ceil(newDuration * ratio); } newDuration = Math.max(MIN_WINDOW_SIZE, newDuration); // Center the zoom on mouse position, distribute new duration and adjust // for boundaries. IAxis xAxis = getChart().getAxisSet().getXAxis(0); long timeAtXPos = limitXDataCoordinate(xAxis.getDataCoordinate(x)) + viewer.getTimeOffset(); // Note: ratio = newDuration/oldDuration long newWindowStartTime = timeAtXPos - Math.round(ratio * (timeAtXPos - viewer.getWindowStartTime())); long newWindowEndTime = validateWindowEndTime(newWindowStartTime, newWindowStartTime + newDuration); newWindowStartTime = validateWindowStartTime(newWindowStartTime); viewer.updateWindow(newWindowStartTime, newWindowEndTime); xAxis.setRange(new Range(newWindowStartTime - viewer.getTimeOffset(), newWindowEndTime - viewer.getTimeOffset())); } // ------------------------------------------------------------------------ // Helper methods // ------------------------------------------------------------------------ private long validateWindowStartTime(long start) { ITmfChartTimeProvider viewer = getChartViewer(); long realStart = start; long startTime = viewer.getStartTime(); long endTime = viewer.getEndTime(); if (realStart < startTime) { realStart = startTime; } if (realStart > endTime) { realStart = endTime; } return realStart; } private long validateWindowEndTime(long start, long end) { ITmfChartTimeProvider viewer = getChartViewer(); long realEnd = end; long endTime = viewer.getEndTime(); if (realEnd > endTime) { realEnd = endTime; } if (realEnd < start + MIN_WINDOW_SIZE) { realEnd = start + MIN_WINDOW_SIZE; } return realEnd; } }