blob: ea907bf0fad9be1c725892bb839ce8e2541c5cfb [file] [log] [blame]
package org.eclipse.swt.widgets;
/*
* Copyright (c) 2000, 2002 IBM Corp. All rights reserved.
* This file is made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*/
import org.eclipse.swt.internal.carbon.*;
import org.eclipse.swt.*;
import org.eclipse.swt.graphics.*;
import org.eclipse.swt.events.*;
/**
* Instances of this class are selectable user interface
* objects that represent a range of positive, numeric values.
* <p>
* At any given moment, a given scroll bar will have a
* single <em>selection</em> that is considered to be its
* value, which is constrained to be within the range of
* values the scroll bar represents (that is, between its
* <em>minimum</em> and <em>maximum</em> values).
* </p><p>
* Typically, scroll bars will be made up of five areas:
* <ol>
* <li>an arrow button for decrementing the value</li>
* <li>a page decrement area for decrementing the value by a larger amount</li>
* <li>a <em>thumb</em> for modifying the value by mouse dragging</li>
* <li>a page increment area for incrementing the value by a larger amount</li>
* <li>an arrow button for incrementing the value</li>
* </ol>
* Based on their style, scroll bars are either <code>HORIZONTAL</code>
* (which have a left facing button for decrementing the value and a
* right facing button for incrementing it) or <code>VERTICAL</code>
* (which have an upward facing button for decrementing the value
* and a downward facing buttons for incrementing it).
* </p><p>
* On some platforms, the size of the scroll bar's thumb can be
* varied relative to the magnitude of the range of values it
* represents (that is, relative to the difference between its
* maximum and minimum values). Typically, this is used to
* indicate some proportional value such as the ratio of the
* visible area of a document to the total amount of space that
* it would take to display it. SWT supports setting the thumb
* size even if the underlying platform does not, but in this
* case the appearance of the scroll bar will not change.
* </p><p>
* Scroll bars are created by specifying either <code>H_SCROLL</code>,
* <code>V_SCROLL</code> or both when creating a <code>Scrollable</code>.
* They are accessed from the <code>Scrollable</code> using
* <code>getHorizontalBar</code> and <code>getVerticalBar</code>.
* </p><p>
* Note: Scroll bars are not Controls. On some platforms, scroll bars
* that appear as part of some standard controls such as a text or list
* have no operating system resources and are not children of the control.
* For this reason, scroll bars are treated specially. To create a control
* that looks like a scroll bar but has operating system resources, use
* <code>Slider</code>.
* </p>
* <dl>
* <dt><b>Styles:</b></dt>
* <dd>HORIZONTAL, VERTICAL</dd>
* <dt><b>Events:</b></dt>
* <dd>Selection</dd>
* </dl>
* <p>
* Note: Only one of the styles HORIZONTAL and VERTICAL may be specified.
* </p><p>
* IMPORTANT: This class is <em>not</em> intended to be subclassed.
* </p>
*
* @see Slider
* @see Scrollable
* @see Scrollable#getHorizontalBar
* @see Scrollable#getVerticalBar
*/
public /*final*/ class ScrollBar extends Widget {
Scrollable parent;
// AW
private int fIncrement= 1;
private int fPageIncrement= 10;
// AW
ScrollBar () {
/* Do Nothing */
}
ScrollBar (Scrollable parent, int style) {
super (parent, checkStyle (style));
this.parent = parent;
createWidget (0);
}
/**
* Adds the listener to the collection of listeners who will
* be notified when the receiver's value changes, by sending
* it one of the messages defined in the <code>SelectionListener</code>
* interface.
* <p>
* When <code>widgetSelected</code> is called, the event object detail field contains one of the following values:
* <code>0</code> - for the end of a drag.
* <code>SWT.DRAG</code>.
* <code>SWT.HOME</code>.
* <code>SWT.END</code>.
* <code>SWT.ARROW_DOWN</code>.
* <code>SWT.ARROW_UP</code>.
* <code>SWT.PAGE_DOWN</code>.
* <code>SWT.PAGE_UP</code>.
* <code>widgetDefaultSelected</code> is not called.
* </p>
*
* @param listener the listener which should be notified
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see SelectionListener
* @see #removeSelectionListener
* @see SelectionEvent
*/
public void addSelectionListener(SelectionListener listener) {
checkWidget();
if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
TypedListener typedListener = new TypedListener(listener);
addListener(SWT.Selection,typedListener);
addListener(SWT.DefaultSelection,typedListener);
}
static int checkStyle (int style) {
return checkBits (style, SWT.HORIZONTAL, SWT.VERTICAL, 0, 0, 0, 0);
}
void createHandle (int index) {
state |= HANDLE;
/* AW
int [] argList = {
OS.XmNancestorSensitive, 1,
OS.XmNborderWidth, (style & SWT.BORDER) != 0 ? 1 : 0,
OS.XmNorientation, ((style & SWT.H_SCROLL) != 0) ? OS.XmHORIZONTAL : OS.XmVERTICAL,
};
*/
/*
handle= 0;
int[] outHandle= new int[1];
int status= 0;
int count= OS.CountSubControls(parent.scrolledHandle);
if (count < 3)
count= count;
if (MacUtil.REVERSE) {
if ((style & SWT.H_SCROLL) != 0) {
status= OS.GetIndexedSubControl(parent.scrolledHandle, (short)2, outHandle);
} else if ((style & SWT.V_SCROLL) != 0) {
status= OS.GetIndexedSubControl(parent.scrolledHandle, (short)1, outHandle);
}
} else {
if ((style & SWT.H_SCROLL) != 0) {
status= OS.GetIndexedSubControl(parent.scrolledHandle, (short)1, outHandle);
} else if ((style & SWT.V_SCROLL) != 0) {
status= OS.GetIndexedSubControl(parent.scrolledHandle, (short)2, outHandle);
}
}
if (status == 0)
handle= outHandle[0];
else {
error (SWT.ERROR_NO_HANDLES);
}
*/
handle= 0;
if ((style & SWT.H_SCROLL) != 0) {
handle= parent.fHScrollBar;
} else if ((style & SWT.V_SCROLL) != 0) {
handle= parent.fVScrollBar;
}
if (handle == 0) error (SWT.ERROR_NO_HANDLES);
}
/**
* Gets the Display.
*/
public Display getDisplay () {
Scrollable parent = this.parent;
if (parent == null) error (SWT.ERROR_WIDGET_DISPOSED);
return parent.getDisplay ();
}
/**
* Returns <code>true</code> if the receiver is enabled, and
* <code>false</code> otherwise. A disabled control is typically
* not selectable from the user interface and draws with an
* inactive or "grayed" look.
*
* @return the enabled state
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public boolean getEnabled () {
checkWidget();
return OS.IsControlEnabled(handle);
}
/**
* Returns the amount that the receiver's value will be
* modified by when the up/down (or right/left) arrows
* are pressed.
*
* @return the increment
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public int getIncrement () {
checkWidget();
return fIncrement;
}
/**
* Returns the maximum value which the receiver will allow.
*
* @return the maximum
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public int getMaximum () {
checkWidget();
return OS.GetControl32BitMaximum(handle) + OS.GetControlViewSize(handle);
}
/**
* Returns the minimum value which the receiver will allow.
*
* @return the minimum
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public int getMinimum () {
checkWidget();
return OS.GetControl32BitMinimum(handle);
}
/**
* Returns the amount that the receiver's value will be
* modified by when the page increment/decrement areas
* are selected.
*
* @return the page increment
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public int getPageIncrement () {
checkWidget();
return fPageIncrement;
}
/**
* Returns the receiver's parent, which must be scrollable.
*
* @return the receiver's parent
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public Scrollable getParent () {
checkWidget();
return parent;
}
/**
* Returns the single <em>selection</em> that is the receiver's value.
*
* @return the selection
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public int getSelection () {
checkWidget();
return OS.GetControl32BitValue(handle);
}
/**
* Returns a point describing the receiver's size. The
* x coordinate of the result is the width of the receiver.
* The y coordinate of the result is the height of the
* receiver.
*
* @return the receiver's size
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public Point getSize () {
checkWidget();
/* AW
int [] argList = {OS.XmNwidth, 0, OS.XmNheight, 0, OS.XmNborderWidth, 0};
OS.XtGetValues (handle, argList, argList.length / 2);
int borders = argList [5] * 2;
return new Point (argList [1] + borders, argList [3] + borders);
*/
MacRect bounds= new MacRect();
OS.GetControlBounds(handle, bounds.getData());
return bounds.getSize();
}
/**
* Answers the size of the receiver's thumb relative to the
* difference between its maximum and minimum values.
*
* @return the thumb value
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see ScrollBar
*/
public int getThumb () {
checkWidget();
return OS.GetControlViewSize(handle);
}
/**
* Returns <code>true</code> if the receiver is visible, and
* <code>false</code> otherwise.
* <p>
* If one of the receiver's ancestors is not visible or some
* other condition makes the receiver not visible, this method
* may still indicate that it is considered visible even though
* it may not actually be showing.
* </p>
*
* @return the receiver's visibility state
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public boolean getVisible () {
checkWidget();
return OS.IsControlVisible(handle);
}
/* AW
void hookEvents () {
int windowProc = parent.getDisplay ().windowProc;
OS.XtAddCallback (handle, OS.XmNvalueChangedCallback, windowProc, SWT.Selection);
OS.XtAddCallback (handle, OS.XmNdragCallback, windowProc, SWT.Selection);
OS.XtAddCallback (handle, OS.XmNtoBottomCallback, windowProc, SWT.Selection);
OS.XtAddCallback (handle, OS.XmNincrementCallback, windowProc, SWT.Selection);
OS.XtAddCallback (handle, OS.XmNdecrementCallback, windowProc, SWT.Selection);
OS.XtAddCallback (handle, OS.XmNpageIncrementCallback, windowProc, SWT.Selection);
OS.XtAddCallback (handle, OS.XmNpageDecrementCallback, windowProc, SWT.Selection);
OS.XtAddCallback (handle, OS.XmNtoTopCallback, windowProc, SWT.Selection);
}
*/
/**
* Returns <code>true</code> if the receiver is enabled and all
* of the receiver's ancestors are enabled, and <code>false</code>
* otherwise. A disabled control is typically not selectable from the
* user interface and draws with an inactive or "grayed" look.
*
* @return the receiver's enabled state
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see #getEnabled
*/
public boolean isEnabled () {
checkWidget();
return getEnabled () && parent.isEnabled ();
}
/**
* Returns <code>true</code> if the receiver is visible and all
* of the receiver's ancestors are visible and <code>false</code>
* otherwise.
*
* @return the receiver's visibility state
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see #getVisible
*/
public boolean isVisible () {
checkWidget();
return getVisible () && parent.isVisible ();
}
/* AW
void manageChildren () {
OS.XtManageChild (handle);
}
*/
int processSelection (Object callData) {
MacControlEvent macEvent= (MacControlEvent) callData;
if (! macEvent.isMouseDown())
return 0;
Event event= new Event ();
switch (macEvent.getPartCode()) {
case OS.kControlUpButtonPart:
OS.SetControl32BitValue(handle, OS.GetControl32BitValue(handle) - fIncrement);
event.detail = SWT.ARROW_UP;
break;
case OS.kControlPageUpPart:
OS.SetControl32BitValue(handle, OS.GetControl32BitValue(handle) - fPageIncrement);
event.detail = SWT.PAGE_UP;
break;
case OS.kControlPageDownPart:
OS.SetControl32BitValue(handle, OS.GetControl32BitValue(handle) + fPageIncrement);
event.detail = SWT.PAGE_DOWN;
break;
case OS.kControlDownButtonPart:
OS.SetControl32BitValue(handle, OS.GetControl32BitValue(handle) + fIncrement);
event.detail = SWT.ARROW_DOWN;
break;
case OS.kControlIndicatorPart: // end of drag or continuos drag
if (macEvent.isMouseDown()) {
event.detail = SWT.DRAG; // continuos drag
} else {
/*
* Do not set the detail field to SWT.DRAG
* to indicate that the dragging has ended.
*/
}
break;
}
sendEvent (SWT.Selection, event);
Display.processAllUpdateEvents(handle);
return 0;
}
void releaseChild () {
super.releaseChild ();
if (parent.horizontalBar == this) parent.horizontalBar = null;
if (parent.verticalBar == this) parent.verticalBar = null;
}
void releaseWidget () {
super.releaseWidget ();
parent = null;
}
/**
* Removes the listener from the collection of listeners who will
* be notified when the receiver's value changes.
*
* @param listener the listener which should no longer be notified
*
* @exception IllegalArgumentException <ul>
* <li>ERROR_NULL_ARGUMENT - if the listener is null</li>
* </ul>
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see SelectionListener
* @see #addSelectionListener
*/
public void removeSelectionListener(SelectionListener listener) {
checkWidget();
if (listener == null) error (SWT.ERROR_NULL_ARGUMENT);
if (eventTable == null) return;
eventTable.unhook(SWT.Selection, listener);
eventTable.unhook(SWT.DefaultSelection,listener);
}
/**
* Enables the receiver if the argument is <code>true</code>,
* and disables it otherwise. A disabled control is typically
* not selectable from the user interface and draws with an
* inactive or "grayed" look.
*
* @param enabled the new enabled state
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public void setEnabled (boolean enabled) {
checkWidget();
if (enabled)
OS.EnableControl(handle);
else
OS.DisableControl(handle);
}
/**
* Sets the amount that the receiver's value will be
* modified by when the up/down (or right/left) arrows
* are pressed to the argument, which must be at least
* one.
*
* @param value the new increment (must be greater than zero)
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public void setIncrement (int value) {
checkWidget();
if (value < 1) return;
fIncrement= value;
}
/**
* Sets the maximum value which the receiver will allow
* to be the argument which must be greater than or
* equal to zero.
*
* @param value the new maximum (must be zero or greater)
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public void setMaximum (int value) {
checkWidget();
if (value < 0) return;
OS.SetControl32BitMaximum(handle, value-OS.GetControlViewSize(handle));
}
/**
* Sets the minimum value which the receiver will allow
* to be the argument which must be greater than or
* equal to zero.
*
* @param value the new minimum (must be zero or greater)
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public void setMinimum (int value) {
checkWidget();
if (value < 0) return;
OS.SetControl32BitMinimum(handle, value);
}
/**
* Sets the amount that the receiver's value will be
* modified by when the page increment/decrement areas
* are selected to the argument, which must be at least
* one.
*
* @return the page increment (must be greater than zero)
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public void setPageIncrement (int value) {
checkWidget();
if (value < 1) return;
fPageIncrement= value;
}
/**
* Sets the single <em>selection</em> that is the receiver's
* value to the argument which must be greater than or equal
* to zero.
*
* @param value the new selection (must be zero or greater)
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public void setSelection (int selection) {
checkWidget();
if (selection < 0) return;
OS.SetControl32BitValue(handle, selection);
}
/**
* Sets the size of the receiver's thumb relative to the
* difference between its maximum and minimum values to the
* argument which must be at least one.
*
* @param value the new thumb value (must be at least one)
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*
* @see ScrollBar
*/
public void setThumb (int value) {
checkWidget();
if (value < 1) return;
int oldMaximum= OS.GetControl32BitMaximum(handle) + OS.GetControlViewSize(handle);
OS.SetControlViewSize(handle, value);
OS.SetControl32BitMaximum(handle, oldMaximum-value);
}
/**
* Sets the receiver's selection, minimum value, maximum
* value, thumb, increment and page increment all at once.
* <p>
* Note: This is equivalent to setting the values individually
* using the appropriate methods, but may be implemented in a
* more efficient fashion on some platforms.
* </p>
*
* @param selection the new selection value
* @param minimum the new minimum value
* @param maximum the new maximum value
* @param thumb the new thumb value
* @param increment the new increment value
* @param pageIncrement the new pageIncrement value
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public void setValues (int selection, int minimum, int maximum, int thumb, int increment, int pageIncrement) {
checkWidget();
if (selection < 0) return;
if (minimum < 0) return;
if (maximum < 0) return;
if (thumb < 1) return;
if (maximum - minimum - thumb < 0) return;
if (increment < 1) return;
if (pageIncrement < 1) return;
OS.SetControl32BitMinimum(handle, minimum);
OS.SetControl32BitMaximum(handle, maximum-thumb);
OS.SetControlViewSize(handle, thumb);
OS.SetControl32BitValue(handle, selection);
fIncrement= increment;
fPageIncrement= pageIncrement;
}
/**
* Marks the receiver as visible if the argument is <code>true</code>,
* and marks it invisible otherwise.
* <p>
* If one of the receiver's ancestors is not visible or some
* other condition makes the receiver not visible, marking
* it visible may not actually cause it to be displayed.
* </p>
*
* @param visible the new visibility state
*
* @exception SWTException <ul>
* <li>ERROR_WIDGET_DISPOSED - if the receiver has been disposed</li>
* <li>ERROR_THREAD_INVALID_ACCESS - if not called from the thread that created the receiver</li>
* </ul>
*/
public void setVisible (boolean visible) {
checkWidget();
/*
* Feature in Motif. Hiding or showing a scroll bar
* can cause the widget to automatically resize in
* the OS. This behavior is unwanted. The fix is
* to force the widget to resize to original size.
*/
/* AW
int scrolledHandle = parent.scrolledHandle;
int [] argList = {OS.XmNwidth, 0, OS.XmNheight, 0};
OS.XtGetValues (scrolledHandle, argList, argList.length / 2);
*/
/* Hide or show the scroll bar */
/* AW
if (visible) {
OS.XtManageChild (handle);
} else {
OS.XtUnmanageChild (handle);
}
*/
if (OS.IsControlVisible(handle) != visible) {
OS.SetControlVisibility(handle, visible, true);
parent.relayout123(parent.topHandle());
sendEvent(visible ? SWT.Show : SWT.Hide);
}
/* Restore the size */
/* AW
OS.XtSetValues (scrolledHandle, argList, argList.length / 2);
*/
}
}