/*
 * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package sun.awt.X11;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import sun.awt.SunToolkit;
import sun.awt.X11GraphicsConfig;
import sun.util.logging.PlatformLogger;

A simple vertical scroll bar.
/** * A simple vertical scroll bar. */
abstract class XScrollbar { private static PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XScrollbar");
The thread that asynchronously tells the scrollbar to scroll.
See Also:
  • startScrolling
/** * The thread that asynchronously tells the scrollbar to scroll. * @see #startScrolling */
private static XScrollRepeater scroller = new XScrollRepeater(null); /* * The repeater that used for concurrent scrolling of the vertical and horizontal scrollbar * And so there is not static keyword * See 6243382 for more information */ private XScrollRepeater i_scroller = new XScrollRepeater(null); // Thumb length is always >= MIN_THUMB_H private final static int MIN_THUMB_H = 5; private static final int ARROW_IND = 1; XScrollbarClient sb; //Use set methods to set scrollbar parameters private int val; private int min; private int max; private int vis; private int line; private int page; private boolean needsRepaint = true; private boolean pressed = false; private boolean dragging = false; Polygon firstArrow, secondArrow; int width, height; // Dimensions of the visible part of the parent window int barWidth, barLength; // Rotation-independent values, // equal to (width, height) for vertical, // rotated by 90 for horizontal. // That is, barLength is always the length between // the tips of the arrows. int arrowArea; // The area reserved for the scroll arrows int alignment; public static final int ALIGNMENT_VERTICAL = 1, ALIGNMENT_HORIZONTAL = 2; int mode; Point thumbOffset; private Rectangle prevThumb; public XScrollbar(int alignment, XScrollbarClient sb) { this.sb = sb; this.alignment = alignment; } public boolean needsRepaint() { return needsRepaint; } void notifyValue(int v) { notifyValue(v, false); } void notifyValue(int v, final boolean isAdjusting) { if (v < min) { v = min; } else if (v > max - vis) { v = max - vis; } final int value = v; final int mode = this.mode; if ((sb != null) && ((value != val)||(!pressed))) { SunToolkit.executeOnEventHandlerThread(sb.getEventSource(), new Runnable() { public void run() { sb.notifyValue(XScrollbar.this, mode, value, isAdjusting); } }); } } abstract protected void rebuildArrows(); public void setSize(int width, int height) { if (log.isLoggable(PlatformLogger.Level.FINER)) { log.finer("Setting scroll bar " + this + " size to " + width + "x" + height); } this.width = width; this.height = height; }
Creates oriented directed arrow
/** * Creates oriented directed arrow */
protected Polygon createArrowShape(boolean vertical, boolean up) { Polygon arrow = new Polygon(); // TODO: this should be done polymorphically in subclasses // FIXME: arrows overlap the thumb for very wide scrollbars if (vertical) { int x = width / 2 - getArrowWidth()/2; int y1 = (up ? ARROW_IND : barLength - ARROW_IND); int y2 = (up ? getArrowWidth() : barLength - getArrowWidth() - ARROW_IND); arrow.addPoint(x + getArrowWidth()/2, y1); arrow.addPoint(x + getArrowWidth(), y2); arrow.addPoint(x, y2); arrow.addPoint(x + getArrowWidth()/2, y1); } else { int y = height / 2 - getArrowWidth()/2; int x1 = (up ? ARROW_IND : barLength - ARROW_IND); int x2 = (up ? getArrowWidth() : barLength - getArrowWidth() - ARROW_IND); arrow.addPoint(x1, y + getArrowWidth()/2); arrow.addPoint(x2, y + getArrowWidth()); arrow.addPoint(x2, y); arrow.addPoint(x1, y + getArrowWidth()/2); } return arrow; }
Gets the area of the scroll track
/** * Gets the area of the scroll track */
protected abstract Rectangle getThumbArea();
paint the scrollbar
Params:
  • g – the graphics context to paint into
  • colors – the colors to use when painting the scrollbar
  • width – the width of the scrollbar
  • height – the height of the scrollbar
  • paintAll – paint the whole scrollbar if true, just the thumb is false
/** * paint the scrollbar * @param g the graphics context to paint into * @param colors the colors to use when painting the scrollbar * @param width the width of the scrollbar * @param height the height of the scrollbar * @param paintAll paint the whole scrollbar if true, just the thumb is false */
void paint(Graphics g, Color colors[], boolean paintAll) { if (log.isLoggable(PlatformLogger.Level.FINER)) { log.finer("Painting scrollbar " + this); } boolean useBufferedImage = false; Graphics2D g2 = null; BufferedImage buffer = null; if (!(g instanceof Graphics2D)) { // Fix for 5045936, 5055171. While printing, g is an instance // of sun.print.ProxyPrintGraphics which extends Graphics. // So we use a separate buffered image and its graphics is // always Graphics2D instance X11GraphicsConfig graphicsConfig = (X11GraphicsConfig)(sb.getEventSource().getGraphicsConfiguration()); buffer = graphicsConfig.createCompatibleImage(width, height); g2 = buffer.createGraphics(); useBufferedImage = true; } else { g2 = (Graphics2D)g; } try { Rectangle thumbRect = calculateThumbRect(); // if (prevH == thumbH && prevY == thumbPosY) { // return; // } prevThumb = thumbRect; // TODO: Share Motif colors Color back = colors[XComponentPeer.BACKGROUND_COLOR]; Color selectColor = new Color(MotifColorUtilities.calculateSelectFromBackground(back.getRed(),back.getGreen(),back.getBlue())); Color darkShadow = new Color(MotifColorUtilities.calculateBottomShadowFromBackground(back.getRed(),back.getGreen(),back.getBlue())); Color lightShadow = new Color(MotifColorUtilities.calculateTopShadowFromBackground(back.getRed(),back.getGreen(),back.getBlue())); XToolkit.awtLock(); try { XlibWrapper.XFlush(XToolkit.getDisplay()); } finally { XToolkit.awtUnlock(); } /* paint the background slightly darker */ if (paintAll) { // fill the entire background g2.setColor(selectColor); if (alignment == ALIGNMENT_HORIZONTAL) { g2.fillRect(0, 0, thumbRect.x, height); g2.fillRect(thumbRect.x + thumbRect.width , 0, width - (thumbRect.x + thumbRect.width), height); } else { g2.fillRect(0, 0, width, thumbRect.y); g2.fillRect(0, thumbRect.y + thumbRect.height, width, height - (thumbRect.y + thumbRect.height)); } // Paint edges // TODO: Share Motif 3d rect drawing g2.setColor(darkShadow); g2.drawLine(0, 0, width-1, 0); // top g2.drawLine(0, 0, 0, height-1); // left g2.setColor(lightShadow); g2.drawLine(1, height-1, width-1, height-1); // bottom g2.drawLine(width-1, 1, width-1, height-1); // right } else { // Clear all thumb area g2.setColor(selectColor); Rectangle thumbArea = getThumbArea(); g2.fill(thumbArea); } if (paintAll) { // ************ paint the arrows paintArrows(g2, colors[XComponentPeer.BACKGROUND_COLOR], darkShadow, lightShadow ); } // Thumb g2.setColor(colors[XComponentPeer.BACKGROUND_COLOR]); g2.fillRect(thumbRect.x, thumbRect.y, thumbRect.width, thumbRect.height); g2.setColor(lightShadow); g2.drawLine(thumbRect.x, thumbRect.y, thumbRect.x + thumbRect.width, thumbRect.y); // top g2.drawLine(thumbRect.x, thumbRect.y, thumbRect.x, thumbRect.y+thumbRect.height); // left g2.setColor(darkShadow); g2.drawLine(thumbRect.x+1, thumbRect.y+thumbRect.height, thumbRect.x+thumbRect.width, thumbRect.y+thumbRect.height); // bottom g2.drawLine(thumbRect.x+thumbRect.width, thumbRect.y+1, thumbRect.x+thumbRect.width, thumbRect.y+thumbRect.height); // right } finally { if (useBufferedImage) { g2.dispose(); } } if (useBufferedImage) { g.drawImage(buffer, 0, 0, null); } XToolkit.awtLock(); try { XlibWrapper.XFlush(XToolkit.getDisplay()); } finally { XToolkit.awtUnlock(); } } void paintArrows(Graphics2D g, Color background, Color darkShadow, Color lightShadow) { g.setColor(background); // paint firstArrow if (pressed && (mode == AdjustmentEvent.UNIT_DECREMENT)) { g.fill(firstArrow); g.setColor(lightShadow); g.drawLine(firstArrow.xpoints[0],firstArrow.ypoints[0], firstArrow.xpoints[1],firstArrow.ypoints[1]); g.drawLine(firstArrow.xpoints[1],firstArrow.ypoints[1], firstArrow.xpoints[2],firstArrow.ypoints[2]); g.setColor(darkShadow); g.drawLine(firstArrow.xpoints[2],firstArrow.ypoints[2], firstArrow.xpoints[0],firstArrow.ypoints[0]); } else { g.fill(firstArrow); g.setColor(darkShadow); g.drawLine(firstArrow.xpoints[0],firstArrow.ypoints[0], firstArrow.xpoints[1],firstArrow.ypoints[1]); g.drawLine(firstArrow.xpoints[1],firstArrow.ypoints[1], firstArrow.xpoints[2],firstArrow.ypoints[2]); g.setColor(lightShadow); g.drawLine(firstArrow.xpoints[2],firstArrow.ypoints[2], firstArrow.xpoints[0],firstArrow.ypoints[0]); } g.setColor(background); // paint second Arrow if (pressed && (mode == AdjustmentEvent.UNIT_INCREMENT)) { g.fill(secondArrow); g.setColor(lightShadow); g.drawLine(secondArrow.xpoints[0],secondArrow.ypoints[0], secondArrow.xpoints[1],secondArrow.ypoints[1]); g.setColor(darkShadow); g.drawLine(secondArrow.xpoints[1],secondArrow.ypoints[1], secondArrow.xpoints[2],secondArrow.ypoints[2]); g.drawLine(secondArrow.xpoints[2],secondArrow.ypoints[2], secondArrow.xpoints[0],secondArrow.ypoints[0]); } else { g.fill(secondArrow); g.setColor(darkShadow); g.drawLine(secondArrow.xpoints[0],secondArrow.ypoints[0], secondArrow.xpoints[1],secondArrow.ypoints[1]); g.setColor(lightShadow); g.drawLine(secondArrow.xpoints[1],secondArrow.ypoints[1], secondArrow.xpoints[2],secondArrow.ypoints[2]); g.drawLine(secondArrow.xpoints[2],secondArrow.ypoints[2], secondArrow.xpoints[0],secondArrow.ypoints[0]); } }
Tell the scroller to start scrolling.
/** * Tell the scroller to start scrolling. */
void startScrolling() { if (log.isLoggable(PlatformLogger.Level.FINER)) { log.finer("Start scrolling on " + this); } // Make sure that we scroll at least once scroll(); // wake up the scroll repeater if (scroller == null) { // If there isn't a scroller, then create // one and start it. scroller = new XScrollRepeater(this); } else { scroller.setScrollbar(this); } scroller.start(); }
Tell the instance scroller to start scrolling. See 6243382 for more information
/** * Tell the instance scroller to start scrolling. * See 6243382 for more information */
void startScrollingInstance() { if (log.isLoggable(PlatformLogger.Level.FINER)) { log.finer("Start scrolling on " + this); } // Make sure that we scroll at least once scroll(); i_scroller.setScrollbar(this); i_scroller.start(); }
Tell the instance scroller to stop scrolling. See 6243382 for more information
/** * Tell the instance scroller to stop scrolling. * See 6243382 for more information */
void stopScrollingInstance() { if (log.isLoggable(PlatformLogger.Level.FINER)) { log.finer("Stop scrolling on " + this); } i_scroller.stop(); }
The set method for mode property. See 6243382 for more information
/** * The set method for mode property. * See 6243382 for more information */
public void setMode(int mode){ this.mode = mode; }
Scroll one unit.
See Also:
  • notifyValue
/** * Scroll one unit. * @see notifyValue */
void scroll() { switch (mode) { case AdjustmentEvent.UNIT_DECREMENT: notifyValue(val - line); return; case AdjustmentEvent.UNIT_INCREMENT: notifyValue(val + line); return; case AdjustmentEvent.BLOCK_DECREMENT: notifyValue(val - page); return; case AdjustmentEvent.BLOCK_INCREMENT: notifyValue(val + page); return; } return; } boolean isInArrow(int x, int y) { // Mouse is considered to be in the arrow if it is anywhere in the // arrow area. int coord = (alignment == ALIGNMENT_HORIZONTAL ? x : y); int arrAreaH = getArrowAreaWidth(); if (coord < arrAreaH || coord > barLength - arrAreaH + 1) { return true; } return false; }
Is x,y in the scroll thumb? If we ever cache the thumb rect, we may need to clone the result of calculateThumbRect().
/** * Is x,y in the scroll thumb? * * If we ever cache the thumb rect, we may need to clone the result of * calculateThumbRect(). */
boolean isInThumb(int x, int y) { Rectangle thumbRect = calculateThumbRect(); // If the mouse is in the shadow of the thumb or the shadow of the // scroll track, treat it as hitting the thumb. So, slightly enlarge // our rectangle. thumbRect.x -= 1; thumbRect.width += 3; thumbRect.height += 1; return thumbRect.contains(x,y); } abstract boolean beforeThumb(int x, int y);
See Also:
  • MouseEvent.MOUSE_CLICKED MouseEvent.MOUSE_PRESSED MouseEvent.MOUSE_RELEASED MouseEvent.MOUSE_MOVED MouseEvent.MOUSE_ENTERED MouseEvent.MOUSE_EXITED MouseEvent.MOUSE_DRAGGED
/** * * @see java.awt.event.MouseEvent * MouseEvent.MOUSE_CLICKED * MouseEvent.MOUSE_PRESSED * MouseEvent.MOUSE_RELEASED * MouseEvent.MOUSE_MOVED * MouseEvent.MOUSE_ENTERED * MouseEvent.MOUSE_EXITED * MouseEvent.MOUSE_DRAGGED */
public void handleMouseEvent(int id, int modifiers, int x, int y) { if ((modifiers & InputEvent.BUTTON1_MASK) == 0) { return; } if (log.isLoggable(PlatformLogger.Level.FINER)) { String type; switch (id) { case MouseEvent.MOUSE_PRESSED: type = "press"; break; case MouseEvent.MOUSE_RELEASED: type = "release"; break; case MouseEvent.MOUSE_DRAGGED: type = "drag"; break; default: type = "other"; } log.finer("Mouse " + type + " event in scroll bar " + this + "x = " + x + ", y = " + y + ", on arrow: " + isInArrow(x, y) + ", on thumb: " + isInThumb(x, y) + ", before thumb: " + beforeThumb(x, y) + ", thumb rect" + calculateThumbRect()); } switch (id) { case MouseEvent.MOUSE_PRESSED: if (isInArrow(x, y)) { pressed = true; if (beforeThumb(x, y)) { mode = AdjustmentEvent.UNIT_DECREMENT; } else { mode = AdjustmentEvent.UNIT_INCREMENT; } sb.repaintScrollbarRequest(this); startScrolling(); break; } if (isInThumb(x, y)) { mode = AdjustmentEvent.TRACK; } else { if (beforeThumb(x, y)) { mode = AdjustmentEvent.BLOCK_DECREMENT; } else { mode = AdjustmentEvent.BLOCK_INCREMENT; } startScrolling(); } Rectangle pos = calculateThumbRect(); thumbOffset = new Point(x - pos.x, y - pos.y); break; case MouseEvent.MOUSE_RELEASED: pressed = false; sb.repaintScrollbarRequest(this); scroller.stop(); if(dragging){ handleTrackEvent(x, y, false); dragging=false; } break; case MouseEvent.MOUSE_DRAGGED: dragging = true; handleTrackEvent(x, y, true); } } private void handleTrackEvent(int x, int y, boolean isAdjusting){ if (mode == AdjustmentEvent.TRACK) { notifyValue(calculateCursorOffset(x, y), isAdjusting); } } private int calculateCursorOffset(int x, int y){ if (alignment == ALIGNMENT_HORIZONTAL) { if (dragging) return Math.max(0,(int)((x - (thumbOffset.x + getArrowAreaWidth()))/getScaleFactor())) + min; else return Math.max(0,(int)((x - (getArrowAreaWidth()))/getScaleFactor())) + min; } else { if (dragging) return Math.max(0,(int)((y - (thumbOffset.y + getArrowAreaWidth()))/getScaleFactor())) + min; else return Math.max(0,(int)((y - (getArrowAreaWidth()))/getScaleFactor())) + min; } } /* private void updateNeedsRepaint() { Rectangle thumbRect = calculateThumbRect(); if (!prevThumb.equals(thumbRect)) { needsRepaint = true; } prevThumb = thumbRect; } */
Sets the values for this Scrollbar. This method enforces the same constraints as in java.awt.Scrollbar:
  • The maximum must be greater than the minimum
  • The value must be greater than or equal to the minimum and less than or equal to the maximum minus the visible amount
  • The visible amount must be greater than 1 and less than or equal to the difference between the maximum and minimum values.
Values which do not meet these criteria are quietly coerced to the appropriate boundary value.
Params:
  • value – is the position in the current window.
  • visible – is the amount visible per page
  • minimum – is the minimum value of the scrollbar
  • maximum – is the maximum value of the scrollbar
/** * Sets the values for this Scrollbar. * This method enforces the same constraints as in java.awt.Scrollbar: * <UL> * <LI> The maximum must be greater than the minimum </LI> * <LI> The value must be greater than or equal to the minimum * and less than or equal to the maximum minus the * visible amount </LI> * <LI> The visible amount must be greater than 1 and less than or equal * to the difference between the maximum and minimum values. </LI> * </UL> * Values which do not meet these criteria are quietly coerced to the * appropriate boundary value. * @param value is the position in the current window. * @param visible is the amount visible per page * @param minimum is the minimum value of the scrollbar * @param maximum is the maximum value of the scrollbar */
synchronized void setValues(int value, int visible, int minimum, int maximum) { if (maximum <= minimum) { maximum = minimum + 1; } if (visible > maximum - minimum) { visible = maximum - minimum; } if (visible < 1) { visible = 1; } if (value < minimum) { value = minimum; } if (value > maximum - visible) { value = maximum - visible; } this.val = value; this.vis = visible; this.min = minimum; this.max = maximum; }
Sets param of this Scrollbar to the specified values.
Params:
  • value – is the position in the current window.
  • visible – is the amount visible per page
  • minimum – is the minimum value of the scrollbar
  • maximum – is the maximum value of the scrollbar
  • unitSize – is the unit size for increment or decrement of the value
  • page – is the block size for increment or decrement of the value
See Also:
/** * Sets param of this Scrollbar to the specified values. * @param value is the position in the current window. * @param visible is the amount visible per page * @param minimum is the minimum value of the scrollbar * @param maximum is the maximum value of the scrollbar * @param unitSize is the unit size for increment or decrement of the value * @param page is the block size for increment or decrement of the value * @see #setValues */
synchronized void setValues(int value, int visible, int minimum, int maximum, int unitSize, int blockSize) { /* Use setValues so that a consistent policy * relating minimum, maximum, and value is enforced. */ setValues(value, visible, minimum, maximum); setUnitIncrement(unitSize); setBlockIncrement(blockSize); }
Returns the current value of this Scrollbar.
See Also:
/** * Returns the current value of this Scrollbar. * @see #getMinimum * @see #getMaximum */
int getValue() { return val; }
Sets the value of this Scrollbar to the specified value.
Params:
  • value – the new value of the Scrollbar. If this value is below the current minimum or above the current maximum minus the visible amount, it becomes the new one of those values, respectively.
See Also:
/** * Sets the value of this Scrollbar to the specified value. * @param value the new value of the Scrollbar. If this value is * below the current minimum or above the current maximum minus * the visible amount, it becomes the new one of those values, * respectively. * @see #getValue */
synchronized void setValue(int newValue) { /* Use setValues so that a consistent policy * relating minimum, maximum, and value is enforced. */ setValues(newValue, vis, min, max); }
Returns the minimum value of this Scrollbar.
See Also:
/** * Returns the minimum value of this Scrollbar. * @see #getMaximum * @see #getValue */
int getMinimum() { return min; }
Sets the minimum value for this Scrollbar.
Params:
  • minimum – the minimum value of the scrollbar
/** * Sets the minimum value for this Scrollbar. * @param minimum the minimum value of the scrollbar */
synchronized void setMinimum(int newMinimum) { /* Use setValues so that a consistent policy * relating minimum, maximum, and value is enforced. */ setValues(val, vis, newMinimum, max); }
Returns the maximum value of this Scrollbar.
See Also:
/** * Returns the maximum value of this Scrollbar. * @see #getMinimum * @see #getValue */
int getMaximum() { return max; }
Sets the maximum value for this Scrollbar.
Params:
  • maximum – the maximum value of the scrollbar
/** * Sets the maximum value for this Scrollbar. * @param maximum the maximum value of the scrollbar */
synchronized void setMaximum(int newMaximum) { /* Use setValues so that a consistent policy * relating minimum, maximum, and value is enforced. */ setValues(val, vis, min, newMaximum); }
Returns the visible amount of this Scrollbar.
/** * Returns the visible amount of this Scrollbar. */
int getVisibleAmount() { return vis; }
Sets the visible amount of this Scrollbar, which is the range of values represented by the width of the scroll bar's bubble.
Params:
  • visible – the amount visible per page
/** * Sets the visible amount of this Scrollbar, which is the range * of values represented by the width of the scroll bar's bubble. * @param visible the amount visible per page */
synchronized void setVisibleAmount(int newAmount) { setValues(val, newAmount, min, max); }
Sets the unit increment for this scrollbar. This is the value that will be added (subtracted) when the user hits the unit down (up) gadgets.
Params:
  • unitSize – is the unit size for increment or decrement of the value
/** * Sets the unit increment for this scrollbar. This is the value * that will be added (subtracted) when the user hits the unit down * (up) gadgets. * @param unitSize is the unit size for increment or decrement of the value */
synchronized void setUnitIncrement(int unitSize) { line = unitSize; }
Gets the unit increment for this scrollbar.
/** * Gets the unit increment for this scrollbar. */
int getUnitIncrement() { return line; }
Sets the block increment for this scrollbar. This is the value that will be added (subtracted) when the user hits the block down (up) gadgets.
Params:
  • blockSize – is the block size for increment or decrement of the value
/** * Sets the block increment for this scrollbar. This is the value * that will be added (subtracted) when the user hits the block down * (up) gadgets. * @param blockSize is the block size for increment or decrement of the value */
synchronized void setBlockIncrement(int blockSize) { page = blockSize; }
Gets the block increment for this scrollbar.
/** * Gets the block increment for this scrollbar. */
int getBlockIncrement() { return page; }
Width of the arrow image
/** * Width of the arrow image */
int getArrowWidth() { return getArrowAreaWidth() - 2*ARROW_IND; }
Width of the area reserved for arrow
/** * Width of the area reserved for arrow */
int getArrowAreaWidth() { return arrowArea; } void calculateArrowWidth() { if (barLength < 2*barWidth + MIN_THUMB_H + 2) { arrowArea = (barLength - MIN_THUMB_H + 2*ARROW_IND)/2 - 1; } else { arrowArea = barWidth - 1; } }
Returns the scale factor for the thumbArea ( thumbAreaH / (max - min)).
See Also:
  • getArrowAreaSize
/** * Returns the scale factor for the thumbArea ( thumbAreaH / (max - min)). * @see #getArrowAreaSize */
private double getScaleFactor(){ double f = (double)(barLength - 2*getArrowAreaWidth()) / Math.max(1,(max - min)); return f; }
Method to calculate the scroll thumb's size and position. This is based on CalcSliderRect in ScrollBar.c of Motif source. If we ever cache the thumb rect, we'll need to use a clone in isInThumb().
/** * Method to calculate the scroll thumb's size and position. This is * based on CalcSliderRect in ScrollBar.c of Motif source. * * If we ever cache the thumb rect, we'll need to use a clone in * isInThumb(). */
protected Rectangle calculateThumbRect() { float range; float trueSize; // Area of scroll track float factor; float slideSize; int minSliderWidth; int minSliderHeight; int hitTheWall = 0; int arrAreaH = getArrowAreaWidth(); Rectangle retVal = new Rectangle(0,0,0,0); trueSize = barLength - 2*arrAreaH - 1; // Same if vert or horiz if (alignment == ALIGNMENT_HORIZONTAL) { minSliderWidth = MIN_THUMB_H ; // Base on user-set vis? minSliderHeight = height - 3; } else { // Vertical minSliderWidth = width - 3; minSliderHeight = MIN_THUMB_H ; } // Total number of user units displayed range = max - min; // A naive notion of pixels per user unit factor = trueSize / range; // A naive notion of the size of the slider in pixels // in thermo, slider_size is 0 ans is ignored slideSize = vis * factor; if (alignment == ALIGNMENT_HORIZONTAL) { // Simulating MAX_SCROLLBAR_DIMENSION macro int localVal = (int) (slideSize + 0.5); int localMin = minSliderWidth; if (localVal > localMin) { retVal.width = localVal; } else { retVal.width = localMin; hitTheWall = localMin; } retVal.height = minSliderHeight; } else { // Vertical retVal.width = minSliderWidth; // Simulating MAX_SCROLLBAR_DIMENSION macro int localVal = (int) (slideSize + 0.5); int localMin = minSliderHeight; if (localVal > localMin) { retVal.height = localVal; } else { retVal.height = localMin; hitTheWall = localMin; } } if (hitTheWall != 0) { trueSize -= hitTheWall; // Actual pixels available range -= vis; // Actual range factor = trueSize / range; } if (alignment == ALIGNMENT_HORIZONTAL) { retVal.x = ((int) (((((float) val) - ((float) min)) * factor) + 0.5)) + arrAreaH; retVal.y = 1; } else { retVal.x = 1; retVal.y = ((int) (((((float) val) - ((float) min)) * factor) + 0.5)) + arrAreaH; } // There was one final adjustment here in the Motif function, which was // noted to be for backward-compatibility. It has been left out for now. return retVal; } public String toString() { return getClass() + "[" + width + "x" + height + "," + barWidth + "x" + barLength + "]"; } } class XScrollRepeater implements Runnable {
Time to pause before the first scroll repeat.
/** * Time to pause before the first scroll repeat. */
static int beginPause = 500; // Reminder - make this a user definable property
Time to pause between each scroll repeat.
/** * Time to pause between each scroll repeat. */
static int repeatPause = 100; // Reminder - make this a user definable property
The scrollbar that we sending scrolling.
/** * The scrollbar that we sending scrolling. */
XScrollbar sb;
newScroll gets reset when a new scrollbar gets set.
/** * newScroll gets reset when a new scrollbar gets set. */
boolean newScroll; boolean shouldSkip;
Creates a new scroll repeater.
Params:
  • sb – the scrollbar that this thread will scroll
/** * Creates a new scroll repeater. * @param sb the scrollbar that this thread will scroll */
XScrollRepeater(XScrollbar sb) { this.setScrollbar(sb); newScroll = true; } public void start() { stop(); shouldSkip = false; XToolkit.schedule(this, beginPause); } public void stop() { synchronized(this) { shouldSkip = true; } XToolkit.remove(this); }
Sets the scrollbar.
Params:
  • sb – the scrollbar that this thread will scroll
/** * Sets the scrollbar. * @param sb the scrollbar that this thread will scroll */
public synchronized void setScrollbar(XScrollbar sb) { this.sb = sb; stop(); newScroll = true; } public void run () { synchronized(this) { if (shouldSkip) { return; } } sb.scroll(); XToolkit.schedule(this, repeatPause); } }