/*
 * $Id: JSlider2.java,v 1.9 2000/11/02 21:22:03 dwd Exp $
 */

package sgtplot.pmel.swing;

import javax.swing.*;
import javax.swing.border.EtchedBorder;

import sgtplot.pmel.swing.beans.SliderHandle;
import sgtplot.util.Range;

import java.awt.event.*;
import java.beans.*;
import java.awt.Dimension;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.FontMetrics;
import java.awt.BorderLayout;
import java.awt.Rectangle;
import org.freehep.graphics2d.VectorGraphics;


/**
 * JSlider2 provides the graphical input and feedback
 * for JSlider2Double and JSlider2Date.
 *
 * @author Donald Denbo
 * @version $Revision: 1.9 $, $Date: 2000/11/02 21:22:03 $
 * @see JSlider2Double
 * @see JSlider2Date
**/
public class JSlider2 extends JComponent 
  implements java.io.Serializable {
  protected Range rawRange_;
  protected int handleSize_;
  protected Dimension size_;
  protected int yval_;
  boolean showBorder_;
  boolean twoHandles_;
  boolean alwaysPost_;
  SliderHandle minHandle_, maxHandle_;
  int min_, max_;
  double scale_;
  double minValue_, maxValue_;
  double minOld_, maxOld_;
  String minLabel_, maxLabel_;
  private PropertyChangeSupport changes = new PropertyChangeSupport(this);
  boolean indexed_ = false;
  double[] values_;
  int[] pixels_;
  
  private EtchedBorder eBorder_ = null;
  /**
   * Class for the Date and Double JSlider2 classes. This class creates
   * the slider portion of the JSlider2Date and JSlider2Double classes.
   *
   * @see JSlider2Date
   * @see JSlider2Double
   **/
  public JSlider2() {
    this(true);
    setSize(40,40);
  }

  /**
   * Class for the GeoDate and Double JSlider2 classes. This class creates
   * the slider portion of the JSlider2Date and JSlider2Double classes.
   *
   * @param twoHandles if true create two handles
   * @see JSlider2Date
   * @see JSlider2Double
   **/
  public JSlider2(boolean twoHandles) {
    super();
    
    //{{REGISTER_LISTENERS
    SymMouse aSymMouse = new SymMouse();
    this.addMouseListener(aSymMouse);
    SymMouseMotion aSymMouseMotion = new SymMouseMotion();
    this.addMouseMotionListener(aSymMouseMotion);
    MyComponent aMyComponent = new MyComponent();
    this.addComponentListener(aMyComponent);
    //}}
                
    twoHandles_ = twoHandles;
    showBorder_ = true;
    eBorder_ = new EtchedBorder();
    setBorder(eBorder_);
    handleSize_ = 6;
    alwaysPost_ = false;
        
    size_ = new Dimension(175, 50);        
    rawRange_ = new Range(handleSize_ + 1, size_.width - handleSize_ - 1);
        
    reset();
        
    minLabel_ = Double.toString(minValue_);
    maxLabel_ = Double.toString(maxValue_);
        
    minHandle_ = new SliderHandle(handleSize_, Color.green, SliderHandle.LEFT);
    maxHandle_ = new SliderHandle(handleSize_, Color.red, SliderHandle.RIGHT);
    if(!twoHandles_) 
      minHandle_.setStyle(SliderHandle.SINGLE);
  }
  /**
   * Set the minimum handle value. Valid range 0.0 - 1.0.
   *
   * @param min minimum handle value
   **/
  public void setMinValue(double min) {
    minValue_ = Math.max(min, 0.0);
    if(minOld_ != minValue_) {
      Double tempOld = new Double(minOld_);
      minOld_ = minValue_;
      changes.firePropertyChange("minValue", tempOld, new Double(minValue_));  
    }
    repaint();
  }
  /**
   * Get the minimum handle value. 
   *
   * @return minimum handle value
   **/
  public double getMinValue() {
    return minValue_;
  }
  /**
   * Set the maximum handle value. Valid range 0.0 - 1.0.
   *
   * @param max maximum handle value
   **/
  public void setMaxValue(double max) {
    maxValue_ = Math.min(max, 1.0);
    if(maxOld_ != maxValue_) {
      Double tempOld = new Double(maxOld_);
      maxOld_ = maxValue_;
      changes.firePropertyChange("maxValue", tempOld, new Double(maxValue_));  
    }
    repaint();
  }
  /**
   * Get the maximum handle value.
   *
   * @return maximum handle value
   **/
  public double getMaxValue() {
    return maxValue_;
  } 
  /**
   * Reset the max,min values to the range limits
   **/
  public void reset() {
    maxValue_ = 1.0;
    minValue_ = 0.0;
    maxOld_ = 1.0;
    minOld_ = 0.0;
  }
   
  /**
   * Set the minimum label.
   *
   * @param lab minimum string
   **/
  public void setMinLabel(String lab) {
    minLabel_ = lab;
    repaint();
  }
  /**
   * Get the minimum label.
   *
   * @return the minimum label
   */
  public String getMinLabel() {
    return minLabel_;
  }
  /**
   * Set the maximum label.
   *
   * @param lab maximum string
   **/
  public void setMaxLabel(String lab) {
    maxLabel_ = lab;
    repaint();
  }
  /**
   * Get the maximum label.
   *
   * @return the maximum label
   */
  public String getMaxLabel() {
    return maxLabel_;
  }
  /**
   * Add a property change listener. The properties that fire a property
   * change are "minValue" and "maxValue". The old and new Double objects
   * are set.
   *
   * @param l property change listener
   */
  public void addPropertyChangeListener(PropertyChangeListener l) {
    changes.addPropertyChangeListener(l);
  }
  /**
   * Remove a property change listener.
   *
   * @param l property change listener
   */
  public void removePropertyChangeListener(PropertyChangeListener l) {
    changes.removePropertyChangeListener(l);
  }
  /**
   * Set the two handle mode.
   *
   * @param th if true set two handles
   */
  public void setTwoHandles(boolean th) {
    twoHandles_ = th;
    if(twoHandles_) {
      minHandle_.setStyle(SliderHandle.LEFT);
    } else {
      minHandle_.setStyle(SliderHandle.SINGLE);
    }
    repaint();
  }
  /**
   * Get the two handle flag.
   *
   * @return true if two handles
   */
  public boolean isTwoHandles() {
    return twoHandles_;
  }
  /**
   * Get the two handle flag.
   *
   * @return true if two handles
   */
  public boolean getTwoHandles() {
    return twoHandles_;
  }
  /**
   * Show a border around the slider.
   *
   * @param sb if true show the border
   */
  public void setShowBorder(boolean sb) {
    showBorder_ = sb;
    if(!showBorder_) setBorder(null);
    repaint();
  }
  /**
   * Get border status for the slider.
   *
   * @return true if border is showing
   */
  public boolean isShowBorder() {
    return showBorder_;
  }
  /**
   * Get border status for the slider.
   *
   * @return true if border is showing
   */
  public boolean getShowBorder() {
    return showBorder_;
  }
  /**
   * Set the handle size for the slider.
   *
   * @param sz handle size in pixels
   */
  public void setHandleSize(int sz) {
    if(handleSize_ != sz) {
      handleSize_ = sz;
      minHandle_ = new SliderHandle(handleSize_, Color.green);
      maxHandle_ = new SliderHandle(handleSize_, Color.red);
      repaint();
    }
  }
  /**
   * Get the current slider handle size.
   *
   * @return handle size in pixels
   */
  public int getHandleSize() {
    return handleSize_;
  }
  /**
   * Set the always post flag for the slider. If true any motion of the
   * slider will fire a property change, if false a property change is
   * only caused when the mouse button is released.
   *
   * @param ap if true always post
   */
  public void setAlwaysPost(boolean ap) {
    alwaysPost_ = ap;
  }
  /**
   * Get the always post flag for the slider.
   *
   * @return true if the slider will always post
   */
  public boolean isAlwaysPost() {
    return alwaysPost_;
  }
  /**
   * Get the always post flag for the slider.
   *
   * @return true if the slider will always post
   */
  public boolean getAlwaysPost() {
    return alwaysPost_;
  }
  /**
   * Get the range of the slider. The range is in pixels and is determined from
   * the size of the slider and the sizes of the handles.
   *
   * @return slider range
   **/
  public Range getRawRange() {
    return rawRange_;
  }

  public void setBounds(Rectangle r) {
    super.setBounds(r);
    invalidate();
    doCompute();
  }

  public void setBounds(int x, int y, int w, int h) {
    super.setBounds(x,y,w,h);
    invalidate();
    doCompute();
  }
  /**
   * Set the size of the slider.
   *
   * @param size slider size
   **/
  public void setSize(Dimension size) {
    super.setSize(size);
    invalidate();
    doCompute();
  }
  
  public void setSize(int width, int height) {
    super.setSize(width, height);
    invalidate();
    doCompute();
  }

  public void setIndexed(boolean ind) {
    indexed_ = ind;
  }
  
  public boolean isIndexed() {
    return indexed_;
  }
  
  public void paintComponent(Graphics g) {
    FontMetrics fmet;
    int xs, ys, swidth;
        
    min_ = rawRange_.start + (int)(minValue_*scale_);
    max_ = rawRange_.start + (int)(maxValue_*scale_);

    VectorGraphics g2 = VectorGraphics.create(g);

    g2.setColor(getBackground());
    g2.fillRect(0, 0, size_.width, size_.height);

    g2.setColor(Color.black);
//      if(showBorder_) {
//        g.drawRect(0, 0, size_.width-1, size_.height-1);
//      }
    g2.setColor(Color.black);
    g2.drawLine(rawRange_.start, yval_ - 3, rawRange_.end, yval_ - 3);
    g2.setColor(Color.gray);
    g2.drawLine(rawRange_.start, yval_ - 2, rawRange_.end, yval_ - 2);
    //
    // draw labels
    //
    g2.setColor(Color.black);
    fmet = g.getFontMetrics();
    ys = yval_ - 8;
    xs = rawRange_.start;
    g2.drawString(minLabel_, xs, ys);
    swidth = fmet.stringWidth(maxLabel_);
    xs = rawRange_.end - swidth;
    g2.drawString(maxLabel_, xs, ys);
    //
    // draw handles
    //
    minHandle_.draw(g, min_, yval_);
    if(twoHandles_) maxHandle_.draw(g2, max_, yval_);
  }
        
  public Dimension getMinimumSize() {
    return new Dimension(96,57);
  }
    
  public Dimension getPreferredSize() {
    return new Dimension(200,57);
  }
    
  public Dimension getMaximumSize() {
    return new Dimension(Short.MAX_VALUE,Short.MIN_VALUE);
  }
  
  public void setIndexValues(double[] array) {
    values_ = array;
    indexed_ = true;
    pixels_ = new int[values_.length];
    doCompute();
  }

  void doCompute() {
    size_ = getSize();
    rawRange_.start = 2*handleSize_ + 1;
    rawRange_.end = size_.width - 2*handleSize_ - 1;    
    yval_ = size_.height - 3*handleSize_ - 10;
    scale_ = (double)(rawRange_.end - rawRange_.start);
    if(indexed_) {
      for(int i=0; i < values_.length; i++) {
        pixels_[i] = rawRange_.start + (int)(values_[i]*scale_);
      }
    }
  }
 
  /**
   *
   **/
        
  void doMove(int xpos, boolean forcePost) {
    double value;
    if(xpos > rawRange_.end) xpos = rawRange_.end;
    if(xpos < rawRange_.start) xpos = rawRange_.start;
            
    if(indexed_ && forcePost) {
      int ind = 0;
      if(xpos <= pixels_[0]) {
        ind = 0;
      } else if(xpos >= pixels_[pixels_.length-1]) {
        ind = pixels_.length-1;
      } else {
        for(int i=0; i < pixels_.length - 1; i++) {
          if(xpos >= pixels_[i] && xpos < pixels_[i+1]) {
            if(xpos - pixels_[i] < pixels_[i+1] - xpos) {
              ind = i;
            } else {
              ind = i+1;
            }
            break;
          }
        }
      }
      value = values_[ind];
      xpos = pixels_[ind];
    } else {
      value = (double)(xpos - rawRange_.start)/scale_;
    }
    
    if(twoHandles_) {
      int toMin = xpos - min_;
      int toMax = xpos - max_;
      if(toMin < 0) {
        minValue_ = value;
      } else if(toMax > 0) {
        maxValue_ = value;
      } else if(toMin < -toMax) {
        minValue_ = value;
      } else {
        maxValue_ = value;
      }
    } else 
      minValue_ = value;
      
    if(forcePost || alwaysPost_) {
      if(minOld_ != minValue_) {
        Double tempOld = new Double(minOld_);
        minOld_ = minValue_;
        changes.firePropertyChange("minValue", tempOld, new Double(minValue_));
      }
      if(maxOld_ != maxValue_) {
        Double tempOld = new Double(maxOld_);
        maxOld_ = maxValue_;
        changes.firePropertyChange("maxValue", tempOld, new Double(maxValue_));
      }
    }
    paint(getGraphics());
  }

  class SymMouse extends MouseAdapter {
    public void mouseReleased(MouseEvent event) {
      Object object = event.getSource();
      if (object == JSlider2.this)
        JSlider2_MouseRelease(event);
    }

    public void mouseClicked(MouseEvent event) {
      Object object = event.getSource();
      if (object == JSlider2.this)
        JSlider2_MouseClick(event);
    }
  }

  void JSlider2_MouseClick(MouseEvent event) {
    doMove(event.getX(), true);
  }

  class MyComponent extends ComponentAdapter {
    public void componentResized(ComponentEvent event) {
      Object object = event.getSource();
      if(object == JSlider2.this)
        JSlider2_resized(event);
    }
  }
  
  void JSlider2_resized(ComponentEvent event) {
    doCompute();
  }
  
  class SymMouseMotion extends MouseMotionAdapter {
    public void mouseDragged(MouseEvent event) {
      Object object = event.getSource();
      if (object == JSlider2.this)
        JSlider2_MouseDrag(event);
    }
  }

  void JSlider2_MouseDrag(MouseEvent event) {
    doMove(event.getX(), false);
  }
  

  void JSlider2_MouseRelease(MouseEvent event) {
    doMove(event.getX(), true);
  }
  
  public static void main(String[] args) {
    double[] values = {0.0, 0.1, 0.2, 0.3, 0.4,
		       0.5, 0.6, 0.7, 0.8, 0.9, 1.0};
    JFrame jf = new JFrame("JSlider2 Test");
    jf.setSize(400,100);
    jf.getContentPane().setLayout(new BorderLayout());
    JSlider2 js2 = new JSlider2();
    //
    // valid range of slider is 0-1
    //
    js2.setDoubleBuffered(true);
    js2.setMinValue(0.2);
    js2.setMaxValue(0.8);
    js2.setIndexValues(values);
    js2.setMinLabel("-20 stuff");
    js2.setMaxLabel("20 stuff");
    jf.getContentPane().add(js2, BorderLayout.CENTER);
    jf.setVisible(true);
  }
}

 

Ads help maintain this website.