/* * Created on 26-Jul-2004 by Ryan McNally */ package com.ryanm.config.swing.imp; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.SwingConstants; import javax.swing.border.CompoundBorder; import javax.swing.border.EmptyBorder; import javax.swing.border.LineBorder; import javax.swing.border.TitledBorder; import javax.vecmath.Tuple3f; import com.ryanm.config.Configurator; import com.ryanm.config.swing.Widget; import com.ryanm.util.swing.FloatChooser; import com.ryanm.util.swing.PointChooser; /** * A widget for editing a 3-dimensional tuple * * @author ryanm */ public class Tuple3fWidget extends Widget implements FloatChooser.Listener, PointChooser.Listener { private Tuple3f current; private JPanel cardPanel = new JPanel(); private CardLayout cardLayout = new CardLayout(); private CardSwitcher cardSwitcher = new CardSwitcher(); private Box sliderPanel = new Box( BoxLayout.Y_AXIS ); private JLabel xLabel; private FloatChooser xChooser; private JLabel yLabel; private FloatChooser yChooser; private JLabel zLabel; private FloatChooser zChooser; private JPanel pointChooserPanel = null; private PointChooser xyChooser; private PointChooser xzChooser; private PointChooser zyChooser; private JLabel coordLabel; /** * Standard constructor * * @param conf * The configurator object * @param name * The name of the variable to bind to */ public Tuple3fWidget( Configurator conf, String name ) { super( conf, name ); xLabel = new JLabel( " X " ); xChooser = new FloatChooser( null, null, 0 ); yLabel = new JLabel( " Y " ); yChooser = new FloatChooser( null, null, 0 ); zLabel = new JLabel( " Z " ); zChooser = new FloatChooser( null, null, 0 ); current = ( Tuple3f ) conf.getValue( name ); // add range listeners xLabel.addMouseListener( xChooser.getRangeAdjustListener() ); yLabel.addMouseListener( yChooser.getRangeAdjustListener() ); zLabel.addMouseListener( zChooser.getRangeAdjustListener() ); Box xbox = new Box( BoxLayout.X_AXIS ); xbox.add( xLabel ); xbox.add( xChooser ); Box ybox = new Box( BoxLayout.X_AXIS ); ybox.add( yLabel ); ybox.add( yChooser ); Box zbox = new Box( BoxLayout.X_AXIS ); zbox.add( zLabel ); zbox.add( zChooser ); xChooser.setValue( current.x ); yChooser.setValue( current.y ); zChooser.setValue( current.z ); xChooser.addListener( this ); yChooser.addListener( this ); zChooser.addListener( this ); sliderPanel.add( xbox ); sliderPanel.add( ybox ); sliderPanel.add( zbox ); cardPanel.setLayout( cardLayout ); cardPanel.add( sliderPanel, "sliders" ); setLayout( new BorderLayout() ); add( cardPanel, BorderLayout.CENTER ); setBorder( new TitledBorder( name ) ); setRange( conf.getRange( name ) ); setEnabled( conf.isGUIEnabled( name ) ); } /** * * */ public Tuple3fWidget() { } @Override public void updateValue() { synchronized( lock ) { Object value = conf.getValue( name ); xChooser.removeListener( this ); yChooser.removeListener( this ); zChooser.removeListener( this ); current = ( Tuple3f ) value; xChooser.setValue( current.x ); yChooser.setValue( current.y ); zChooser.setValue( current.z ); xChooser.addListener( this ); yChooser.addListener( this ); zChooser.addListener( this ); } } public void valueChanged( float value ) { // copy to current float x = xChooser.getValue(); float y = yChooser.getValue(); float z = zChooser.getValue(); // set the variable setVariable( x, y, z ); } public void pointChanged( float x, float y, PointChooser chooser ) { float nx = xChooser.getValue(); float ny = yChooser.getValue(); float nz = zChooser.getValue(); if( chooser == xyChooser ) { nx = xyChooser.getPointX(); ny = xyChooser.getPointY(); } else if( chooser == xzChooser ) { nx = xzChooser.getPointX(); nz = xzChooser.getPointY(); } else if( chooser == zyChooser ) { nz = zyChooser.getPointX(); ny = zyChooser.getPointY(); } else { assert false; } setVariable( nx, ny, nz ); } /** * Keeps the components synced * * @param x * @param y * @param z */ private void setVariable( float x, float y, float z ) { float f = 100000.0f; x = Math.round( x * f ) / f; y = Math.round( y * f ) / f; z = Math.round( z * f ) / f; if( x != current.x || y != current.y || z != current.z ) { current.x = x; current.y = y; current.z = z; xChooser.removeListener( this ); yChooser.removeListener( this ); zChooser.removeListener( this ); xChooser.setValue( x ); yChooser.setValue( y ); zChooser.setValue( z ); xChooser.addListener( this ); yChooser.addListener( this ); zChooser.addListener( this ); if( xyChooser != null ) { xyChooser.removeListener( this ); xzChooser.removeListener( this ); zyChooser.removeListener( this ); xyChooser.setPoint( x, y ); xzChooser.setPoint( x, z ); zyChooser.setPoint( z, y ); xyChooser.addListener( this ); xzChooser.addListener( this ); zyChooser.addListener( this ); coordLabel.setText( "( " + current.x + ", " + current.y + ", " + current.z + " )" ); } applyChange( conf, name, current ); } } public void rangeChanged( float low, float high ) { // not sure if I care } @Override public void setEnabled( boolean b ) { xLabel.setEnabled( b ); xChooser.setEnabled( b ); yLabel.setEnabled( b ); yChooser.setEnabled( b ); zLabel.setEnabled( b ); zChooser.setEnabled( b ); super.setEnabled( b ); } @Override public void updateRange( Object range ) { range = conf.getRange( name ); if( range != null && range instanceof float[] ) { float[] array = ( float[] ) range; xChooser.setRange( array.length > 0 ? array[ 0 ] : Float.NaN, array.length > 3 ? array[ 3 ] : Float.NaN ); yChooser.setRange( array.length > 1 ? array[ 1 ] : Float.NaN, array.length > 4 ? array[ 4 ] : Float.NaN ); zChooser.setRange( array.length > 2 ? array[ 2 ] : Float.NaN, array.length > 5 ? array[ 5 ] : Float.NaN ); } else { xChooser.setRange( Float.NaN, Float.NaN ); yChooser.setRange( Float.NaN, Float.NaN ); zChooser.setRange( Float.NaN, Float.NaN ); } if( pointChooserPanel != null ) { xyChooser.removeListener( this ); xzChooser.removeListener( this ); zyChooser.removeListener( this ); cardPanel.remove( pointChooserPanel ); remove( cardSwitcher ); } float[] xr = xChooser.getRange(); float[] yr = yChooser.getRange(); float[] zr = zChooser.getRange(); if( !Float.isNaN( xr[ 0 ] ) && !Float.isNaN( xr[ 1 ] ) && !Float.isNaN( yr[ 0 ] ) && !Float.isNaN( yr[ 1 ] ) && !Float.isNaN( zr[ 0 ] ) && !Float.isNaN( zr[ 1 ] ) ) { pointChooserPanel = new JPanel(); pointChooserPanel.setLayout( new BorderLayout() ); xyChooser = new PointChooser( xr[ 0 ], yr[ 0 ], xr[ 1 ], yr[ 1 ] ); xzChooser = new PointChooser( xr[ 0 ], zr[ 0 ], xr[ 1 ], zr[ 1 ] ); zyChooser = new PointChooser( zr[ 0 ], yr[ 0 ], zr[ 1 ], yr[ 1 ] ); xyChooser.setLabel( "X/Y" ); xzChooser.setLabel( "X/Z" ); zyChooser.setLabel( "Z/Y" ); xyChooser.setPoint( current.x, current.y ); xzChooser.setPoint( current.x, current.z ); zyChooser.setPoint( current.z, current.y ); xyChooser.addListener( this ); xzChooser.addListener( this ); zyChooser.addListener( this ); Box pcb = new Box( BoxLayout.X_AXIS ); pcb.add( xyChooser ); pcb.add( Box.createHorizontalStrut( 2 ) ); pcb.add( xzChooser ); pcb.add( Box.createHorizontalStrut( 2 ) ); pcb.add( zyChooser ); pcb.setBorder( new EmptyBorder( 0, 0, 2, 0 ) ); pointChooserPanel.add( pcb, BorderLayout.CENTER ); coordLabel = new JLabel( "( " + current.x + ", " + current.y + ", " + current.z + " )" ); coordLabel.setHorizontalAlignment( SwingConstants.CENTER ); coordLabel.setBorder( new CompoundBorder( new LineBorder( Color.gray ), new EmptyBorder( 4, 4, 4, 4 ) ) ); pointChooserPanel.add( coordLabel, BorderLayout.SOUTH ); pointChooserPanel.setBorder( new EmptyBorder( 0, 2, 0, 0 ) ); cardPanel.add( pointChooserPanel, "points" ); add( cardSwitcher, BorderLayout.WEST ); } validate(); } @Override public Widget newWidget( Configurator conf, String name, Class runtimeType ) { return new Tuple3fWidget( conf, name ); } @Override public Class getType() { return Tuple3f.class; } private class CardSwitcher extends JComponent implements MouseListener { boolean over = false; private CardSwitcher() { addMouseListener( this ); setPreferredSize( new Dimension( 20, 20 ) ); setBorder( new LineBorder( Color.gray ) ); } @Override protected void paintComponent( Graphics g ) { g.setColor( over ? Color.lightGray : Color.white ); g.fillRect( 1, 1, getWidth() - 2, getHeight() - 2 ); Graphics2D g2d = ( Graphics2D ) g.create(); String s = "Switch controls"; Rectangle2D sb = g2d.getFontMetrics().getStringBounds( s, g2d ); double x = getWidth() / 2 + sb.getHeight() / 2 - 3; double y = getHeight() / 2 + sb.getWidth() / 2; AffineTransform at = AffineTransform.getTranslateInstance( x, y ); at.rotate( -Math.PI / 2 ); g2d.transform( at ); g2d.setColor( Color.black ); g2d.drawString( s, 0, 0 ); } public void mouseEntered( MouseEvent e ) { over = true; repaint(); } public void mouseExited( MouseEvent e ) { over = false; repaint(); } public void mouseClicked( MouseEvent e ) { } public void mousePressed( MouseEvent e ) { } public void mouseReleased( MouseEvent e ) { cardLayout.next( cardPanel ); } } }