gov.nasa.worldwind.util.tree.ScrollBar Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2012 United States Government as represented by the Administrator of the
* National Aeronautics and Space Administration.
* All Rights Reserved.
*/
package gov.nasa.worldwind.util.tree;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.event.SelectEvent;
import gov.nasa.worldwind.pick.PickSupport;
import gov.nasa.worldwind.render.*;
import gov.nasa.worldwind.util.*;
import com.jogamp.opengl.*;
import java.awt.*;
import java.awt.event.*;
/**
* A scrollbar component. The scrollable range is defined by four values: min, max, value, and extent. {@code value} is
* the current position of the scroll bar. {@code extent} represents the visible region. The four values must always
* satisfy this relationship:
*
*
* min <= value <= value + extent <= max
*
*
* @author pabercrombie
* @version $Id: ScrollBar.java 1171 2013-02-11 21:45:02Z dcollins $
*/
public class ScrollBar implements Renderable
{
/** Scroll increment for one unit up. */
public static final String UNIT_UP = "gov.nasa.util.ScrollBar.UnitUp";
/** Scroll increment for one unit down. */
public static final String UNIT_DOWN = "gov.nasa.util.ScrollBar.UnitDown";
/** Scroll increment for one page up. */
public static final String BLOCK_UP = "gov.nasa.util.ScrollBar.BlockUp";
/** Scroll increment for one page down. */
public static final String BLOCK_DOWN = "gov.nasa.util.ScrollBar.BlockDown";
/** Default scroll range minimum value. */
protected static final int DEFAULT_MIN_VALUE = 0;
/** Default scroll range maximum value. */
protected static final int DEFAULT_MAX_VALUE = 100;
/** Default unit increment. */
protected static final int DEFAULT_UNIT_INCREMENT = 5;
/** Default minimum size, in pixels, of the scroll knob. */
protected static final int DEFAULT_MIN_SCROLL_KNOB_SIZE = 10;
/** Default delay, in milliseconds, between auto scroll steps. */
protected static final int DEFAULT_AUTO_SCROLL_DELAY = 20;
/** Default insets that position the triangle of the scroll arrow in its box. */
protected static final Insets DEFAULT_ARROW_INSETS = new Insets(2, 2, 2, 2);
/** Default opacity. */
protected static final double DEFAULT_OPACITY = 1.0;
/** Default color used to draw lines in the scroll bar. */
protected static final Color DEFAULT_LINE_COLOR = Color.BLACK;
/** Default first color in the scroll knob gradient. */
protected static final Color DEFAULT_SCROLL_KNOB_COLOR1 = new Color(29, 78, 169);
/** Default second color in the scroll knob gradient. */
protected static final Color DEFAULT_SCROLL_KNOB_COLOR2 = new Color(93, 158, 223);
/** Minimum value in the scroll range. */
protected int minValue = DEFAULT_MIN_VALUE;
/** Maximum value in the scroll range. */
protected int maxValue = DEFAULT_MAX_VALUE;
/** Current scroll bar value. */
protected int value;
/** The amount of the scroll region that is visible in the frame. */
protected int extent;
/** Amount that the scroll bar scrolls when the up or down arrow is clicked. */
protected int unitIncrement = DEFAULT_UNIT_INCREMENT;
/** Size, in pixels, of the scroll arrow square. */
protected int scrollArrowSize;
/**
* The minimum size of the scroll knob. The size of the knob will adjust to the scroll extent, but will never get
* smaller than this size. This prevents the knob from shrinking to a single pixels if the scroll range is very
* large.
*/
protected int minScrollKnobSize = DEFAULT_MIN_SCROLL_KNOB_SIZE;
/** Support for setting up and restoring picking state, and resolving the picked object. */
protected PickSupport pickSupport = new PickSupport();
/** Full bounds of the scroll bar. */
protected Rectangle bounds = new Rectangle();
/**
* Bounds of the scroll track part of the scroll bar. This is the region in which the scroll knob moves, and
* excludes the scroll up and down arrows.
*/
protected Rectangle scrollBounds = new Rectangle();
/** Insets used to position the triangle in the scroll arrow box. */
protected Insets arrowInsets = DEFAULT_ARROW_INSETS;
/** Scroll bar orientation, either {@link AVKey#HORIZONTAL} or {@link AVKey#VERTICAL}. */
protected String orientation;
/** Opacity of the scroll bar knob. */
protected double opacity = DEFAULT_OPACITY;
/** Color applied to lines in the scroll bar. */
protected Color lineColor = DEFAULT_LINE_COLOR;
/** First color of the gradient used to fill the scroll knob. */
protected Color knobColor1 = DEFAULT_SCROLL_KNOB_COLOR1;
/** Second color of the gradient used to fill the scroll knob. */
protected Color knobColor2 = DEFAULT_SCROLL_KNOB_COLOR2;
// Support for long-running scroll operations
/**
* Delay in milliseconds between each step in auto-scroll operation is effect. When auto-scrolling the bar will
* scroll by the {@link #autoScrollIncrement} every {@code autoScrollDelay} milliseconds.
*/
protected int autoScrollDelay = DEFAULT_AUTO_SCROLL_DELAY;
/**
* Indicates whether an auto-scroll operation is active (such as when the user has clicked and held the mouse on the
* scroll arrow).
*/
protected boolean autoScrolling;
/**
* The amount and direction that the bar scrolls while auto-scrolling. One of {@link #UNIT_UP}, {@link #UNIT_DOWN},
* {@link #BLOCK_UP}, {@link #BLOCK_DOWN}.
*/
protected String autoScrollIncrement;
// UI controls
/** HotSpot to handle input on the scroll up control. */
protected HotSpot scrollUpControl;
/** HotSpot to handle input on the scroll down control. */
protected HotSpot scrollDownControl;
/** HotSpot to handle input on page up control. */
protected HotSpot scrollUpBlockControl;
/** HotSpot to handle input on page down control. */
protected HotSpot scrollDownBlockControl;
/** HotSpot to handle input on the scroll knob. */
protected ScrollKnob scrollKnobControl;
// Values computed once per frame and reused during the frame as needed.
/** Identifies frame used to calculate per-frame values. */
protected long frameNumber = -1;
/** Bounds of the "up arrow" control. */
protected Rectangle scrollUpControlBounds;
/** Bounds of the "down arrow" control. */
protected Rectangle scrollDownControlBounds;
/** Bounds of the scroll knob. */
protected Rectangle scrollKnobBounds;
/** Bounds of the scroll bar area above the knob. */
protected Rectangle scrollUpBarBounds;
/** Bounds of the scroll bar area below the knob. */
protected Rectangle scrollDownBarBounds;
/** Time at which the scrollbar should automatically update itself. */
protected long nextAutoScroll;
/**
* Create a scroll bar in the vertical orientation.
*
* @param parent The screen component that contains the scroll bar. Input events that cannot be handled by the
* scroll bar will be passed to this component. May be null.
*/
public ScrollBar(HotSpot parent)
{
this.setOrientation(AVKey.VERTICAL);
this.initializeUIControls(parent);
}
/**
* Create a scroll bar with an orientation.
*
* @param orientation Either {@link AVKey#VERTICAL} or {@link AVKey#HORIZONTAL}.
* @param parent The screen component that contains the scroll bar. Input events that cannot be handled by the
* scroll bar will be passed to this component. May be null.
*/
public ScrollBar(HotSpot parent, String orientation)
{
this.setOrientation(orientation);
this.initializeUIControls(parent);
}
/**
* Initialize the objects that represent the UI controls.
*
* @param parent The screen component that contains the scroll bar. Input events that cannot be handled by the
* scroll bar will be passed to this component. May be null.
*/
protected void initializeUIControls(HotSpot parent)
{
this.scrollKnobControl = new ScrollKnob(parent, this);
this.scrollUpControl = new ScrollControl(parent, this, UNIT_UP);
this.scrollDownControl = new ScrollControl(parent, this, UNIT_DOWN);
this.scrollUpBlockControl = new ScrollControl(parent, this, BLOCK_UP);
this.scrollDownBlockControl = new ScrollControl(parent, this, BLOCK_DOWN);
}
/**
* Get the bounds of the scroll bar.
*
* @return Scroll bar bounds.
*/
public Rectangle getBounds()
{
return bounds;
}
/**
* Set the bounds of the scroll bar.
*
* @param bounds New bounds.
*/
public void setBounds(Rectangle bounds)
{
this.bounds = bounds;
if (AVKey.VERTICAL.equals(this.getOrientation()))
this.scrollArrowSize = bounds.width;
else
this.scrollArrowSize = bounds.height;
this.scrollBounds = new Rectangle(bounds.x, bounds.y + this.scrollArrowSize, bounds.width,
bounds.height - 2 * this.scrollArrowSize);
}
/**
* Get the minimum value in the scroll range.
*
* @return Minimum value.
*/
public int getMinValue()
{
return minValue;
}
/**
* Set the minimum value in the scroll range.
*
* @param minValue New minimum.
*/
public void setMinValue(int minValue)
{
if (minValue < 0)
{
String message = Logging.getMessage("generic.ArgumentOutOfRange", "minValue < 0");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.minValue = minValue;
if (this.getValue() < this.minValue)
this.setValue(this.minValue);
}
/**
* Get the maximum value in the scroll range.
*
* @return Maximum value.
*
* @see #getMinValue()
* @see #setMaxValue(int)
*/
public int getMaxValue()
{
return maxValue;
}
/**
* Set the maximum value in the scroll range.
*
* @param maxValue New maximum.
*/
public void setMaxValue(int maxValue)
{
if (maxValue < 0)
{
String message = Logging.getMessage("generic.ArgumentOutOfRange", "maxValue < 0");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.maxValue = maxValue;
if (this.getValue() > this.maxValue)
this.setValue(this.maxValue);
}
/**
* Get the current value of the scroll bar.
*
* @return Current value. The value is clamped to the range [minValue : maxValue - extent].
*/
public int getValue()
{
return this.value;
}
/**
* Set the value of the scroll bar. The value is clamped to the range [minValue : maxValue - extent].
*
* @param value New value.
*/
public void setValue(int value)
{
this.value = WWMath.clamp(value, this.getMinValue(), this.getMaxValue() - this.getExtent());
}
/**
* Get the unit increment. This is the amount that the scroll bar scrolls by when one of the arrow controls is
* clicked.
*
* @return Unit increment.
*
* @see #setUnitIncrement(int)
*/
public int getUnitIncrement()
{
return this.unitIncrement;
}
/**
* Set the unit increment.
*
* @param unitIncrement New unit increment. Must be a positive number.
*
* @see #getUnitIncrement()
*/
public void setUnitIncrement(int unitIncrement)
{
if (unitIncrement <= 0)
{
String message = Logging.getMessage("generic.ArgumentOutOfRange", "unitIncrement <= 0");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.unitIncrement = unitIncrement;
}
/**
* Get the block increment. This is the amount that the scroll bar scrolls by when the bar is clicked above or below
* the knob.
*
* @return The block increment. This implementation returns the extent, so the scroll bar will adjust by a full
* visible page.
*/
public int getBlockIncrement()
{
return this.extent;
}
/**
* Get the scroll bar orientation.
*
* @return The scroll bar orientation, either {@link AVKey#VERTICAL} or {@link AVKey#HORIZONTAL}.
*/
public String getOrientation()
{
return this.orientation;
}
/**
* Set the scroll bar orientation.
*
* @param orientation The scroll bar orientation, either {@link AVKey#VERTICAL} or {@link AVKey#HORIZONTAL}.
*/
public void setOrientation(String orientation)
{
if (orientation == null)
{
String message = Logging.getMessage("nullValue.StringIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.orientation = orientation;
}
/**
* Get the extent. The extent the amount of the scrollable region that is visible.
*
* @return The extent.
*
* @see #setExtent(int)
*/
public int getExtent()
{
return this.extent;
}
/**
* Set the extent. The extent the amount of the scrollable region that is visible. This method may change the value
* of the scroll bar to maintain the relationship:
*
* min <= value <= value + extent <= max
*
*
* @param extent New extent. If {@code extent} is greater than the range of the scroll bar (max - min), then the
* extent will be set to the maximum valid value.
*
* @see #getExtent()
*/
public void setExtent(int extent)
{
this.extent = Math.min(extent, this.getMaxValue() - this.getMinValue());
if (this.getValue() + this.getExtent() > this.getMaxValue())
this.setValue(this.getMaxValue() - this.getExtent());
}
/**
* Get the value as a percentage of the scroll range.
*
* @return Current value as percentage.
*/
public double getValueAsPercentage()
{
return (double) this.getValue() / (this.getMaxValue() - this.getMinValue());
}
/**
* Indicates the minimum size of the scrollbar knob, in pixels.
*
* @return Minimum size of the knob in pixels.
*/
public int getMinScrollKnobSize()
{
return this.minScrollKnobSize;
}
/**
* Specifies the minimum size of the scrollbar knob, in pixels.
*
* @param minSize Minimum size of the knob in pixels.
*/
public void setMinScrollKnobSize(int minSize)
{
this.minScrollKnobSize = minSize;
}
/**
* Get the size of the scroll knob, in pixels.
*
* @param scrollAreaSize The size of the scroll area, in pixels.
*
* @return Size of the scroll knob, in pixels.
*/
protected int getKnobSize(int scrollAreaSize)
{
return (int) Math.max((scrollAreaSize * ((double) this.getExtent() / (this.getMaxValue() - this.minValue))),
this.getMinScrollKnobSize());
}
/**
* Get the height of the scroll arrow controls at the top and bottom of the scroll bar.
*
* @return Height of arrow control, in pixels.
*/
protected int getScrollArrowSize()
{
return this.scrollArrowSize;
}
/**
* Get the color used to draw the lines of the scroll bar boundary and the scroll arrows.
*
* @return Color used for the scroll bar lines.
*
* @see #setLineColor(java.awt.Color)
* @see #getKnobColor()
*/
public Color getLineColor()
{
return lineColor;
}
/**
* Set the color of the lines of the scroll bar boundary. This color is also used for the arrows in the scroll
* controls.
*
* @param color Color for lines and scroll arrows.
*
* @see #getLineColor()
* @see #setKnobColor(java.awt.Color, java.awt.Color)
*/
public void setLineColor(Color color)
{
if (color == null)
{
String msg = Logging.getMessage("nullValue.AttributesIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
this.lineColor = color;
}
/**
* Set the color of scroll knob. The knob is drawn with a gradient made up of two colors.
*
* @param color1 First color in the gradient.
* @param color2 Second color in the gradient.
*
* @see #getKnobColor()
* @see #setLineColor(java.awt.Color)
*/
public void setKnobColor(Color color1, Color color2)
{
if (color1 == null)
{
String msg = Logging.getMessage("nullValue.ColorIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (color2 == null)
{
String msg = Logging.getMessage("nullValue.ColorIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
this.knobColor1 = color1;
this.knobColor2 = color2;
}
/**
* Get the color of scroll knob. The knob is drawn with a gradient made up of two colors.
*
* @return Two element array containing the two colors that form the gradient.
*
* @see #setKnobColor(java.awt.Color, java.awt.Color)
* @see #getLineColor()
*/
public Color[] getKnobColor()
{
return new Color[] {this.knobColor1, this.knobColor2};
}
/**
* Indicates the opacity of the scroll knob.
*
* @return Scroll knob opacity.
*/
public double getOpacity()
{
return this.opacity;
}
/**
* Specifies the opacity of the scroll knob.
*
* @param opacity New opacity.
*/
public void setOpacity(double opacity)
{
this.opacity = opacity;
}
/**
* Indicates how frequently the scrollbar updates while one of the scroll arrows is pressed.
*
* @return The delay, in milliseconds, between scrollbar updates.
*/
public int getAutoScrollDelay()
{
return this.autoScrollDelay;
}
/**
* Specifies how often the scrollbar will update itself when one of the scroll arrows is pressed.
*
* @param delay Delay in milliseconds between scrollbar updates. A smaller number makes the scrollbar scroll faster,
* a larger number makes it scroll slower. The delay may not be negative.
*/
public void setAutoScrollDelay(int delay)
{
if (delay < 0)
{
String msg = Logging.getMessage("generic.ArgumentOutOfRange", delay);
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
this.autoScrollDelay = delay;
}
//**************************************************************//
//******** Methods for setting the scroll position ***********//
//**************************************************************//
/**
* Adjust the scroll value.
*
* @param amount Amount to add to the current value. A positive value indicates a scroll down; a negative value
* indicates a scroll up.
*/
public void scroll(int amount)
{
this.setValue(this.getValue() + amount);
}
/**
* Adjust the scroll bar by the unit amount or the block amount.
*
* @param amount One of {@link #UNIT_UP}, {@link #UNIT_DOWN}, {@link #BLOCK_UP}, or {@link #BLOCK_DOWN}.
*/
public void scroll(String amount)
{
if (UNIT_UP.equals(amount))
this.scroll(-this.getUnitIncrement());
else if (UNIT_DOWN.equals(amount))
this.scroll(this.getUnitIncrement());
else if (BLOCK_UP.equals(amount))
this.scroll(-this.getBlockIncrement());
else if (BLOCK_DOWN.equals(amount))
this.scroll(this.getBlockIncrement());
}
/**
* Start an auto-scroll operation. During auto-scroll, the scroll bar will adjust its value and repaint continuously
* until the auto-scroll is stopped.
*
* @param increment Amount to adjust scroll bar each time. One of {@link #UNIT_UP}, {@link #UNIT_DOWN}, {@link
* #BLOCK_UP}, or {@link #BLOCK_DOWN}.
*
* @see #stopAutoScroll()
* @see #isAutoScrolling()
* @see #scroll(String)
*/
public void startAutoScroll(String increment)
{
this.autoScrolling = true;
this.autoScrollIncrement = increment;
}
/**
* Stop an auto-scroll operation.
*
* @see #startAutoScroll(String)
* @see #isAutoScrolling()
*/
public void stopAutoScroll()
{
this.autoScrolling = false;
}
/**
* Is the scroll bar auto-scrolling?
*
* @return True if an auto-scroll operation is in progress.
*
* @see #startAutoScroll(String)
* @see #stopAutoScroll()
*/
public boolean isAutoScrolling()
{
return this.autoScrolling;
}
//**************************************************************//
//********************** Rendering ****************************//
//**************************************************************//
/**
* Draw the scroll bar. The scroll will not draw its bounds are too small to draw without distortion.
*
* @param dc the DrawContext
to be used
*/
public void render(DrawContext dc)
{
if (dc.getFrameTimeStamp() != this.frameNumber)
{
// If an auto-scroll operation is in progress, adjust the scroll value and request that the scene be repainted
// and a delay so that the next scroll value can be applied.
if (this.isAutoScrolling())
{
// Only scroll if the autoscroll delay has elapsed since the last scroll
long now = System.currentTimeMillis();
if (now > this.nextAutoScroll)
{
int delay = this.getAutoScrollDelay();
this.scroll(this.autoScrollIncrement);
dc.setRedrawRequested(delay);
this.nextAutoScroll = now + delay;
}
}
this.computeBounds();
this.frameNumber = dc.getFrameTimeStamp();
}
// Don't draw the scrollbar if the bounds are too small to draw without distortion
if (!this.canDrawInBounds())
return;
if (dc.isPickingMode())
{
this.doPick(dc);
}
else
{
this.draw(dc);
}
}
/**
* Determines if the scrollbar is able to draw within its bounds.
*
* @return {@code true} if the scroll bar is able to draw within the bounds, or {@code false} if the bounds are too
* small to draw without distortion.
*/
protected boolean canDrawInBounds()
{
int arrowSize = this.getScrollArrowSize();
String orientation = this.getOrientation();
if (AVKey.VERTICAL.equals(orientation))
return this.bounds.height >= (arrowSize * 2 + this.getMinScrollKnobSize())
&& this.bounds.width >= arrowSize;
else
return this.bounds.width >= (arrowSize * 2 + this.getMinScrollKnobSize())
&& this.bounds.height >= arrowSize;
}
/** Compute the bounds of the scroll bar. */
protected void computeBounds()
{
int x1 = this.bounds.x;
int y1 = this.bounds.y;
int x2 = this.bounds.x + this.bounds.width;
int y2 = this.bounds.y + this.bounds.height;
int scrollControlSize = this.getScrollArrowSize();
if (AVKey.VERTICAL.equals(this.getOrientation()))
{
this.scrollDownControlBounds = new Rectangle(x1, y1, scrollControlSize, scrollControlSize);
this.scrollUpControlBounds = new Rectangle(x1, y2 - scrollControlSize, scrollControlSize,
scrollControlSize);
int scrollAreaHeight = this.bounds.height - 2 * scrollControlSize;
int position = (int) (scrollAreaHeight * this.getValueAsPercentage());
int knobEnd = y2 - scrollControlSize - position - this.getKnobSize(scrollAreaHeight);
// Make sure the knob doesn't overlap the scroll down control
if (knobEnd < y1 + scrollControlSize)
knobEnd = y1 + scrollControlSize;
this.scrollKnobBounds = new Rectangle(x1, knobEnd - 1, scrollControlSize,
this.getKnobSize(scrollAreaHeight) + 1);
this.scrollDownBarBounds = new Rectangle(x1, y1 + scrollControlSize, scrollControlSize,
knobEnd - y1 - scrollControlSize);
int knobStart = (int) this.scrollKnobBounds.getMaxY();
this.scrollUpBarBounds = new Rectangle(x1, knobStart, scrollControlSize,
this.scrollUpControlBounds.y - knobStart);
}
else
{
this.scrollUpControlBounds = new Rectangle(x1, y1, scrollControlSize, scrollControlSize);
this.scrollDownControlBounds = new Rectangle(x2 - scrollControlSize, y1, scrollControlSize,
scrollControlSize);
int scrollAreaWidth = this.bounds.width - 2 * scrollControlSize;
int position = (int) (scrollAreaWidth * this.getValueAsPercentage());
int knobStart = x1 + scrollControlSize + position;
int knobSize = this.getKnobSize(scrollAreaWidth);
this.scrollKnobBounds = new Rectangle(knobStart, y1, knobSize + 1, scrollControlSize);
// Make sure the knob doesn't overlap the scroll right control
if (this.scrollKnobBounds.getMaxX() > x2 - scrollControlSize)
this.scrollKnobBounds.x = x2 - scrollControlSize - knobSize;
this.scrollUpBarBounds = new Rectangle(x1 + scrollControlSize, y1,
this.scrollKnobBounds.x - scrollControlSize - x1, scrollControlSize);
int knobEnd = (int) this.scrollKnobBounds.getMaxX();
this.scrollDownBarBounds = new Rectangle(knobEnd, y1, this.scrollDownControlBounds.x - knobEnd,
scrollControlSize);
}
}
/**
* Draw the scroll bar.
*
* @param dc Current draw context.
*/
protected void draw(DrawContext dc)
{
GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
OGLStackHandler oglStack = new OGLStackHandler();
try
{
oglStack.pushAttrib(gl,
GL2.GL_COLOR_BUFFER_BIT
| GL2.GL_CURRENT_BIT
| GL2.GL_LINE_BIT
| GL2.GL_POLYGON_BIT);
gl.glLineWidth(1f);
OGLUtil.applyColor(gl, this.getLineColor(), this.getOpacity(), false);
gl.glPolygonMode(GL2.GL_FRONT, GL2.GL_LINE);
try
{
gl.glBegin(GL2.GL_QUADS);
// Draw scroll bar frame
this.drawQuad(dc, this.bounds);
// Draw boxes for up and down arrows
this.drawQuad(dc, this.scrollDownControlBounds);
this.drawQuad(dc, this.scrollUpControlBounds);
}
finally
{
gl.glEnd();
}
gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_FILL);
// Draw background gradient
String gradientDirection;
if (AVKey.VERTICAL.equals(this.getOrientation()))
gradientDirection = AVKey.HORIZONTAL;
else
gradientDirection = AVKey.VERTICAL;
TreeUtil.drawRectWithGradient(gl, this.scrollKnobBounds, this.knobColor2, this.knobColor1,
this.getOpacity(), gradientDirection);
// Draw a border around the knob
OGLUtil.applyColor(gl, this.getLineColor(), this.getOpacity(), false);
gl.glBegin(GL2.GL_LINE_LOOP);
this.drawQuad(dc, this.scrollKnobBounds);
gl.glEnd();
gl.glPolygonMode(GL2.GL_FRONT_AND_BACK, GL2.GL_FILL);
if (AVKey.VERTICAL.equals(this.getOrientation()))
{
this.drawTriangle(dc, 90, this.scrollUpControlBounds, arrowInsets);
this.drawTriangle(dc, -90, this.scrollDownControlBounds, arrowInsets);
}
else
{
this.drawTriangle(dc, 180, this.scrollUpControlBounds, arrowInsets);
this.drawTriangle(dc, 0, this.scrollDownControlBounds, arrowInsets);
}
}
finally
{
oglStack.pop(gl);
}
}
/**
* Pick the scroll bar.
*
* @param dc Current draw context.
*/
protected void doPick(DrawContext dc)
{
GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
try
{
this.pickSupport.clearPickList();
this.pickSupport.beginPicking(dc);
gl.glBegin(GL2.GL_QUADS);
this.drawPickableQuad(dc, this.scrollDownControl, this.scrollDownControlBounds);
this.drawPickableQuad(dc, this.scrollUpControl, this.scrollUpControlBounds);
this.drawPickableQuad(dc, this.scrollDownBlockControl, this.scrollDownBarBounds);
this.drawPickableQuad(dc, this.scrollUpBlockControl, this.scrollUpBarBounds);
// The knob, for dragging
this.drawPickableQuad(dc, this.scrollKnobControl, this.scrollKnobBounds);
}
finally
{
gl.glEnd();
this.pickSupport.endPicking(dc);
this.pickSupport.resolvePick(dc, dc.getPickPoint(), dc.getCurrentLayer());
}
}
/**
* Draw a filled quad in a unique pick color. This method must be called between {@code glBegin(GL.GL_QUADS)} and
* {@code glEnd()}.
*
* @param dc Current draw context.
* @param pickObject User object to attach to the picked object.
* @param bounds Bounds of the quad.
*/
protected void drawPickableQuad(DrawContext dc, Object pickObject, Rectangle bounds)
{
GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
Color color = dc.getUniquePickColor();
int colorCode = color.getRGB();
this.pickSupport.addPickableObject(colorCode, pickObject);
gl.glColor3ub((byte) color.getRed(), (byte) color.getGreen(), (byte) color.getBlue());
this.drawQuad(dc, bounds);
}
/**
* Draw the vertices of a quadrilateral. This method must be called between {@code glBegin(GL.GL_QUADS)} and {@code
* glEnd()}.
*
* @param dc Current draw context.
* @param bounds Bounds of the quad.
*/
protected void drawQuad(DrawContext dc, Rectangle bounds)
{
GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
int minX = (int) bounds.getMinX();
int minY = (int) bounds.getMinY();
int maxX = (int) bounds.getMaxX();
int maxY = (int) bounds.getMaxY();
gl.glVertex2i(minX, minY);
gl.glVertex2i(maxX, minY);
gl.glVertex2i(maxX, maxY);
gl.glVertex2i(minX, maxY);
}
/**
* Draw a triangle for one of the scroll bar controls.
*
* @param dc Draw context.
* @param rotation Rotation to apply to the triangle. 0 rotation produces a triangle pointing to the right. Rotation
* must be one of: 0, 90, -90, or 180.
* @param bounds The bounds of the scroll control. The arrow must be drawn within this rectangle.
* @param insets Insets to apply to the bounds.
*/
protected void drawTriangle(DrawContext dc, float rotation, Rectangle bounds, Insets insets)
{
GL2 gl = dc.getGL().getGL2(); // GL initialization checks for GL2 compatibility.
try
{
gl.glPushMatrix();
// Apply the inset to the bounds.
Rectangle insetBounds = new Rectangle(bounds.x + insets.left, bounds.y + insets.bottom,
bounds.width - insets.left - insets.right,
bounds.height - insets.top - insets.bottom);
float halfHeight = insetBounds.height / 2.0f;
float halfWidth = insetBounds.width / 2.0f;
float adjustX = 0;
float adjustY = 0;
if (rotation == 90)
{
adjustX = halfWidth;
adjustY = (insetBounds.height - halfWidth) / 2.0f;
}
else if (rotation == -90)
{
adjustX = halfWidth;
adjustY = (insetBounds.height - halfWidth) / 2.0f + halfWidth;
}
else if (rotation == 0)
{
adjustX = (insetBounds.width - halfWidth) / 2.0f;
adjustY = halfHeight;
}
else if (rotation == 180)
{
adjustX = (insetBounds.width - halfWidth) / 2.0f + halfWidth;
adjustY = halfHeight;
}
gl.glTranslated(insetBounds.x + adjustX, insetBounds.y + adjustY, 1.0);
gl.glRotatef(rotation, 0, 0, 1);
gl.glBegin(GL2.GL_TRIANGLES);
gl.glVertex2f(0, halfHeight);
gl.glVertex2f(halfWidth, 0);
gl.glVertex2f(0, -halfHeight);
gl.glEnd();
}
finally
{
gl.glPopMatrix();
}
}
//**************************************************************//
//***************** User input handling ***********************//
//**************************************************************//
/** Control for the scroll arrows and areas of the scroll bar above and below the knob. */
public class ScrollControl extends TreeHotSpot
{
protected ScrollBar scrollBar;
protected String adjustment;
public ScrollControl(HotSpot parent, ScrollBar owner, String adjustment)
{
super(parent);
this.scrollBar = owner;
this.adjustment = adjustment;
}
@Override
public void mousePressed(MouseEvent event)
{
if (event == null || event.isConsumed())
return;
if (event.getButton() == MouseEvent.BUTTON1)
scrollBar.startAutoScroll(this.adjustment);
}
@Override
public void mouseReleased(MouseEvent event)
{
if (event == null || event.isConsumed())
return;
if (event.getButton() == MouseEvent.BUTTON1)
this.scrollBar.stopAutoScroll();
}
@Override
public void selected(SelectEvent event)
{
// Overridden to prevent the super class passing the event to a parent component
if (event == null || event.isConsumed())
return;
// Consume drag events to prevent the globe from panning in response to the drag.
if (event.isDrag())
event.consume();
}
@Override
public void mouseClicked(MouseEvent event)
{
// Don't let super class pass this event to parent component
}
/**
* {@inheritDoc}
*
* Overridden to stop autoscroll operations when the scrollbar becomes inactive.
*
* @param active {@code true} if the scrollbar is being activated, {@code false} if the scrollbar is being
* deactivated.
*/
@Override
public void setActive(boolean active)
{
// If the scrollbar is being deactivated, stop any autoscroll operations that are in progress. When the
// scrollbar is inactive it will not receive mouse events, so it will not be able to stop the scroll
// operation when the mouse is released.
if (!active)
this.scrollBar.stopAutoScroll();
super.setActive(active);
}
}
/** Control for dragging the scroll knob. */
public class ScrollKnob extends DragControl
{
protected ScrollBar scrollBar;
protected int dragRefValue;
public ScrollKnob(HotSpot parent, ScrollBar owner)
{
super(parent);
this.scrollBar = owner;
}
@Override
public void mouseClicked(MouseEvent event)
{
// Don't let super class pass this event to parent component
}
@Override
protected void beginDrag(Point point)
{
super.beginDrag(point);
this.dragRefValue = this.scrollBar.getValue();
}
protected void drag(Point point)
{
int delta;
int adjustment;
int screenDimension;
if (AVKey.VERTICAL.equals(scrollBar.getOrientation()))
{
delta = point.y - this.dragRefPoint.y;
screenDimension = this.scrollBar.scrollBounds.height - this.scrollBar.getMinScrollKnobSize();
}
else
{
delta = point.x - this.dragRefPoint.x;
screenDimension = this.scrollBar.scrollBounds.width;
}
int scrollRange = this.scrollBar.getMaxValue() - this.scrollBar.getMinValue();
adjustment = (int) (((double) delta / screenDimension) * scrollRange);
this.scrollBar.setValue(this.dragRefValue + adjustment);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy