Package de.sciss.meloncillo.gui

Source Code of de.sciss.meloncillo.gui.BlendingAction$CloseAction

/*
*  BlendingAction.java
*  Meloncillo
*
*  Copyright (c) 2004-2008 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:
*    12-May-05  created from de.sciss.meloncillo.gui.BlendingAction
*    13-Jul-05  manages blending curve
*    14-Jul-08  copied back from EisK
*/

package de.sciss.meloncillo.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.Point2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
//import java.util.ArrayList;
//import java.util.List;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;

import javax.swing.AbstractAction;
import javax.swing.AbstractButton;
import javax.swing.BorderFactory;
import javax.swing.ComboBoxEditor;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.KeyStroke;
import javax.swing.ListCellRenderer;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
//import javax.swing.event.ListDataEvent;
//import javax.swing.event.ListDataListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;

import de.sciss.meloncillo.io.BlendContext;
import de.sciss.meloncillo.timeline.Timeline;

import de.sciss.app.AbstractApplication;
import de.sciss.app.AbstractWindow;
import de.sciss.app.Application;
import de.sciss.app.DynamicAncestorAdapter;
import de.sciss.app.DynamicListening;
import de.sciss.app.GraphicsHandler;
import de.sciss.common.AppWindow;
import de.sciss.gui.CoverGrowBox;
import de.sciss.gui.DefaultUnitViewFactory;
import de.sciss.gui.GUIUtil;
import de.sciss.gui.HelpButton;
import de.sciss.gui.MultiStateButton;
import de.sciss.gui.ParamField;
import de.sciss.gui.PrefParamField;
import de.sciss.gui.SpringPanel;
import de.sciss.util.DefaultUnitTranslator;
import de.sciss.util.Param;
import de.sciss.util.ParamSpace;

