diff dwtx/draw2d/ScrollBar.d @ 98:95307ad235d9

Added Draw2d code, still work in progress
author Frank Benoit <benoit@tionex.de>
date Sun, 03 Aug 2008 00:52:14 +0200
parents
children 2d6540440fe6
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dwtx/draw2d/ScrollBar.d	Sun Aug 03 00:52:14 2008 +0200
@@ -0,0 +1,667 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2005 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
+ * Port to the D programming language:
+ *     Frank Benoit <benoit@tionex.de>
+ *******************************************************************************/
+module dwtx.draw2d.ScrollBar;
+
+import dwt.dwthelper.utils;
+
+import dwtx.dwtxhelper.Bean;
+
+import dwt.graphics.Color;
+import dwtx.draw2d.geometry.Dimension;
+import dwtx.draw2d.geometry.Point;
+import dwtx.draw2d.geometry.Rectangle;
+import dwtx.draw2d.geometry.Transposer;
+
+import dwtx.draw2d.Orientable;
+import dwtx.draw2d.Figure;
+import dwtx.draw2d.IFigure;
+import dwtx.draw2d.RangeModel;
+import dwtx.draw2d.Clickable;
+import dwtx.draw2d.MouseMotionListener;
+import dwtx.draw2d.MouseListener;
+import dwtx.draw2d.MouseEvent;
+import dwtx.draw2d.FigureUtilities;
+import dwtx.draw2d.ColorConstants;
+import dwtx.draw2d.Button;
+import dwtx.draw2d.RangeModel;
+import dwtx.draw2d.DefaultRangeModel;
+import dwtx.draw2d.ArrowButton;
+import dwtx.draw2d.ButtonBorder;
+import dwtx.draw2d.ChangeListener;
+import dwtx.draw2d.ChangeEvent;
+import dwtx.draw2d.Panel;
+import dwtx.draw2d.ScrollBarLayout;
+import dwtx.draw2d.SchemeBorder;
+import dwtx.draw2d.ActionListener;
+import dwtx.draw2d.ActionEvent;
+
+/**
+ * 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
+    : Figure
+    , Orientable, PropertyChangeListener
+{
+
+private static const int ORIENTATION_FLAG = Figure.MAX_FLAG << 1;
+/** @see Figure#MAX_FLAG */
+protected static const int MAX_FLAG = ORIENTATION_FLAG;
+
+private static const Color COLOR_TRACK;
+static this(){
+    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;
+
+private bool isHorizontal_ = false;
+
+private int pageIncrement = 50;
+private int stepIncrement = 10;
+
+/**
+ * Transposes from vertical to horizontal if needed.
+ */
+protected /+final+/ Transposer transposer;
+
+private void instanceInit(){
+    thumbDragger = new ThumbDragger();
+    transposer = new Transposer();
+    setRangeModel(new DefaultRangeModel());
+}
+
+/**
+ * Constructs a ScrollBar. ScrollBar orientation is vertical by default. Call
+ * {@link #setHorizontal(bool)} with <code>true</code> to set horizontal orientation.
+ *
+ * @since 2.0
+ */
+public this() {
+    instanceInit();
+    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() {
+    Clickable clickable = new Clickable();
+    clickable.setOpaque(true);
+    clickable.setBackgroundColor(COLOR_TRACK);
+    clickable.setRequestFocusEnabled(false);
+    clickable.setFocusTraversable(false);
+    clickable.addChangeListener( dgChangeListener( (ChangeEvent evt, Clickable clickable_){
+        if (clickable_.getModel().isArmed())
+            clickable_.setBackgroundColor(ColorConstants.black);
+        else
+            clickable_.setBackgroundColor(COLOR_TRACK);
+    }, clickable));
+    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 bool 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 (null !is cast(RangeModel)event.getSource() ) {
+        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 !is null) {
+        remove(buttonDown);
+    }
+    buttonDown = down;
+    if (buttonDown !is null) {
+        if (auto b = cast(Orientable)buttonDown )
+            b.setDirection(isHorizontal()
+                                                    ? Orientable.EAST
+                                                    : Orientable.SOUTH);
+        buttonDown.setFiringMethod(Clickable.REPEAT_FIRING);
+        buttonDown.addActionListener(dgActionListener( (ActionEvent evt){
+            stepDown();
+        }));
+        add(buttonDown, stringcast(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 !is null) {
+        remove(buttonUp);
+    }
+    buttonUp = up;
+    if (up !is null) {
+        if (auto o = cast(Orientable)up )
+            o.setDirection(isHorizontal()
+                                            ? Orientable.WEST
+                                            : Orientable.NORTH);
+        buttonUp.setFiringMethod(Clickable.REPEAT_FIRING);
+        buttonUp.addActionListener(dgActionListener( (ActionEvent evt){
+            stepUp();
+        }));
+        add(buttonUp, stringcast(ScrollBarLayout.UP_ARROW));
+    }
+}
+
+/**
+ * @see IFigure#setEnabled(bool)
+ */
+public void setEnabled(bool value) {
+    if (isEnabled() is value)
+        return;
+    super.setEnabled(value);
+    setChildrenEnabled(value);
+    if (getThumb() !is 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() is 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(bool 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() is 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() is min)
+        return;
+    getRangeModel().setMinimum(min);
+}
+
+/**
+ * @see Orientable#setOrientation(int)
+ */
+public void setOrientation(int value) {
+    if ((value is HORIZONTAL) is isHorizontal())
+        return;
+    isHorizontal_ = value is 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_ !is null)
+        remove(pageDown_);
+    pageDown_ = down;
+    if (pageDown_ !is null) {
+        pageDown_.setFiringMethod(Clickable.REPEAT_FIRING);
+        pageDown_.addActionListener(dgActionListener( (ActionEvent evt){
+            pageDown();
+        }));
+        add(down,stringcast( 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_ !is null)
+        remove(pageUp_);
+    pageUp_ = up;
+    if (pageUp_ !is null) {
+        pageUp_.setFiringMethod(Clickable.REPEAT_FIRING);
+        pageUp_.addActionListener(dgActionListener((ActionEvent evt){
+            pageUp();
+        }));
+        add(pageUp_, stringcast(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 !is 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 !is null) {
+        thumb.removeMouseListener(thumbDragger);
+        thumb.removeMouseMotionListener(thumbDragger);
+        remove(thumb);
+    }
+    thumb = figure;
+    if (thumb !is null) {
+        thumb.addMouseListener(thumbDragger);
+        thumb.addMouseMotionListener(thumbDragger);
+        add(thumb, stringcast(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());
+}
+
+class ThumbDragger
+    : MouseMotionListener.Stub
+    , MouseListener
+{
+    protected Point start;
+    protected int dragRange;
+    protected int revertValue;
+    protected bool armed;
+    public this() { }
+
+    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() !is null)
+            area.height -= transposer.t(getButtonUp().getSize()).height;
+        if (getButtonDown() !is 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) { }
+}
+
+}