/*******************************************************************************
* 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 fr.inria.linuxtools.tmf.ui.viewers.xycharts;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseWheelListener;
import org.swtchart.IAxis;
/**
* Class for providing zooming based on mouse wheel. It centers the zoom on
* mouse position. It also notifies the viewer about a change of range.
*
* @author Bernd Hufmann
* @since 3.0
*/
public class TmfMouseWheelZoomProvider extends TmfBaseProvider implements MouseWheelListener {
// ------------------------------------------------------------------------
// Constants
// ------------------------------------------------------------------------
private final static double ZOOM_FACTOR = 0.8;
private final static 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();
long oldDuration = viewer.getWindowDuration();
if (oldDuration == 0) {
return;
}
// Compute the new time range
long newDuration = oldDuration;
double ratio = 1.0;
if (event.count > 0) {
ratio = ZOOM_FACTOR;
newDuration = Math.round(ZOOM_FACTOR * oldDuration);
} else {
ratio = 1.0 / ZOOM_FACTOR;
newDuration = (long) Math.ceil(oldDuration * 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(event.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);
}
// ------------------------------------------------------------------------
// 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;
}
}