/******************************************************************************* * Copyright (c) 2006-2009 Nicolas Richeton. * 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 : * Nicolas Richeton (nicolas.richeton@gmail.com) - initial API and implementation *******************************************************************************/ package org.eclipse.nebula.animation; import org.eclipse.nebula.animation.effects.IEffect; import org.eclipse.nebula.animation.effects.MoveScrollBarEffect; import org.eclipse.nebula.animation.movement.IMovement; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.ScrollBar; import org.eclipse.swt.widgets.Scrollable; /** * <p> * Allows to replace the default scrolling behavior by an animation effect. * </p> * * <p> * Compatible with : * </p> * <ul> * <li>Shell</li> * <li>StyledText</li> * <li>Canvas</li> * <li>Gallery</li> * </ul> * * * @author Nicolas Richeton * */ public class ScrollingSmoother { Scrollable component; ScrollBar verticalScrollBar; ScrollBar horizontalScrollBar; IMovement movement = null; int duration = 2000; AnimationRunner animationRunner = new AnimationRunner(); /** * Create a Scrolling Smoother instance over a scrollable widget. This * effect can then be activated using * {@link ScrollingSmoother#smoothControl(boolean)}. * * @see ScrollingSmoother#smoothControl(boolean) * * @param c2 * @param movement */ public ScrollingSmoother(final Scrollable c2, IMovement movement) { this.component = c2; verticalScrollBar = c2.getVerticalBar(); horizontalScrollBar = c2.getHorizontalBar(); this.movement = movement; } /** * Create a Scrolling Smoother instance over a scrollable widget. This * effect can then be activated using * {@link ScrollingSmoother#smoothControl(boolean)}. * * @see ScrollingSmoother#smoothControl(boolean) * * @param c2 * @param movement * @param duration */ public ScrollingSmoother(final Scrollable c2, IMovement movement, int duration) { this(c2, movement); this.duration = duration; } /** * Get current effect duration (ms). * * @return */ public int getDuration() { return duration; } /** * Set effect duration (ms). * * @param duration */ public void setDuration(int duration) { this.duration = duration; } /** * Set the FPS (frame per second) to use with the animator. * * @param fps */ public void setFPS(int fps) { animationRunner = new AnimationRunner(fps); } protected ScrollBar getScrollbar(Event event) { ScrollBar result = verticalScrollBar; if (result == null) { result = horizontalScrollBar; } return result; } Listener mouseWheelListener = new Listener() { public void handleEvent(Event event) { // Remove standard behavior event.doit = false; // Get scrollbar on which the event occurred. ScrollBar currentScrollBar = getScrollbar(event); int start = currentScrollBar.getSelection(); int end = start; // If an effect is currently running, get the current and target // values. IEffect current = animationRunner.getEffect(); if (current instanceof MoveScrollBarEffect) { MoveScrollBarEffect mseffect = (MoveScrollBarEffect) current; start = mseffect.getCurrent(); end = mseffect.getEnd(); } end -= event.count * currentScrollBar.getIncrement(); if (end > currentScrollBar.getMaximum() - currentScrollBar.getThumb()) { end = currentScrollBar.getMaximum() - currentScrollBar.getThumb(); } if (end < currentScrollBar.getMinimum()) { end = currentScrollBar.getMinimum(); } animationRunner.runEffect(new MoveScrollBarEffect(currentScrollBar, start, end, duration, movement, null, null)); } }; /** * Enable or disable scrolling effect. * * @param enable * true or false. */ public void smoothControl(boolean enable) { if (enable) { component.addListener(SWT.MouseWheel, mouseWheelListener); if (verticalScrollBar != null) verticalScrollBar .addSelectionListener(cancelEffectIfUserSelection); if (horizontalScrollBar != null) horizontalScrollBar .addSelectionListener(cancelEffectIfUserSelection); } else { component.removeListener(SWT.MouseWheel, mouseWheelListener); if (verticalScrollBar != null) verticalScrollBar .removeSelectionListener(cancelEffectIfUserSelection); if (horizontalScrollBar != null) horizontalScrollBar .removeSelectionListener(cancelEffectIfUserSelection); } } SelectionListener cancelEffectIfUserSelection = new SelectionListener() { public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } public void widgetSelected(SelectionEvent e) { // data contains an instance of MoveScrollBarEffect if the selection // was generated by this effect. Otherwise this is an user // selection. if (!(e.data instanceof MoveScrollBarEffect)) { animationRunner.cancel(); } } }; }