/* * EZSlider.java * JCollider * * Copyright (c) 2004-2010 Hanns Holger Rutz. All rights reserved. * * This software is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either * version 2, june 1991 of the License, or (at your option) any later version. * * This software 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 for more details. * * You should have received a copy of the GNU General Public * License (gpl.txt) along with this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * * For further information, please contact Hanns Holger Rutz at * contact@sciss.de , or visit http://www.sciss.de/jcollider * * * JCollider is closely modelled after SuperCollider Language, * often exhibiting a direct translation from Smalltalk to Java. * SCLang is a software originally developed by James McCartney, * which has become an Open Source project. * See http://www.audiosynth.com/ for details. * * * Changelog: * 29-Jul-06 created */ package de.sciss.jcollider.gui; import java.awt.AWTEventMulticaster; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JSlider; import javax.swing.SwingConstants; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; /** * Something similar to SClang's EZSlider: a combo of * horizontal slider, number box and label. * * @author Hanns Holger Rutz * @version 0.32, 25-Feb-08 */ public class EZSlider extends JComponent { private final Object sync = new Object(); private ActionListener actionListener = null; protected ControlSpec spec; protected double value = 0.0; private final JLabel ggLabel; protected final JSlider ggSlider; protected final NumberField ggNumber; private final JLabel ggUnits; public EZSlider() { super(); final GridBagLayout lay = new GridBagLayout(); final GridBagConstraints con = new GridBagConstraints(); setLayout( lay ); // con.anchor = GridBagConstraints.WEST; con.fill = GridBagConstraints.HORIZONTAL; // con.ipadx = 2; con.insets = new Insets( 0, 2, 0, 2 ); setLayout( lay ); ggLabel = new JLabel( (String) null, SwingConstants.RIGHT ); con.weightx = 0.0; lay.setConstraints( ggLabel, con ); add( ggLabel ); ggSlider = new JSlider( 0, 0x10000 ); ggSlider.setMaximumSize( new Dimension( 0x10000, ggSlider.getMaximumSize().height )); con.weightx = 1.0; lay.setConstraints( ggSlider, con ); add( ggSlider ); ggNumber = new NumberField(); con.weightx = 0.0; lay.setConstraints( ggNumber, con ); add( ggNumber ); ggUnits = new JLabel(); // con.weightx = 0.0; lay.setConstraints( ggUnits, con ); add( ggUnits ); //setBackground( java.awt.Color.red ); //setBorder( javax.swing.BorderFactory.createMatteBorder( 2, 2, 2, 2, java.awt.Color.blue )); setControlSpec( ControlSpec.defaultSpec ); //System.err.println( "kieka" ); ggNumber.addListener( new NumberListener() { public void numberChanged( NumberEvent e ) { value = e.getNumber().doubleValue(); ggSlider.setValue( (int) (spec.unmap( value ) * 0x10000) ); dispatchEvent(); } }); ggSlider.addChangeListener( new ChangeListener() { public void stateChanged( ChangeEvent e ) { value = spec.map( (double) ggSlider.getValue() / 0x10000 ); ggNumber.setNumber( new Double( value )); dispatchEvent(); } }); } public static void align( EZSlider[] ez ) { int maxLabelWidth = 0; int maxNumberWidth = 0; int maxUnitsWidth = 0; for( int i = 0; i < ez.length; i++ ) { maxLabelWidth = Math.max( maxLabelWidth, ez[ i ].ggLabel.getPreferredSize().width ); maxNumberWidth = Math.max( maxNumberWidth, ez[ i ].ggNumber.getPreferredSize().width ); maxUnitsWidth = Math.max( maxUnitsWidth, ez[ i ].ggUnits.getPreferredSize().width ); } for( int i = 0; i < ez.length; i++ ) { ez[ i ].setLabelWidth( maxLabelWidth ); ez[ i ].setNumberWidth( maxNumberWidth ); ez[ i ].setUnitsWidth( maxUnitsWidth ); // System.err.println( "Aligning ... "+maxLabelWidth+"; "+maxNumberWidth+"; "+maxUnitsWidth ); } } public void setLabelWidth( int width ) { setComponentWidth( ggLabel, width ); } public void setSliderWidth( int width ) { setComponentWidth( ggSlider, width ); } public void setNumberWidth( int width ) { setComponentWidth( ggNumber, width ); ggNumber.setColumns( 0 ); } public void setUnitsWidth( int width ) { setComponentWidth( ggUnits, width ); } private void setComponentWidth( JComponent c, int width ) { c.setSize( width, c.getHeight() ); c.setPreferredSize( new Dimension( width, c.getPreferredSize().height )); c.setMinimumSize( new Dimension( width, c.getMinimumSize().height )); c.setMaximumSize( new Dimension( width, c.getMaximumSize().height )); } public void setLabel( String label ) { ggLabel.setText( label ); } public String getLabel() { return ggLabel.getText(); } public void setControlSpec( ControlSpec spec ) { this.spec = spec; ggNumber.setSpace( new NumberSpace( spec.getMinVal(), spec.getMaxVal(), spec.getStep() )); ggUnits.setText( spec.getUnits() ); } public void addActionListener( ActionListener l ) { synchronized( sync ) { actionListener = AWTEventMulticaster.add( actionListener, l ); } } public void removeActionListener( ActionListener l ) { synchronized( sync ) { actionListener = AWTEventMulticaster.remove( actionListener, l ); } } protected void dispatchEvent() { final ActionListener l = actionListener; if( l != null ) { l.actionPerformed( new ActionEvent( this, ActionEvent.ACTION_PERFORMED, null )); } } public double getValue() { return value; } public double getUnmappedValue() { return spec.unmap( value ); } public void setValue( double value ) { this.value = spec.constrain( value ); ggSlider.setValue( (int) (spec.unmap( value ) * 0x10000) ); ggNumber.setNumber( new Double( value )); } public void setUnmappedValue( double value ) { setValue( spec.map( value )); } public void setValueAction( double value ) { setValue( value ); dispatchEvent(); } }