blob: bee3ff037d6aa88e9eead5e855f77eebc751ce47 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2010 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.draw2d;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.draw2d.geometry.Transposer;
/**
* Provides for the scrollbars used by the {@link ScrollPane}. A ScrollBar is
* made up of five essential Figures: An 'Up' arrow button, a 'Down' arrow
* button, a draggable 'Thumb', a 'Pageup' button, and a 'Pagedown' button.
*/
public class ScrollBar extends Figure implements Orientable,
PropertyChangeListener {
private static final int ORIENTATION_FLAG = Figure.MAX_FLAG << 1;
/** @see Figure#MAX_FLAG */
protected static final int MAX_FLAG = ORIENTATION_FLAG;
private static final Color COLOR_TRACK = FigureUtilities.mixColors(
ColorConstants.white, ColorConstants.button);
private RangeModel rangeModel = null;
private IFigure thumb;
private Clickable pageUp, pageDown;
private Clickable buttonUp, buttonDown;
/**
* Listens to mouse events on the scrollbar to take care of scrolling.
*/
protected ThumbDragger thumbDragger = new ThumbDragger();
private boolean isHorizontal = false;
private int pageIncrement = 50;
private int stepIncrement = 10;
/**
* Transposes from vertical to horizontal if needed.
*/
protected final Transposer transposer = new Transposer();
{
setRangeModel(new DefaultRangeModel());
}
/**
* Constructs a ScrollBar. ScrollBar orientation is vertical by default.
* Call {@link #setHorizontal(boolean)} with <code>true</code> to set
* horizontal orientation.
*
* @since 2.0
*/
public ScrollBar() {
initialize();
}
/**
* Creates the default 'Up' ArrowButton for the ScrollBar.
*
* @return the up button
* @since 2.0
*/
protected Clickable createDefaultUpButton() {
Button buttonUp = new ArrowButton();
buttonUp.setBorder(new ButtonBorder(
ButtonBorder.SCHEMES.BUTTON_SCROLLBAR));
return buttonUp;
}
/**
* Creates the default 'Down' ArrowButton for the ScrollBar.
*
* @return the down button
* @since 2.0
*/
protected Clickable createDefaultDownButton() {
Button buttonDown = new ArrowButton();
buttonDown.setBorder(new ButtonBorder(
ButtonBorder.SCHEMES.BUTTON_SCROLLBAR));
return buttonDown;
}
/**
* Creates the pagedown Figure for the Scrollbar.
*
* @return the page down figure
* @since 2.0
*/
protected Clickable createPageDown() {
return createPageUp();
}
/**
* Creates the pageup Figure for the Scrollbar.
*
* @return the page up figure
* @since 2.0
*/
protected Clickable createPageUp() {
final Clickable clickable = new Clickable();
clickable.setOpaque(true);
clickable.setBackgroundColor(COLOR_TRACK);
clickable.setRequestFocusEnabled(false);
clickable.setFocusTraversable(false);
clickable.addChangeListener(new ChangeListener() {
public void handleStateChanged(ChangeEvent evt) {
if (clickable.getModel().isArmed())
clickable.setBackgroundColor(ColorConstants.black);
else
clickable.setBackgroundColor(COLOR_TRACK);
}
});
return clickable;
}
/**
* Creates the Scrollbar's "thumb", the draggable Figure that indicates the
* Scrollbar's position.
*
* @return the thumb figure
* @since 2.0
*/
protected IFigure createDefaultThumb() {
Panel thumb = new Panel();
thumb.setMinimumSize(new Dimension(6, 6));
thumb.setBackgroundColor(ColorConstants.button);
thumb.setBorder(new SchemeBorder(SchemeBorder.SCHEMES.BUTTON_CONTRAST));
return thumb;
}
/**
* Returns the figure used as the up button.
*
* @return the up button
*/
protected IFigure getButtonUp() {
// TODO: The set method takes a Clickable while the get method returns
// an IFigure.
// Change the get method to return Clickable (since that's what it's
// typed as).
return buttonUp;
}
/**
* Returns the figure used as the down button.
*
* @return the down button
*/
protected IFigure getButtonDown() {
// TODO: The set method takes a Clickable while the get method returns
// an IFigure.
// Change the get method to return Clickable (since that's what it's
// typed as).
return buttonDown;
}
/**
* Returns the extent.
*
* @return the extent
* @see RangeModel#getExtent()
*/
public int getExtent() {
return getRangeModel().getExtent();
}
/**
* Returns the minumum value.
*
* @return the minimum
* @see RangeModel#getMinimum()
*/
public int getMinimum() {
return getRangeModel().getMinimum();
}
/**
* Returns the maximum value.
*
* @return the maximum
* @see RangeModel#getMaximum()
*/
public int getMaximum() {
return getRangeModel().getMaximum();
}
/**
* Returns the figure used for page down.
*
* @return the page down figure
*/
protected IFigure getPageDown() {
// TODO: The set method takes a Clickable while the get method returns
// an IFigure.
// Change the get method to return Clickable (since that's what it's
// typed as).
return pageDown;
}
/**
* Returns the the amound the scrollbar will move when the page up or page
* down areas are pressed.
*
* @return the page increment
*/
public int getPageIncrement() {
return pageIncrement;
}
/**
* Returns the figure used for page up.
*
* @return the page up figure
*/
protected IFigure getPageUp() {
// TODO: The set method takes a Clickable while the get method returns
// an IFigure.
// Change the get method to return Clickable (since that's what it's
// typed as).
return pageUp;
}
/**
* Returns the range model for this scrollbar.
*
* @return the range model
*/
public RangeModel getRangeModel() {
return rangeModel;
}
/**
* Returns the amount the scrollbar will move when the up or down arrow
* buttons are pressed.
*
* @return the step increment
*/
public int getStepIncrement() {
return stepIncrement;
}
/**
* Returns the figure used as the scrollbar's thumb.
*
* @return the thumb figure
*/
protected IFigure getThumb() {
return thumb;
}
/**
* Returns the current scroll position of the scrollbar.
*
* @return the current value
* @see RangeModel#getValue()
*/
public int getValue() {
return getRangeModel().getValue();
}
/**
* Returns the size of the range of allowable values.
*
* @return the value range
*/
protected int getValueRange() {
return getMaximum() - getExtent() - getMinimum();
}
/**
* Initilization of the ScrollBar. Sets the Scrollbar to have a
* ScrollBarLayout with vertical orientation. Creates the Figures that make
* up the components of the ScrollBar.
*
* @since 2.0
*/
protected void initialize() {
setLayoutManager(new ScrollBarLayout(transposer));
setUpClickable(createDefaultUpButton());
setDownClickable(createDefaultDownButton());
setPageUp(createPageUp());
setPageDown(createPageDown());
setThumb(createDefaultThumb());
}
/**
* Returns <code>true</code> if this scrollbar is orientated horizontally,
* <code>false</code> otherwise.
*
* @return whether this scrollbar is horizontal
*/
public boolean isHorizontal() {
return isHorizontal;
}
private void pageDown() {
setValue(getValue() + getPageIncrement());
}
private void pageUp() {
setValue(getValue() - getPageIncrement());
}
/**
* @see PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent event) {
if (event.getSource() instanceof RangeModel) {
setEnabled(getRangeModel().isEnabled());
if (RangeModel.PROPERTY_VALUE.equals(event.getPropertyName())) {
firePropertyChange("value", event.getOldValue(), //$NON-NLS-1$
event.getNewValue());
revalidate();
}
if (RangeModel.PROPERTY_MINIMUM.equals(event.getPropertyName())) {
firePropertyChange("value", event.getOldValue(), //$NON-NLS-1$
event.getNewValue());
revalidate();
}
if (RangeModel.PROPERTY_MAXIMUM.equals(event.getPropertyName())) {
firePropertyChange("value", event.getOldValue(), //$NON-NLS-1$
event.getNewValue());
revalidate();
}
if (RangeModel.PROPERTY_EXTENT.equals(event.getPropertyName())) {
firePropertyChange("value", event.getOldValue(), //$NON-NLS-1$
event.getNewValue());
revalidate();
}
}
}
/**
* @see IFigure#revalidate()
*/
public void revalidate() {
// Override default revalidate to prevent going up the parent chain.
// Reason for this
// is that preferred size never changes unless orientation changes.
invalidate();
getUpdateManager().addInvalidFigure(this);
}
/**
* Does nothing because this doesn't make sense for a scrollbar.
*
* @see Orientable#setDirection(int)
*/
public void setDirection(int direction) {
// Doesn't make sense for Scrollbar.
}
/**
* Sets the Clickable that represents the down arrow of the Scrollbar to
* <i>down</i>.
*
* @param down
* the down button
* @since 2.0
*/
public void setDownClickable(Clickable down) {
if (buttonDown != null) {
remove(buttonDown);
}
buttonDown = down;
if (buttonDown != null) {
if (buttonDown instanceof Orientable)
((Orientable) buttonDown)
.setDirection(isHorizontal() ? Orientable.EAST
: Orientable.SOUTH);
buttonDown.setFiringMethod(Clickable.REPEAT_FIRING);
buttonDown.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
stepDown();
}
});
add(buttonDown, ScrollBarLayout.DOWN_ARROW);
}
}
/**
* Sets the Clickable that represents the up arrow of the Scrollbar to
* <i>up</i>.
*
* @param up
* the up button
* @since 2.0
*/
public void setUpClickable(Clickable up) {
if (buttonUp != null) {
remove(buttonUp);
}
buttonUp = up;
if (up != null) {
if (up instanceof Orientable)
((Orientable) up).setDirection(isHorizontal() ? Orientable.WEST
: Orientable.NORTH);
buttonUp.setFiringMethod(Clickable.REPEAT_FIRING);
buttonUp.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
stepUp();
}
});
add(buttonUp, ScrollBarLayout.UP_ARROW);
}
}
/**
* @see IFigure#setEnabled(boolean)
*/
public void setEnabled(boolean value) {
if (isEnabled() == value)
return;
super.setEnabled(value);
setChildrenEnabled(value);
if (getThumb() != null) {
getThumb().setVisible(value);
revalidate();
}
}
/**
* Sets the extent of the Scrollbar to <i>ext</i>
*
* @param ext
* the extent
* @since 2.0
*/
public void setExtent(int ext) {
if (getExtent() == ext)
return;
getRangeModel().setExtent(ext);
}
/**
* Sets the orientation of the ScrollBar. If <code>true</code>, the
* Scrollbar will have a horizontal orientation. If <code>false</code>, the
* scrollBar will have a vertical orientation.
*
* @param value
* <code>true</code> if the scrollbar should be horizontal
* @since 2.0
*/
public final void setHorizontal(boolean value) {
setOrientation(value ? HORIZONTAL : VERTICAL);
}
/**
* Sets the maximum position to <i>max</i>.
*
* @param max
* the maximum position
* @since 2.0
*/
public void setMaximum(int max) {
if (getMaximum() == max)
return;
getRangeModel().setMaximum(max);
}
/**
* Sets the minimum position to <i>min</i>.
*
* @param min
* the minumum position
* @since 2.0
*/
public void setMinimum(int min) {
if (getMinimum() == min)
return;
getRangeModel().setMinimum(min);
}
/**
* @see Orientable#setOrientation(int)
*/
public void setOrientation(int value) {
if ((value == HORIZONTAL) == isHorizontal())
return;
isHorizontal = value == HORIZONTAL;
transposer.setEnabled(isHorizontal);
setChildrenOrientation(value);
super.revalidate();
}
/**
* Sets the ScrollBar to scroll <i>increment</i> pixels when its pageup or
* pagedown buttons are pressed. (Note that the pageup and pagedown buttons
* are <b>NOT</b> the arrow buttons, they are the figures between the arrow
* buttons and the ScrollBar's thumb figure).
*
* @param increment
* the new page increment
* @since 2.0
*/
public void setPageIncrement(int increment) {
pageIncrement = increment;
}
/**
* Sets the pagedown button to the passed Clickable. The pagedown button is
* the figure between the down arrow button and the ScrollBar's thumb
* figure.
*
* @param down
* the page down figure
* @since 2.0
*/
public void setPageDown(Clickable down) {
if (pageDown != null)
remove(pageDown);
pageDown = down;
if (pageDown != null) {
pageDown.setFiringMethod(Clickable.REPEAT_FIRING);
pageDown.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
pageDown();
}
});
add(down, ScrollBarLayout.PAGE_DOWN);
}
}
/**
* Sets the pageup button to the passed Clickable. The pageup button is the
* rectangular figure between the down arrow button and the ScrollBar's
* thumb figure.
*
* @param up
* the page up figure
* @since 2.0
*/
public void setPageUp(Clickable up) {
if (pageUp != null)
remove(pageUp);
pageUp = up;
if (pageUp != null) {
pageUp.setFiringMethod(Clickable.REPEAT_FIRING);
pageUp.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent event) {
pageUp();
}
});
add(pageUp, ScrollBarLayout.PAGE_UP);
}
}
/**
* Sets the ScrollBar's RangeModel to the passed value.
*
* @param rangeModel
* the new range model
* @since 2.0
*/
public void setRangeModel(RangeModel rangeModel) {
if (this.rangeModel != null)
this.rangeModel.removePropertyChangeListener(this);
this.rangeModel = rangeModel;
rangeModel.addPropertyChangeListener(this);
}
/**
* Sets the ScrollBar's step increment to the passed value. The step
* increment indicates how many pixels the ScrollBar will scroll when its up
* or down arrow button is pressed.
*
* @param increment
* the new step increment
* @since 2.0
*/
public void setStepIncrement(int increment) {
stepIncrement = increment;
}
/**
* Sets the ScrollBar's thumb to the passed Figure. The thumb is the
* draggable component of the ScrollBar that indicates the ScrollBar's
* position.
*
* @param figure
* the thumb figure
* @since 2.0
*/
public void setThumb(IFigure figure) {
if (thumb != null) {
thumb.removeMouseListener(thumbDragger);
thumb.removeMouseMotionListener(thumbDragger);
remove(thumb);
}
thumb = figure;
if (thumb != null) {
thumb.addMouseListener(thumbDragger);
thumb.addMouseMotionListener(thumbDragger);
add(thumb, ScrollBarLayout.THUMB);
}
}
/**
* Sets the value of the Scrollbar to <i>v</i>
*
* @param v
* the new value
* @since 2.0
*/
public void setValue(int v) {
getRangeModel().setValue(v);
}
/**
* Causes the ScrollBar to scroll down (or right) by the value of its step
* increment.
*
* @since 2.0
*/
protected void stepDown() {
setValue(getValue() + getStepIncrement());
}
/**
* Causes the ScrollBar to scroll up (or left) by the value of its step
* increment.
*
* @since 2.0
*/
protected void stepUp() {
setValue(getValue() - getStepIncrement());
}
/**
* @since 3.6
*/
protected class ThumbDragger extends MouseMotionListener.Stub implements
MouseListener {
protected Point start;
protected int dragRange;
protected int revertValue;
protected boolean armed;
public ThumbDragger() {
}
public void mousePressed(MouseEvent me) {
armed = true;
start = me.getLocation();
Rectangle area = new Rectangle(transposer.t(getClientArea()));
Dimension thumbSize = transposer.t(getThumb().getSize());
if (getButtonUp() != null)
area.height -= transposer.t(getButtonUp().getSize()).height;
if (getButtonDown() != null)
area.height -= transposer.t(getButtonDown().getSize()).height;
Dimension sizeDifference = new Dimension(area.width, area.height
- thumbSize.height);
dragRange = sizeDifference.height;
revertValue = getValue();
me.consume();
}
public void mouseDragged(MouseEvent me) {
if (!armed)
return;
Dimension difference = transposer.t(me.getLocation().getDifference(
start));
int change = getValueRange() * difference.height / dragRange;
setValue(revertValue + change);
me.consume();
}
public void mouseReleased(MouseEvent me) {
if (!armed)
return;
armed = false;
me.consume();
}
public void mouseDoubleClicked(MouseEvent me) {
}
}
}