/*******************************************************************************
* Copyright (c) 2007, 2014 compeople 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:
* compeople AG - initial API and implementation
*******************************************************************************/
package org.eclipse.riena.ui.swt.utils;
import org.eclipse.core.runtime.Assert;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.riena.internal.ui.swt.facades.WorkbenchFacade;
import org.eclipse.riena.ui.swt.facades.SWTFacade;
/**
* Handles mouse wheel events on a given control.
*
* @since 6.0
*/
public class MouseWheelAdapter implements Listener {
/**
* Implementations handle the received scroll events.
*/
public interface Scroller {
/**
* @return <code>true</code> if scrolling is currently possible
*/
boolean mayScroll();
/**
* @param pixels
* the pixels to scroll up
*/
void scrollUp(int pixels);
/**
* @param pixels
* the pixels to scroll down
*/
void scrollDown(int pixels);
}
/**
* The pixels to scroll for one mouse wheel step
*
* @deprecated Using an absolute mouse wheel scrolling step ignores the system's mouse wheel setting. Use {@link #setScrollingSpeed(int)} instead.
*/
@Deprecated
public static final int SCROLLING_STEP = 20;
private final Control control;
private final Scroller scroller;
private int scrollingSpeed = 7;
public MouseWheelAdapter(final Control control, final Scroller scroller) {
this.control = control;
this.scroller = scroller;
final Display display = control.getDisplay();
SWTFacade.getDefault().addFilterMouseWheel(display, this);
control.addDisposeListener(new DisposeListener() {
public void widgetDisposed(final DisposeEvent e) {
SWTFacade.getDefault().removeFilterMouseWheel(display, MouseWheelAdapter.this);
}
});
}
/**
* The scrolling speed is the non-accelerated pixels count to scroll for one mouse wheel step. The absolute (accelerated) scrolling speed is this value
* multiplied by the system mouse wheel setting.
*
* @return the scrollSpeed
*/
public int getScrollingSpeed() {
return scrollingSpeed;
}
/**
* The scrolling speed is the non-accelerated pixels count to scroll for one mouse wheel step. The absolute (accelerated) scrolling speed is this value
* multiplied by the system mouse wheel setting.
*
* @param scrollingSpeed
* a positive value or <code>0</code> to disable scrolling
*/
public void setScrollingSpeed(final int scrollingSpeed) {
Assert.isLegal(scrollingSpeed >= 0, "The scrolling speed must be a non-negative value."); //$NON-NLS-1$
this.scrollingSpeed = scrollingSpeed;
}
// for saving last event time
private int lastEventTime = 0;
public void handleEvent(final Event event) {
// only go further if the event has a new time stamp
if (scroller.mayScroll() && acceptEvent(event)) {
lastEventTime = event.time;
final Rectangle navigationComponentBounds = control.getBounds();
// convert navigation bounds relative to display
final Point navigationPtAtDisplay = control.toDisplay(0, 0);
navigationComponentBounds.x = navigationPtAtDisplay.x;
navigationComponentBounds.y = navigationPtAtDisplay.y;
if (event.widget instanceof Control) {
final Control widget = (Control) event.widget;
// convert widget event point relative to display
final Point evtPt = widget.toDisplay(event.getBounds().x, event.getBounds().y);
// now check if inside navigation
if (navigationComponentBounds.contains(evtPt.x, evtPt.y)) {
if (event.count > 0) {
scroller.scrollUp(event.count * scrollingSpeed);
} else {
scroller.scrollDown(-event.count * scrollingSpeed);
}
}
}
}
}
private boolean acceptEvent(final Event event) {
// check that this is the latest event
final boolean isCurrent = event.time > lastEventTime;
// 282089: check this window is has the focus, to avoid scrolling when
// the mouse pointer happens to be over another overlapping window
final Control control = (Control) event.widget;
final Shell activeShell = WorkbenchFacade.getInstance().getActiveWindowShell();
final boolean isActive = control.getShell() == activeShell;
// 282091: check that this navigation component is visible. Since
// we are using a display filter the navigation components of _each_
// subapplication are notified when scrolling!
final boolean isVisible = this.control.isVisible();
return isCurrent && isActive && isVisible;
}
}