/**
*  A class implementing the <code>Action</code> interface
*  which deals with the blending setting. Each instance
*  generates a toggle button suitable for attaching to a tool bar;
*  this button reflects the blending preferences settings and
*  when alt+pressed will prompt the user to alter the blending settings.
*
@author    Hanns Holger Rutz
@version  0.70, 23-Mar-08
*
*  @todo    gui panels should be destroyed / disposed
*        because otherwise different BlendingAction instances
*        for different docs all create their own panels
*
*  @todo    should not be a subclass of AbstractAction
*
*  @todo    close action should be called whenenver popup disappears,
*        and duplicates should be filtered out!
*/
public class BlendingAction
extends AbstractAction
// implements LaterInvocationManager.Listener
{
  public static final int            MAX_RECENTNUM  = 5;
 
  public static final String          DEFAULT_NODE  = "blending";
 
  private static final String          KEY_ACTIVE    = "active";
  public static final String          KEY_DURATION  = "duration";
  private static final String          NODE_RECENT    = "recent";

  protected static final Param        DEFAULT_DUR    =
    new Param( 100.0, ParamSpace.ABS | ParamSpace.TIME | ParamSpace.MILLI | ParamSpace.SECS );


  private static PrefComboBoxModel      pcbm      = null;
//  private PrefComboBoxModel          pcbm      = null;
 
//  private final JToggleButton          b;
  protected final MultiStateButton      b;
  protected final Preferences          prefs;
  protected PrefParamField          ggBlendTime;
  protected CurvePanel            ggCurvePanel;
  private SpringPanel              ggSettingsPane;
  private JComponent              bottomPanel;
//  private JDialog                dlg        = null;
  private  static final DefaultUnitTranslator  ut        = new DefaultUnitTranslator();
  protected static final DefaultUnitViewFactory uvf      = new DefaultUnitViewFactory();
 
  private final CurvePanel.Icon        curveIcon;

//  private boolean                guiCreated    = false;
 
  private final PopupTriggerMonitor      popMon;
  private JPopupMenu              popup      = null;
  private AppWindow              palette      = null;
//  private boolean                listening    = false;
 
  private boolean                active;
 
  private final Timeline            timeline;
 
//  private List                collListeners  = new ArrayList();
 
  protected final Settings          current;

  /**
   *  Creates a new instance of an action
   *  that tracks blending changes
   *
   *  @param  prefs  node of preferences tree (usually DEFAULT_NODE)
   */
  public BlendingAction( Timeline timeline, Preferences prefs )
  {
    super();
    this.prefs    = prefs != null ? prefs : AbstractApplication.getApplication().getUserPrefs().node( DEFAULT_NODE );
    this.timeline  = timeline;

//    b        = new JToggleButton( this );
    b        = new MultiStateButton();
    b.setNumColumns( 8 );
    b.setAutoStep( false );
    b.addActionListener( this );
    b.addItem( "", null, new Color( 0, 0, 0, 0 ));
    b.addItem( "", null, new Color( 0xFF, 0xFA, 0x9D ));
//    uvf        = new DefaultUnitViewFactory();
//    GraphicsUtil.setToolIcons( b, GraphicsUtil.createToolIcons( GraphicsUtil.ICON_BLENDING ));
    curveIcon    = new CurvePanel.Icon( createBasicCurves() );
//    curveIcon.update( this.prefs );
//    b.setIcon( curveIcon );
    b.setItemIcon( 0, curveIcon );
    b.setItemIcon( 1, curveIcon );
   
//    new DynamicAncestorAdapter( new DynamicPrefChangeManager( this.prefs,
//      new String[] { KEY_ACTIVE, KEY_DURATION }, this )).addTo( b );

    popMon = new PopupTriggerMonitor( b );
    popMon.addListener( new PopupTriggerMonitor.Listener() {
      public void componentClicked( PopupTriggerMonitor m ) { /* empty */ }
     
      public void popupTriggered( PopupTriggerMonitor m )
      {
        b.getModel().setArmed( false );
        showPopup( m.getComponent(), 0, m.getComponent().getHeight() );
      }
    });
   
    active        = this.prefs.getBoolean( KEY_ACTIVE, false );
    current        = Settings.fromPrefs( this.prefs );
//    current.duration  = Param.fromPrefs( this.prefs, KEY_DURATION, null );
//    current.ctrlPt    = CurvePanel.getControlPoints( this.prefs );
//    curveIcon.update( current.ctrlPt[ 0 ], current.ctrlPt[ 1 ]);
    updateButton();
  }
 
  public Preferences getPreferences() { return prefs; }
  private Preferences getRecentPreferences() { return prefs.node( NODE_RECENT ); }
 
//  public void addRecentListener( ListDataListener l )
//  {
//    collListeners.add( l );
//  }
//
//  public void removeRecentListener( ListDataListener l )
//  {
//    collListeners.remove( l );
//  }

  private void createBlendPan( boolean popped )
  {
    destroyBlendPan();

//    if( guiCreated ) return;
    createGadgets( 0 );
    final Font fnt = AbstractApplication.getApplication().getGraphicsHandler()
      .getFont( GraphicsHandler.FONT_SYSTEM | GraphicsHandler.FONT_SMALL );
    GUIUtil.setDeepFont( ggSettingsPane, fnt );
    GUIUtil.setDeepFont( bottomPanel, fnt );
    ggBlendTime.setCycling( popped ); // cannot open popup menu in another popup menu!
    if( palette != null ) {
      palette.getContentPane().add( ggSettingsPane, BorderLayout.CENTER );
      palette.getContentPane().add( bottomPanel, BorderLayout.SOUTH );
      palette.revalidate();
    } else {
      popup.add( ggSettingsPane, BorderLayout.CENTER );
      popup.add( bottomPanel, BorderLayout.SOUTH );
      popup.revalidate();
    }
//    guiCreated  = true;
  }

  private void destroyBlendPan()
  {
    if( ggSettingsPane != null ) {
      ggSettingsPane.getParent().remove( ggSettingsPane );
      ggSettingsPane = null;
    }
    if( bottomPanel != null ) {
      bottomPanel.getParent().remove( bottomPanel );
      bottomPanel = null;
    }
  }

  private void createGadgets( int flags )
  {
    bottomPanel    = createBottomPanel( flags );
//    ggSettingsPane  = new JScrollPane( JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
//                       JScrollPane.HORIZONTAL_SCROLLBAR_NEVER );
    ggSettingsPane  = new SpringPanel( 4, 2, 4, 2 );
//    ggBlendTime    = new PrefNumberField( 0, NumberSpace.genericDoubleSpace, "sec." );
    ut.setLengthAndRate( 0, timeline.getRate() );
    ggBlendTime    = new PrefParamField( ut );
    ggBlendTime.addSpace( ParamSpace.spcTimeMillis );
    ggBlendTime.addSpace( ParamSpace.spcTimeSmps );
    ggBlendTime.setPreferences( prefs, KEY_DURATION );
    ggBlendTime.setReadPrefs( false );
    if( current.duration != null ) {
//System.err.println( "setDuration" );
      ggBlendTime.setValueAndSpace( current.duration );
    }
    ggBlendTime.addListener( new ParamField.Listener() {
      public void paramSpaceChanged( ParamField.Event e )
      {
        paramValueChanged( e );
      }
     
      public void paramValueChanged( ParamField.Event e )
      {
        if( !e.isAdjusting() ) {
          current.duration = ggBlendTime.getValue();
          updateButtonText();
        }
      }
    });

    ggCurvePanel  = new CurvePanel( createBasicCurves(), this.prefs );
//System.err.println( "setControlPoints" );
    ggCurvePanel.setControlPoints( current.ctrlPt[ 0 ], current.ctrlPt[ 1 ]);
    ggCurvePanel.setPreferredSize( new Dimension( 162, 162 ))
    ggCurvePanel.addActionListener( new ActionListener() {
      public void actionPerformed( ActionEvent e )
      {
        final Point2D[] pt = ggCurvePanel.getControlPoints();
        current.ctrlPt[ 0 ].setLocation( pt[ 0 ]);
        current.ctrlPt[ 1 ].setLocation( pt[ 1 ]);
        updateButtonIcon();
      }
    });

    ggSettingsPane.gridAdd( ggBlendTime, 0, 0 );
    ggSettingsPane.gridAdd( ggCurvePanel, 0, 1 );
    ggSettingsPane.makeCompactGrid();
  }

  public void showPopup( Component invoker, int x, int y )
  {
    createPopup();
//    startListening();
    popup.show( invoker, x, y );
    // XXX this is necessary unfortunately
    // coz the DynamicAncestorAdapter doesn't seem
    // to work with the popup menu ...
    ggBlendTime.startListening();
//    if( beginDragging ) pan.beginDragging();
  }

  private void createPopup()
  {
    if( popup != null ) return;
    if( palette != null ) destroyPalette();
   
    popup  = new JPopupMenu();
    createBlendPan( true );
    popup.addPopupMenuListener( new PopupMenuListener() {
      public void popupMenuCanceled( PopupMenuEvent e )
      {
        stopAndDispose();
      }
     
      public void popupMenuWillBecomeInvisible( PopupMenuEvent e ) { /* empty */ }
      public void popupMenuWillBecomeVisible( PopupMenuEvent e ) { /* empty */ }
    });
//popup.setCursor( new java.awt.Cursor( java.awt.Cursor.CROSSHAIR_CURSOR ));
  }
 
  protected void stopAndDispose()
  {
    // XXX this is necessary unfortunately
    // coz the DynamicAncestorAdapter doesn't seem
    // to work with the popup menu ...
    ggBlendTime.stopListening();
    dispose();
  }

  public void showPalette()
  {
    createPalette();
//    startListening();
    palette.setVisible( true );
    palette.toFront();
  }

  private void destroyPalette()
  {
    if( palette == null ) return;
   
    palette.dispose();
    palette = null;
  }

  private void destroyPopup()
  {
    if( popup == null ) return;
   
    popup.setVisible( false );
    popup = null;
  }

  protected static CubicCurve2D[] createBasicCurves()
  {
    return new CubicCurve2D[] {
      new CubicCurve2D.Double( 0.0, 1.0, 0.5, 0.0, 0.5, 0.0, 1.0, 0.0 ),
      new CubicCurve2D.Double( 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 1.0, 1.0 )
    };
  }
 
  /**
   *  Returns the toggle button
   *  which is connected to this action.
   *
   *  @return  a toggle button which is suitable for tool bar display
   */
//  public JToggleButton getButton()
  public AbstractButton getButton()
  {
    return b;
  }
 
  public JComboBox getComboBox()
  {
    final ComboBoxModel    model      = getComboBoxModel();
    final ComboBoxModel    emptyCBM    = new DefaultComboBoxModel();
    final MultiStateButton  button      = b;
    final JComboBox      ggBlend      = new JComboBox(); // ( pcbm );
    final ListCellRenderer  blendRenderer  = getComboBoxRenderer();
   
    ggBlend.setEditable( true );
    ggBlend.setEditor( new ComboBoxEditor() {
      public Component getEditorComponent() { return button; }

      public void setItem( Object o )
      {
//System.err.println( "setItem " + o );
        if( o != null ) {
          current.setFrom( (Settings) o );
          current.toPrefs( prefs );
          updateButton();
        }
      }
     
      public Object getItem() { return current; }
      public void selectAll() { /* ignore */ }
      public void addActionListener(ActionListener l) { /* ignore */ }
      public void removeActionListener(ActionListener l) { /* ignore */ }
    });
    ggBlend.setRenderer( blendRenderer );
    button.setFocusable( false );
    ggBlend.setFocusable( false );
    GUIUtil.constrainSize( ggBlend, 120, 26 )// 110 XXX (140 for MetalLAF)
    ggBlend.setOpaque( false );
   
    // this is _crucial_ because since pcbm is global
    // and the combobox registers with it, we have a
    // memory leak otherwise!!
    new DynamicAncestorAdapter( new DynamicListening() {
      public void startListening()
      {
        ggBlend.setModel( model );
      }
     
      public void stopListening()
      {
        ggBlend.setModel( emptyCBM );
      }
    }).addTo( ggBlend );
   
    return ggBlend;
  }

  private void updateButtonState()
  {
//    b.setSelected( prefs.getBoolean( KEY_ACTIVE, false ));
//    b.setSelectedIndex( prefs.getBoolean( KEY_ACTIVE, false ) ? 1 : 0 );
    b.setSelectedIndex( active ? 1 : 0 );
  }
 
  protected void updateButton()
  {
    updateButtonState();
    updateButtonText();
    updateButtonIcon();
  }

  protected void updateButtonText()
  {
//    final Param    p;
    final Param    p    = current.duration;
    final Object  view;
    final String  text;
   
//    p = Param.fromPrefs( prefs, KEY_DURATION, null );
    if( p != null ) {
      view = uvf.createView( p.unit );
     
      if( view instanceof Icon ) {
        // XXX hmmm. should use composite icon
      } else {
//        b.setText( String.valueOf( (int) p.val ) + " " + view.toString() );
        text = String.valueOf( (int) p.val ) + " " + view.toString();
        b.setItemText( 0, text );
        b.setItemText( 1, text );
      }
      if( ggBlendTime != null ) ggBlendTime.setValueAndSpace( p );
    }
  }

  protected void updateButtonIcon()
  {
    curveIcon.update( current.ctrlPt[ 0 ], current.ctrlPt[ 1 ]);
    if( ggCurvePanel != null ) ggCurvePanel.setControlPoints( current.ctrlPt[ 0 ], current.ctrlPt[ 1 ]);
    b.repaint();
  }

  private JComponent createBottomPanel( int flags )
  {
    final JPanel  panel;
    final JButton  ggClose;

    panel    = new JPanel( new FlowLayout( FlowLayout.TRAILING, 4, 2 ));
    ggClose    = new JButton( new CloseAction( getResourceString( "buttonClose" )));
    GUIUtil.createKeyAction( ggClose, KeyStroke.getKeyStroke( KeyEvent.VK_ESCAPE, 0 ));
    ggClose.setFocusable( false );
    panel.add( ggClose );
    panel.add( new HelpButton( "Blending" ));
    panel.add( CoverGrowBox.create() );

    return panel;
  }

  private String getResourceString( String key )
  {
    return AbstractApplication.getApplication().getResourceString( key );
  }
 
  public void actionPerformed( ActionEvent e )
  {
    if( (e.getModifiers() & ActionEvent.ALT_MASK) != 0 ) {
      showPalette();
    } else {
//      prefs.putBoolean( KEY_ACTIVE, b.isSelected() );
      active = b.getSelectedIndex() == 0;
      prefs.putBoolean( KEY_ACTIVE, active );
      updateButtonState();
    }
  }
 
  private void createPalette()
  {
    if( palette != null ) return;
    if( popup != null ) destroyPopup();

    final Application  app      = AbstractApplication.getApplication();
 
    palette = new AppWindow( AbstractWindow.PALETTE );
    palette.setTitle( app.getResourceString( "inputDlgSetBlendSpan" ));
    createBlendPan( false );
       palette.getContentPane().add( CoverGrowBox.create(), BorderLayout.SOUTH );
    palette.setDefaultCloseOperation( WindowConstants.DO_NOTHING_ON_CLOSE );
    palette.addListener( new AbstractWindow.Adapter() {
      public void windowClosing( AbstractWindow.Event e )
      {
        dispose();
      }
    });
    palette.init();
  }

  public void dispose()
  {
//    stopListening();
    destroyPalette();
    destroyPopup();
    destroyBlendPan();
  }
 
  private ComboBoxModel getComboBoxModel()
  {
    if( pcbm == null ) {
      pcbm = new PrefComboBoxModel() {
        public Object dataFromNode( Preferences node )
        {
          return Settings.fromPrefs( node );
        }

        public void dataToNode( Object data, Preferences node )
        {
          ((Settings) data).toPrefs( node );
        }
      };
      pcbm.setPreferences( getRecentPreferences() );
    }
    return pcbm;
  }
 
  private ListCellRenderer getComboBoxRenderer()
  {
    return new BlendCBRenderer();
  }
 
  protected void storeRecent()
  {
    if( pcbm == null ) return;
   
    pcbm.setSelectedItem( null );
   
    while( pcbm.getSize() >= MAX_RECENTNUM ) {
      try {
        pcbm.remove( pcbm.getSize() - 1 );
      }
      catch( BackingStoreException e1 ) {
        e1.printStackTrace();
        return;
      }
    }
    pcbm.add( 0, current.duplicate() );
  }
 
//  private void storeRecentXXX()
//  {
//    final Preferences rPrefs = getRecentPreferences();
//    Preferences node1, node2;
//    String[] names;
////    final ListDataEvent lde;
//    int i;
//    try {
//      for( i = 0; i < MAX_RECENTNUM; i++ ) {
//        if( !rPrefs.nodeExists( DEFAULT_NODE + (i+1) )) break;
//      }
//      if( i == MAX_RECENTNUM ) {
//        node2 = rPrefs.node( DEFAULT_NODE + "1" );
//        for( int j = 1; j < MAX_RECENTNUM; j++ ) {
//          node1 = node2;
//          node2 = rPrefs.node( DEFAULT_NODE + (j+1)  );
//          names = node2.childrenNames();
//          for( int k = 0; k < names.length; k++ ) {
//            node1.put( names[ k ], node2.get( names[ k ], null ));
//          }
//        }
//        i--;
//System.err.println( "remove " + node2 );
//        node2.removeNode();
//      }
//      node1 = rPrefs.node( DEFAULT_NODE + (i+1)  );
//System.err.println( "added " + node1 );
//      node1.put( KEY_DURATION, current.duration.toString() );
//      ggCurvePanel.toPrefs( node1 );
//     
////      lde = new ListDataEvent( this, ListDataEvent.CONTENTS_CHANGED, 0, i );
////      for( int j = 0; j < collListeners.size(); j++ ) {
////        ((ListDataListener) collListeners.get( j )).contentsChanged( lde );
////      }
//    }
//    catch( BackingStoreException e1 ) {
//      System.err.println( e1 );
//    }
//  }

//  private void startListening()
//  {
//    if( !listening ) {
////      tracks.addListener( scListener );
////      audioPrefs.addPreferenceChangeListener( prefListener );
//      ggBlendTime.fromPrefsString( prefs.get( KEY_DURATION, null ));
//      listening = true;
//    }
//  }
// 
//  private void stopListening()
//  {
//    if( listening ) {
////      tracks.removeListener( scListener );
////      audioPrefs.removePreferenceChangeListener( prefListener );
//      listening = false;
//    }
//  }

//  private void openDialog()
//  {
////    new TestDialog();
//    if( dlg == null ) {
//      final Window w = SwingUtilities.windowForComponent( b );
//      dlg = new JDialog( ((w == null) || !(w instanceof Frame)) ? null : (Frame) w,
//        getResourceString( "inputDlgSetBlendSpan" ), true );
//      final Container cp  = dlg.getContentPane();
//      if( !guiCreated ) {
//        createGUI();
//      }
//      cp.add( ggSettingsPane, BorderLayout.CENTER );
//      cp.add( bottomPanel, BorderLayout.SOUTH );
//      dlg.pack();
//      dlg.setLocationRelativeTo( b );
//    }
//    dlg.setVisible( true );
//    // XXX dispose gui
//    prefs.putBoolean( KEY_ACTIVE, ggBlendTime.getValue().val > 0.0 );
//    updateButtonState();  // prefsChangeEvent not guaranteed!!
//  }
 
//  // o instanceof PreferenceChangeEvent
//  public void laterInvocation( Object o )
//  {
//    final PreferenceChangeEvent  pce = (PreferenceChangeEvent) o;
//    final String        key = pce.getKey();
//     
//    if( key.equals( KEY_ACTIVE )) {
//      updateButtonState();
//    } else if( key.equals( KEY_DURATION )) {
//      updateButtonText();
//    }
//  }
 
//  /**
//   *  @param  maxLength  the maximum blend length or <code>-1</code> if there is no max
//   *
//   *  @todo  pre/post position not yet effective (using 0.5 right now)
//   */
//  public static BlendContext createBlendContext( Preferences prefs, double rate, long maxPre, long maxPost )
//  {
//    long  blendLen  = 0;
//    long  pre = 0, post = 0;
//    Param  p;
//
//    if( prefs.getBoolean( KEY_ACTIVE, false )) {
//      p = Param.fromPrefs( prefs, KEY_DURATION, null );
//      if( p != null ) {
//        synchronized( ut ) {
//          ut.setLengthAndRate( 0, rate );
//          blendLen = (long) (ut.translate( p, ParamSpace.spcTimeSmps ).val + 0.5);
//          pre = blendLen >> 1;
//          post = blendLen - pre;
//          if( (maxPre >= 0) && (pre > maxPre) ) {
//            pre    = maxPre;
//            post  = pre;  // XXX cheesy
//          }
//          if( (maxPost >= 0) && (post > maxPost) ) {
//            post  = maxPost;
//            pre    = post;
//          }
//        }
//      }
//    }
//    return new BlendContext( pre, post, CurvePanel.getControlPoints( prefs ) );
//  }

  /**
   *  @param  maxLength  the maximum blend length or <code>-1</code> if there is no max
   *
   *  @todo  pre/post position not yet effective (using 0.5 right now)
   */
  public BlendContext createBlendContext( long maxLeft, long maxRight )
  {
    if( !java.awt.EventQueue.isDispatchThread() ) throw new IllegalMonitorStateException();
    if( !active ) return null;
   
    final long  blendLen;
    final Param  p;

    p = current.duration; // Param.fromPrefs( prefs, KEY_DURATION, null );
    if( p != null ) {
      ut.setLengthAndRate( 0, timeline.getRate() );
      blendLen  = (long) (ut.translate( p, ParamSpace.spcTimeSmps ).val + 0.5);
      if( maxLeft + maxRight > blendLen ) {
        maxLeft  = (long) (maxLeft * (double) blendLen / (maxLeft + maxRight) + 0.5 );
        maxRight= blendLen - maxLeft;
      }
    }
    return new BlendContext( maxLeft, maxRight, CurvePanel.getControlPoints( prefs ) );
  }
 
  private static class Settings
  {
    protected Param        duration;
    protected final Point2D[]  ctrlPt  = new Point2D[] { new Point2D.Double(), new Point2D.Double() };
   
    private Settings() { /* empty */ }
   
    private Settings( Settings orig )
    {
      setFrom( orig );
    }
   
    protected void setFrom( Settings orig )
    {
      duration = orig.duration;
      ctrlPt[ 0 ].setLocation( orig.ctrlPt[ 0 ]);
      ctrlPt[ 1 ].setLocation( orig.ctrlPt[ 1 ]);
    }
   
    protected static Settings fromPrefs( Preferences node )
    {
      final Settings s = new Settings();
      s.duration = Param.fromPrefs( node, KEY_DURATION, DEFAULT_DUR );
      final Point2D[] pt = CurvePanel.getControlPoints( node );
      s.ctrlPt[ 0 ].setLocation( pt[ 0 ]);
      s.ctrlPt[ 1 ].setLocation( pt[ 1 ]);
      return s;
    }
   
    protected Settings duplicate()
    {
      return new Settings( this );
    }
   
    protected void toPrefs( Preferences node )
    {
      node.put( KEY_DURATION, duration.toString() );
      CurvePanel.toPrefs( ctrlPt, node );
    }
   
    public String toString()
    {
      return String.valueOf( duration.val );
    }
  }
 
  private static class BlendCBRenderer
  extends JLabel
  implements ListCellRenderer
  {
    private final Color bgNorm, bgSel, fgNorm, fgSel;
    final CurvePanel.Icon curveIcon;
 
    protected BlendCBRenderer()
    {
      super();
      setOpaque( true );
      bgNorm    = UIManager.getColor( "List.background" );
      bgSel    = UIManager.getColor( "List.selectionBackground" );
      fgNorm    = UIManager.getColor( "List.foreground" );
      fgSel    = UIManager.getColor( "List.selectionForeground" );
      curveIcon  = new CurvePanel.Icon( createBasicCurves() );
      setIcon( curveIcon );
      setBorder( BorderFactory.createEmptyBorder( 2, 2, 2, 2 ));
      }
   
    public Component getListCellRendererComponent(
      JList list, Object value, int index, boolean isSelected, boolean cellHasFocus )
    {
      final Settings  s    = (Settings) value;
      final Object  view  = uvf.createView( s.duration.unit );
     
      curveIcon.update( s.ctrlPt[0], s.ctrlPt[1] );
      if( view instanceof Icon ) {
        // XXX hmmm. should use composite icon
      } else {
        setText( String.valueOf( (int) s.duration.val ) + " " + view.toString() );
      }
      setBackground( isSelected ? bgSel : bgNorm );
      setForeground( isSelected ? fgSel : fgNorm );
      return this;
    }
  }

  private class CloseAction
  extends AbstractAction
  {
    protected CloseAction( String text )
    {
      super( text );
    }

    public void actionPerformed( ActionEvent e )
    {
      stopAndDispose();
      storeRecent();
    }
  }
 
  ////////////////////////////////////////// TEST

//  private class TestDialog
//  {
//    private TestDialog()
//    {
//      JDialog dlg = new JDialog( (Frame) null,
//        getResourceString( "inputDlgSetBlendSpan" ), true );
//      final Container cp  = dlg.getContentPane();
//
//      cp.add( new TestPanel(), BorderLayout.CENTER );
//
//      dlg.pack();
//      dlg.setLocationRelativeTo( b );
//      dlg.setVisible( true );
//      // XXX dispose gui
//    }
//  }
 
//  private class TestPanel
//  extends JComponent
//  {
//Paint  pntMarkStick= new Color( 0x31, 0x50, 0x4D, 0x7F );
//Stroke  strkStick  = new BasicStroke( 1.0f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_BEVEL,
//    1.0f, new float[] { 4.0f, 4.0f }, 0.0f );
//
//    private TestPanel()
//    {
//      super();
//    }
//   
//    public void paintComponent( Graphics g )
//    {
//      super.paintComponent( g );
//     
//      final Graphics2D    g2        = (Graphics2D) g;
//      final int        currentWidth  = getWidth(); // - insets.left - insets.right;
//      final int        currentHeight  = getHeight(); // - insets.top - insets.bottom;
//      final AffineTransform  atOrig      = g2.getTransform();
//      final Stroke      strkOrig    = g2.getStroke();
//      final Shape        clipOrig    = g2.getClip();
//
////      double trnsX, trnsY;
//     
//      g2.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
////      g2.translate( insets.left, insets.top );
//
//AffineTransform atSchoko = AffineTransform.getScaleInstance( currentWidth / 7f, currentHeight / 6f );
//AffineTransform atSchoko2 = new AffineTransform( atSchoko );
//AffineTransform atSchoko3 = new AffineTransform( atSchoko );
//atSchoko2.translate( 0f, 3f );
//atSchoko3.translate( -3f, 3f );
//
//Area a = new Area( new Rectangle2D.Float( 0f, 0f, 0.95f, 6f ));
//a.add( new Area( new Rectangle2D.Float( 1f, 0f, 5f, 3f )));
//a.add( new Area( new Rectangle2D.Float( 6.05f, 0f, 0.95f, 3f )));
//a.add( new Area( new Rectangle2D.Float( 1f, 3f, 2f, 3f )));
//a.add( new Area( new Rectangle2D.Float( 3.05f, 3f, 3.95f, 3f )));
//a.transform( atSchoko );
//g2.clip( a );
//
//g2.translate( 0, currentHeight / 12f );
//
//GeneralPath gp;
//gp = new GeneralPath();
//gp.moveTo( 0f, 0f );
//gp.lineTo( 1f, 0f );
//gp.curveTo( 2f, 0f, 2f, 2f, 3f, 2f );
//g2.setColor( Color.red );
//g2.setStroke( new BasicStroke( 2f ));
//g2.draw( gp.createTransformedShape( atSchoko ));
//g2.draw( gp.createTransformedShape( atSchoko2 ));
//gp.lineTo( 0f, 2f );
//g2.setColor( new Color( 0xFF, 0x00, 0x00, 0x7F ));
//g2.fill( gp.createTransformedShape( atSchoko ));
//g2.fill( gp.createTransformedShape( atSchoko2 ));
//
//gp = new GeneralPath();
//gp.moveTo( 4f, 2f );
//gp.curveTo( 5f, 2f, 5f, 0f, 6f, 0f );
//gp.lineTo( 7f, 0f );
//g2.setColor( new Color( 0x00, 0xA0, 0x00 ));
//g2.setStroke( new BasicStroke( 2f ));
//g2.draw( gp.createTransformedShape( atSchoko ));
//g2.draw( gp.createTransformedShape( atSchoko3 ));
//gp.lineTo( 7f, 2f );
//g2.setColor( new Color( 0x00, 0xA0, 0x00, 0x7F ));
//g2.fill( gp.createTransformedShape( atSchoko ));
//g2.fill( gp.createTransformedShape( atSchoko3 ));
//
//g2.setColor( GraphicsUtil.colrSelection );
//g2.fill( new GeneralPath( new Rectangle2D.Float( 2f, -0.5f, 3f, 3f )).createTransformedShape( atSchoko ));
//
//Point2D p1 = atSchoko.transform( new Point2D.Float( 2f, -0.5f ), null );
//Point2D p2 = atSchoko.transform( new Point2D.Float( 2f,  5.5f ), null );
//Line2D li = new Line2D.Float( p1, p2 );
//g2.setPaint( pntMarkStick );
//g2.setStroke( strkStick );
//g2.draw( li );
//
//      g2.setTransform( atOrig );
//      g2.setClip( clipOrig );
//      g2.setStroke( strkOrig );
//    }
//  }
}
TOP

Related Classes of de.sciss.meloncillo.gui.BlendingAction$CloseAction

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.
);