Package de.sciss.swingosc

Source Code of de.sciss.swingosc.MultiSlider$MouseAdapter

/*
*  MultiSlider.java
*  SwingOSC
*
*  Copyright (c) 2005-2011 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
*
*
*  Changelog:
*    27-Oct-06  created
*    05-Feb-07  extends AbstractMultiSlider
*/

package de.sciss.swingosc;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.InputEvent;
import java.awt.event.MouseEvent;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.io.IOException;
import javax.swing.event.MouseInputAdapter;

import de.sciss.net.OSCMessage;

/**
*  Swing implementation of SCMultiSliderView by Jan Truetzschler.
*
@author    Hanns Holger Rutz
@author    Tim Blechmann
@version  0.64, 14-Mar-10
*/
public class MultiSlider
extends AbstractMultiSlider
{
  protected float    thumbWidth     = 12f;
  protected float    thumbHeight    = 12f;
  private Color    fillColor     = Color.black;
  private Color    indexColor     = new Color( 0x00, 0x00, 0x00, 0x55 );
  private boolean   hasFill      = true;
  private float    xOffset      = 1f;
  protected float    xStep      = 13f;
  protected boolean  showIndex    = false;
  protected boolean  isFilled    = false;
  protected boolean  horizontal    = true;
  protected boolean  readOnly    = false;
 
  protected float[]  values      = new float[ 0 ];
  protected int    startIndex    = 0;
  private float[][]  drawValues    = new float[][] { values };
 
  protected int    dirtyStart    = -1;
  protected int    dirtyStop    = -1;

  protected int    selectedIndex  = -1;
  protected int    selectionSize  = 1;

  private static final double  PIH = Math.PI / 2;
//  protected static final int precisionModifier = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
  protected static final int precisionModifier = SwingOSC.isMacOS() ?
    InputEvent.META_MASK : InputEvent.CTRL_MASK | InputEvent.ALT_MASK; 

  protected boolean  steady      = false;
  protected float    highPrecision  = 0.05f;
 
//  private static final Stroke strkOutline =
//    new BasicStroke( 1f, BasicStroke.CAP_ROUND, BasicStroke.CAP_ROUND );

  public MultiSlider()
  {
    super();
//    setOpaque( true );

    final MouseAdapter ma = new MouseAdapter();
    addMouseListener( ma );
    addMouseMotionListener( ma );
  }
 
  protected void paintKnob( Graphics2D g2, int cw, int ch )
  {
//    final AffineTransform  atOrig  = g2.getTransform();
    final Shape        clipOrig  = g2.getClip();
    final int        h, w;
    final float        hm;
    final Rectangle2D    r  = new Rectangle2D.Float();
    final RoundRectangle2D  rr;
    float          thumbWidth, thumbWidthH, xOffset, xStep;
    float          x, y, y2, lastX;
    GeneralPath        gpOutline, gpFill, gpLines;
    float[]          values;
    int            numValues;
   
//    g2.setColor( getBackground() );
//    g2.fillRect( 0, 0, getWidth(), getHeight() );
//    g2.clearRect( 0, 0, getWidth(), getHeight() );

    cw -= 2;
    ch -= 2;
    g2.translate( 1, 1 );
    g2.clipRect( 0, 0, cw, ch );
//    cw -= 2;
//    ch -= 2;
   
    g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
   
    if( horizontal ) {
      w  = cw; // getWidth() - 2;
      h  = ch; // getHeight() - 2;
      g2.translate( 0, h );
      g2.scale( 1f, -1f );
    } else {
      w  = ch; // getHeight() - 2;
      h  = cw; // getWidth() - 2;
//      g2.translate( 1, 1 );
      g2.scale( -1f, 1f );
      g2.rotate( PIH, 0, 0 );
    }
    hm      = h - thumbHeight;
   
    gpOutline   = new GeneralPath();
    gpFill     = new GeneralPath();
    gpLines    = new GeneralPath();
    rr      = new RoundRectangle2D.Float( 0f, 0f, 0f, 0f, 2f, 2f );

    for( int n = drawValues.length - 1; n >= 0; n-- ) {
      values    = drawValues[ n ];
      numValues  = values.length;
      if( elasticResize ) {
        final float scale = w / (numValues * this.xStep);
        thumbWidth  = this.thumbWidth; // * scale;
        xOffset    = this.xOffset * scale;
        xStep    = this.xStep * scale;
      } else {
        thumbWidth  = this.thumbWidth;
        xOffset    = this.xOffset;
        xStep    = this.xStep;
      }
      thumbWidthH = thumbWidth * 0.5f;
     
      if( drawLines && (values.length > 0) ) {
        y2  = values[ 0 ] * hm + thumbHeight + 1;
        gpLines.moveTo( thumbWidthH, y2 );
      }
      lastX = 0f;
      for( int i = 0, j = startIndex; j < numValues; i++, j++ ) {
        x  = i * xStep;
        if( lastX > w ) break;
        y  = values[ j ] * hm;
        y2  = y + thumbHeight;
        if( isFilled ) {
          r.setFrame( x, -1f, thumbWidth, y2 + 1 );
          rr.setFrame( x - 0.5f, -0.5f, thumbWidth, y2 + 1 );
        } else {
          r.setFrame( x, y, thumbWidth, thumbHeight );
          rr.setFrame( x - 0.5f, y + 0.5f, thumbWidth, thumbHeight );
        }
        if( drawRects ) {
          if( hasFill ) gpFill.append( r, false );
          if( hasStroke ) gpOutline.append( rr, false );
        }
        if( drawLines ) {
          gpLines.lineTo( x + thumbWidthH, y2 );
        }
        lastX = x;
      }
      if( drawLines && isFilled && (numValues > 0) ) {
        x  = (numValues - 1 - startIndex) * xStep;
        y2  = values[ numValues - 1 ] * hm + thumbHeight;
        gpLines.lineTo( x + thumbWidthH, y2 );
        gpLines.closePath();
      }
      if( hasFill ) {
        g2.setColor( fillColor );
        g2.fill( gpFill );
      }
      if( hasStroke ) {
        g2.setColor( strokeColor );
  //      g2.setStroke( strkOutline );
        g2.draw( gpOutline );
      }
      if( drawLines ) {
        if( isFilled ) {
          g2.setColor( fillColor );
          g2.fill( gpLines );
        } else {
          g2.setColor( strokeColor );
          g2.draw( gpLines );
        }
      }
      if( showIndex && (selectedIndex >= 0) && (n == 0) ) {
        r.setFrame( (selectedIndex - startIndex) * xStep, 0, selectionSize * xStep - xOffset, h );
        g2.setColor( indexColor );
        g2.fill( r );
      }
    }
//    g2.setTransform( atOrig );
    g2.setClip( clipOrig );
  }
 
  public void setValues( float[] values )
  {
    this.values  = values;
    if( selectedIndex >= 0 ) {
      selectedIndex = Math.min( selectedIndex, values.length - 1 );
      selectionSize = Math.min( selectionSize, values.length - selectedIndex );
    }
    drawValues[ 0 ] = values;
    repaint();
  }

  public void setValues( Object[] values )
  {
    final float[] fValues = new float[ values.length ];
    for( int i = 0; i < values.length; i++ ) {
      fValues[ i ] = ((Number) values[ i ]).floatValue();
    }
    setValues( fValues );
  }
 
  public float[] getValues()
  {
    return values;
  }
 
  public void setReferenceValues( float[] refValues )
  {
    if( (refValues != null) && (refValues.length > 0) ) {
      drawValues = new float[][] { values, refValues };
    } else {
      drawValues = new float[][] { values };
    }
    repaint();
  }

  public void setReferenceValues( Object[] values )
  {
    final float[] fValues = new float[ values.length ];
    for( int i = 0; i < values.length; i++ ) {
      fValues[ i ] = ((Number) values[ i ]).floatValue();
    }
    setReferenceValues( fValues );
  }
 
  public void sendValues( Object id, int offset, int num )
  {
    offset   = Math.max( 0, Math.min( values.length - 1, offset ));
    num    = Math.min( values.length - offset, num );

    final SwingOSC    osc      = SwingOSC.getInstance();
    final SwingClient  client    = osc.getCurrentClient();
    final Object[]     replyArgs  = new Object[ 3 + num ];
    replyArgs[ 0 ]          = id;
    replyArgs[ 1 ]          = new Integer( offset );
    replyArgs[ 2 ]          = new Integer( num );

    for( int i = offset, j = 3; j < replyArgs.length; i++, j++ ) {
      replyArgs[ j ]        = new Float( values[ i ]);
    }
   
    try {
      client.reply( new OSCMessage( "/values", replyArgs ));
    }
    catch( IOException ex ) {
      SwingOSC.printException( ex, "sendValues" );
    }
  }
 
  public void sendValuesAndClear( Object id )
  {
    sendValues( id, dirtyStart, dirtyStop - dirtyStart );
    clearDirty();
  }
 
  public void setThumbWidth( float w )
  {
    thumbWidth  = w;
//    thumbWidthH  = w / 2;
    xStep    = thumbWidth + xOffset;
    hasStroke  = (strokeColor.getAlpha() > 0x00) && (thumbWidth > 1);
    repaint();
  }
 
  public float getThumbWidth()
  {
    return thumbWidth;
  }

  public void setThumbHeight( float h )
  {
    thumbHeight = h;
    repaint();
  }
 
  public float getThumbHeight()
  {
    return thumbHeight;
  }
 
  public void setThumbSize( float size )
  {
    setThumbWidth( size );
    setThumbHeight( size );
  }

  public void setFillColor( Color c )
  {
    fillColor  = c;
    hasFill    = fillColor.getAlpha() > 0x00;
    indexColor  = new Color( fillColor.getRed(), fillColor.getGreen(), fillColor.getBlue(),
            fillColor.getAlpha() / 3 );
    repaint();
  }
 
  public Color getFillColor()
  {
    return fillColor;
  }

  public void setStrokeColor( Color c )
  {
    strokeColor  = c;
    hasStroke  = (strokeColor.getAlpha() > 0x00) && (thumbWidth > 1);
    repaint();
  }
 
  public Color getStrokeColor()
  {
    return strokeColor;
  }

  public void setXOffset( float off )
  {
    xOffset  = off;
    xStep  = thumbWidth + xOffset;
    repaint();
  }
 
  public float getXOffset()
  {
    return xOffset;
  }
 
  public void setShowIndex( boolean onOff )
  {
    showIndex  = onOff;
    repaint();
  }
 
  public boolean getShowIndex()
  {
    return showIndex;
  }
 
  public void setFilled( boolean onOff )
  {
    isFilled  = onOff;
    repaint();
  }

  public boolean getFilled()
  {
    return isFilled;
  }
 
  public void setOrientation( int orient )
  {
    if( orient == HORIZONTAL ) {
      horizontal = true;
    } else if( orient == VERTICAL ) {
      horizontal = false;
    } else {
      throw new IllegalArgumentException( String.valueOf( orient ));
    }
  }
 
  public int getOrientation()
  {
    return horizontal ? HORIZONTAL : VERTICAL;
  }

  public void setStepSize( float stepSize )
  { 
    super.setStepSize( stepSize );
   
    if( stepSize > 0f ) {
      for( int i = 0; i < values.length; i++ ) {
        values[ i ] = snap( values[ i ]);
      }
      repaint();
    }
  }

  public void setStartIndex( int idx )
  {
    startIndex  = Math.max( 0, idx );
    repaint();
  }
 
  public int getStartIndex()
  {
    return startIndex;
  }

  public void setReadOnly( boolean onOff )
  {
    readOnly  = onOff;
  }

  public boolean getReadOnly()
  {
    return readOnly;
  }
 
  public void setSelectedIndex( int idx )
  {
    selectedIndex = idx;
    if( showIndex ) repaint();
  }
 
  public int getSelectedIndex()
  {
    return selectedIndex;
  }

  public void setSelectionSize( int numIndices )
  {
    selectionSize = numIndices;
    if( showIndex ) repaint();
  }
 
  public int getSelectionSize()
  {
    return selectionSize;
  }
 
  public int getDirtyIndex()
  {
    return dirtyStart;
  }
 
  public int getDirtySize()
  {
    return( dirtyStop - dirtyStart );
  }
 
  public void clearDirty()
  {
    dirtyStart   = -1;
    dirtyStop  = -1;
  }

  public boolean getSteady()
  {
    return steady;
  }
 
  public void setSteady( boolean stdy )
  {
    steady = stdy;
  }
 
  public float getPrecision()
  {
    return highPrecision;
  }
 
  public void setPrecision( float hghPrcsn )
  {
    highPrecision = hghPrcsn;
  }

  // --------------- internal classes ---------------
 
  private class MouseAdapter
  extends MouseInputAdapter
  {
    private boolean  dragExtend    = false;
    private int    lastDragIdx    = -1;
    private boolean  dragExtendDir  = false;
    private float  lastDragY    = 0.f;

    protected MouseAdapter() { /* empty */ }
   
    private float computeVal( MouseEvent e, float y, float h, int dragIdx, boolean isDrag )
    {
      if( steady && (lastDragIdx == -1) ) {
        return values[ dragIdx ];
      }
      final boolean meta = (e.getModifiers() & precisionModifier) == precisionModifier;
      final float valueRaw;
      if( steady || (meta && isDrag )) {
        // todo: how to handle sliders index changes?
        //
        // if (lastDragIdx != dragIdx) lastDragIdx = dragIdx;
       
        final float precisionFactor = meta ? highPrecision : 1f;

        final float lastVal = values[ lastDragIdx ];
        final float diffY  = y - lastDragY;
 
        final float diffVal = (diffY * precisionFactor) / (h - thumbHeight);
        valueRaw = lastVal + diffVal;
      } else {
        final float localThumbHeight = isFilled ? thumbHeight : thumbHeight / 2;
        valueRaw = (y - localThumbHeight) / (h - thumbHeight);
      }
      return Math.max( 0f, Math.min( 1f, valueRaw ));
    }

    private void processMouse( MouseEvent e, boolean init )
    {
      if( values.length == 0 ) return;
     
      final int     x, w, y, h;
      final Insets  ins  = getInsets();
      final float   scale, xSub, value;
      final int     dragIdx, dragIdx2;
      final int     newSelStop;
      boolean      action  = false;
      boolean      repaint  = false;
 
      if( horizontal ) {
        w  = getWidth() - ins.left - ins.right - 2;
        h  = getHeight() - ins.top - ins.bottom - 2;
        x  = e.getX() - ins.left - 1;
        y  = h - (e.getY() - ins.top - 1);
      } else {
        h  = getWidth() - ins.left - ins.right - 2;
        w  = getHeight() - ins.top - ins.bottom - 2;
        x  = e.getY() - ins.top - 1;       
        y  = e.getX() - ins.left - 1;
      }
//      if( isFilled ) {
//        val  = Math.max( 0f, Math.min( 1f, (y - thumbHeight) / (h - thumbHeight) ));
//      } else {
//        val  = Math.max( 0f, Math.min( 1f, (y - thumbHeight/2) / (h - thumbHeight) ));
//      }

      if( elasticResize ) {
        scale   = values.length / (float) w;
        xSub  = thumbWidth/2 * (w / (values.length * xStep));
      } else {
        scale   = 1 / xStep;
        xSub  = thumbWidth/2;
      }
      dragIdx2  = (int) ((x - xSub) * scale + 0.5f) + startIndex;
      dragIdx    = Math.max( 0, Math.min( values.length - 1, dragIdx2 ));
      // values might have been modified!!!
      if( lastDragIdx >= values.length ) lastDragIdx = -1;
      if( init ) dragExtend = e.isShiftDown();
     
      value = computeVal( e, y, h, dragIdx, !init );
      lastDragY = y;
     
      if( dragExtend ) {
        if( selectedIndex >= 0 ) {
          if( init ) dragExtendDir = dragIdx2 > (selectedIndex + (selectionSize >> 1));
          if( dragExtendDir ) {
            newSelStop = dragIdx2; // + 1;
            if( newSelStop != selectedIndex + selectionSize ) {
              selectionSize  = newSelStop - selectedIndex;
              if( selectionSize < 0 ) {
                selectionSize = -selectionSize;
                selectedIndex = newSelStop - selectionSize + 1;
                dragExtendDir  = !dragExtendDir;
//                System.out.println( "A ");
              }
              selectedIndex  = Math.max( 0, Math.min( values.length - 1, selectedIndex ));
              selectionSize   = Math.min( values.length - selectedIndex, selectionSize );
              action  = true;
              repaint  |= showIndex;
            }
          } else {
            if( dragIdx != selectedIndex ) {
              selectionSize += selectedIndex - dragIdx2;
              selectedIndex  = dragIdx2;
              if( selectionSize < 0 ) {
//                newSelStop     = selectedIndex + selectionSize;
                selectionSize  = -selectionSize;
                selectedIndex  = dragIdx2 - selectionSize;
                dragExtendDir  = !dragExtendDir;
              }
              selectedIndex  = Math.max( 0, Math.min( values.length - 1, selectedIndex ));
              selectionSize   = Math.min( values.length - selectedIndex, selectionSize );
              action  = true;
              repaint  |= showIndex;
            }
          }
        } else {
          selectedIndex  = dragIdx;
          action      = true;
          repaint       |= showIndex;
        }
      } else if( !readOnly ) {
        if( (lastDragIdx == -1) || (lastDragIdx == dragIdx) ) {
          if( snap( value ) != values[ dragIdx ]) {
            values[ dragIdx ] = snap( value );
            action  = true;
            repaint  = true;
            if( dirtyStart == -1 ) {
              dirtyStart  = dragIdx;
              dirtyStop  = dirtyStart + 1;
            } else {
              dirtyStart  = Math.min( dirtyStart, dragIdx );
              dirtyStop  = Math.max( dirtyStop, dragIdx + 1 );
            }
          }
        } else {
          final int  step  = dragIdx < lastDragIdx ? -1 : 1;
          final float  valOff  = values[ lastDragIdx ];
          final float valScale= (value - valOff) / Math.abs( lastDragIdx - dragIdx );
          for( int i = lastDragIdx + step, j = 1; i != dragIdx; i += step, j++ ) {
            values[ i ] = snap( j * valScale + valOff );
          }
          values[ dragIdx ] = snap( value );
          action  = true;
          repaint  = true;
          if( dirtyStart == -1 ) {
            dirtyStart  = Math.min( dragIdx, lastDragIdx );
            dirtyStop  = Math.max( dragIdx, lastDragIdx ) + 1;
          } else {
            dirtyStart  = Math.min( dirtyStart, Math.min( dragIdx, lastDragIdx ));
            dirtyStop  = Math.max( dirtyStop, Math.max( dragIdx, lastDragIdx ) + 1 );
          }
        }
      }
      lastDragIdx   = dragIdx;
      if( !dragExtend && (selectedIndex != lastDragIdx) ) {
        selectedIndex   = lastDragIdx;
        action      = true;
        selectionSize  = Math.min( selectionSize, values.length - selectedIndex );
        repaint       |= showIndex;
      }

      if( action ) fireActionPerformed();
      if( repaint ) repaint()// XXX should use painting rectangle here!!
    }

    public void mousePressed( MouseEvent e )
    {
      if( !isEnabled() || e.isControlDown() ) return;

      requestFocus();

      processMouse( e, true );
    }
   
    public void mouseReleased( MouseEvent e )
    {
      lastDragIdx = -1;
    }
   
    public void mouseDragged( MouseEvent e )
    {
      if( !isEnabled() ) return;

      processMouse( e, false );
    }
  }
}
TOP

Related Classes of de.sciss.swingosc.MultiSlider$MouseAdapter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.