/*
* BasicFrame.java
* (FScape)
*
* Copyright (c) 2001-2016 Hanns Holger Rutz. All rights reserved.
*
* This software is published under the GNU General Public License v3+
*
*
* For further information, please contact Hanns Holger Rutz at
* contact@sciss.de
*/
package de.sciss.fscape.gui;
import de.sciss.fscape.prop.Presets;
import de.sciss.fscape.prop.PropertyArray;
import de.sciss.fscape.util.Constants;
import de.sciss.fscape.util.Curve;
import de.sciss.fscape.util.DoublePoint;
import de.sciss.fscape.util.Envelope;
import de.sciss.fscape.util.Param;
import de.sciss.fscape.util.ParamSpace;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.util.Iterator;
import java.util.Properties;
/**
* Dialog for breakpoint editing.
*/
public class EditEnvDlg
extends BasicDialog {
// -------- public variables --------
public static final int GG_PRESETS = 1; // IDs und zugleich Hash-Keys
public static final int GG_ADDPRESET = 2;
public static final int GG_DELPRESET = 3;
public static final int GG_ATK = 10; // WICHTIG: immer aufeinanderfolgende IDs
public static final int GG_SUS = 11; // fuer Atk/Sus/Rls Gadgets!!!
public static final int GG_RLS = 12;
public static final int GG_ATKCURVE = 13;
public static final int GG_SUSCURVE = 14;
public static final int GG_RLSCURVE = 15;
public static final int GG_ATKTIME = 16;
public static final int GG_SUSTIME = 17;
public static final int GG_RLSTIME = 18;
public static final int GG_POINTX = 19;
public static final int GG_POINTY = 20;
public static final int GG_OK = 30;
public static final int GG_CANCEL = 31;
// -------- private variables --------
protected GUISupport gui; // Dialog-Oberflaeche
private boolean choice = false; // keine Veraenderung bei Cancel noetig
protected static PropertyArray static_pr = null;
protected static Presets presets = null;
protected PropertyArray pr; // consists just of single env...
// Properties (defaults)
private static final int PR_ENV = 0; // Array-Indices: pr.envl
private static final String PRN_ENV = "Env"; // Property-Keynames
private static final Envelope prEnvl[] = { null };
private static final String prEnvlName[] = { PRN_ENV };
private final EditEnvDlg enc_this = this;
// -------- public methods --------
// public boolean getJComboBox();
/**
* !! setVisible() und dispose() bleibt dem Aufrufer ueberlassen
*
* @param parent aufrufendes Fenster
*/
public EditEnvDlg(Component parent, Envelope env) {
super(parent, "Edit Curve: ", true);
// einmalig PropertyArray initialisieren
if( static_pr == null ) {
static_pr = new PropertyArray();
static_pr.envl = prEnvl;
static_pr.envl[ PR_ENV ] = Envelope.createBasicEnvelope( Envelope.BASIC_TIME );
static_pr.envlName = prEnvlName;
}
// einmalig Presets initialisieren
if( presets == null ) {
presets = new Presets( getClass(), static_pr.toProperties( true ));
}
pr = (PropertyArray) static_pr.clone();
pr.envl[ PR_ENV ] = env;
// -------- build GUI --------
GridBagConstraints con;
GridBagLayout lay;
EditEnvDlgListener list;
JComboBox ggPresets;
Iterator presetNames;
CurvePanel ggAtkCurve, ggSusCurve, ggRlsCurve;
GroupLabel lbAtk, lbSus, lbRls;
JCheckBox ggAtk, ggSus, ggRls;
ParamField ggAtkTime, ggSusTime, ggRlsTime;
GroupLabel lbPoint;
ParamField ggPointX, ggPointY;
JPanel buttonBar;
JButton ggOk, ggCancel;
gui = new GUISupport();
con = gui.getGridBagConstraints();
lay = gui.getGridBagLayout();
list = new EditEnvDlgListener(this);
con.insets = new Insets(2, 2, 2, 2);
// -------- Toolbar --------
con.fill = GridBagConstraints.HORIZONTAL;
final JPanel toolBar = new JPanel(new FlowLayout(FlowLayout.LEADING, 4, 2));
// toolBar.putClientProperty("styleId", "attached");
// toolBar.setLayout( new FlowLayout( FlowLayout.LEFT, 2, 2 ) );
final JButton ggAddPreset = new JButton("Add");
ggAddPreset.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
addPreset();
}
});
gui.registerGadget(ggAddPreset, GG_ADDPRESET);
// ggAddPreset.addMouseListener(list);
final JButton ggDelPreset = new JButton("Remove");
ggDelPreset.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
removePreset();
}
});
gui.registerGadget(ggDelPreset, GG_DELPRESET);
// ggDelPreset.addMouseListener(list);
ggPresets = new JComboBox();
presetNames = getPresets().presetNames().iterator();
while( presetNames.hasNext() ) {
ggPresets.addItem(presetNames.next());
}
ggPresets.setSelectedItem( Presets.DEFAULT ); // default waehlen und
ggDelPreset.setEnabled( false ); // DelPreset deaktivieren
gui.registerGadget( ggPresets, GG_PRESETS );
ggPresets.addItemListener( list );
toolBar.add(new JLabel("Preset:"));
toolBar.add( ggAddPreset );
toolBar.add( ggDelPreset );
toolBar.add( ggPresets );
con.gridwidth = GridBagConstraints.REMAINDER;
lay.setConstraints( toolBar, con );
gui.add( toolBar );
// -------- Eigentliche Gadgets --------
lbAtk = new GroupLabel( "Attack", GroupLabel.ORIENT_HORIZONTAL, GroupLabel.BRACE_BOTTOM );
lbSus = new GroupLabel( "Sustain", GroupLabel.ORIENT_HORIZONTAL, GroupLabel.BRACE_BOTTOM );
lbRls = new GroupLabel( "Release", GroupLabel.ORIENT_HORIZONTAL, GroupLabel.BRACE_BOTTOM );
con.weightx = 0.17;
con.gridwidth = 2;
gui.addLabel( lbAtk );
con.weightx = 0.66;
gui.addLabel( lbSus );
con.weightx = 0.17;
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addLabel( lbRls );
con.fill = GridBagConstraints.BOTH;
ggAtkCurve = new CurvePanel();
ggSusCurve = new CurvePanel();
ggRlsCurve = new CurvePanel();
con.weighty = 1.0;
con.weightx = 0.17;
con.gridwidth = 2;
ggAtkCurve.addActionListener( list );
gui.addGadget( ggAtkCurve, GG_ATKCURVE );
con.weightx = 0.66;
ggSusCurve.addActionListener( list );
gui.addGadget( ggSusCurve, GG_SUSCURVE );
con.weightx = 0.17;
con.gridwidth = GridBagConstraints.REMAINDER;
ggRlsCurve.addActionListener( list );
gui.addGadget( ggRlsCurve, GG_RLSCURVE );
// TEST
ParamSpace[] timeSpace = new ParamSpace[ 3 ];
timeSpace[ 0 ] = new ParamSpace( Constants.spaces[ Constants.absMsSpace ]);
//timeSpace[ 0 ].min = timeSpace[ 0 ].inc;
timeSpace[ 0 ] = new ParamSpace( timeSpace[ 0 ].inc, timeSpace[ 0 ].max, timeSpace[ 0 ].inc, timeSpace[ 0 ].unit );
timeSpace[ 1 ] = new ParamSpace( Constants.spaces[ Constants.absBeatsSpace ]);
//timeSpace[ 1 ].min = timeSpace[ 1 ].inc;
timeSpace[ 0 ] = new ParamSpace( timeSpace[ 1 ].inc, timeSpace[ 1 ].max, timeSpace[ 1 ].inc, timeSpace[ 1 ].unit );
timeSpace[ 2 ] = new ParamSpace( Constants.spaces[ Constants.ratioTimeSpace ]);
//timeSpace[ 2 ].min = timeSpace[ 2 ].inc;
timeSpace[ 2 ] = new ParamSpace( timeSpace[ 2 ].inc, timeSpace[ 2 ].max, timeSpace[ 2 ].inc, timeSpace[ 2 ].unit );
ggAtkTime = new ParamField( timeSpace );
ggSusTime = new ParamField( timeSpace );
ggRlsTime = new ParamField( timeSpace );
ggAtk = new JCheckBox();
ggSus = new JCheckBox();
ggRls = new JCheckBox();
con.fill = GridBagConstraints.HORIZONTAL;
con.weighty = 0.0;
con.weightx = 0.0;
con.gridwidth = 1;
gui.addCheckbox( ggAtk, GG_ATK, list );
con.weightx = 0.17;
gui.addParamField( ggAtkTime, GG_ATKTIME, list );
con.weightx = 0.0;
gui.addCheckbox( ggSus, GG_SUS, list );
con.weightx = 0.66;
gui.addParamField( ggSusTime, GG_SUSTIME, list );
con.weightx = 0.0;
gui.addCheckbox( ggRls, GG_RLS, list );
con.weightx = 0.17;
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addParamField( ggRlsTime, GG_RLSTIME, list );
lbPoint = new GroupLabel( "Point", GroupLabel.ORIENT_HORIZONTAL, GroupLabel.BRACE_BOTTOM );
con.gridwidth = 4;
gui.addLabel( lbPoint );
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addLabel( new JLabel() );
ggPointX = new ParamField( Constants.spaces[ Constants.absMsSpace ]);
ggPointY = new ParamField( Constants.spaces[ Constants.modSpace ]);
con.weightx = 0.0;
con.gridwidth = 1;
gui.addLabel( new JLabel( "X", SwingConstants.RIGHT ));
con.weightx = 0.17;
gui.addParamField( ggPointX, GG_POINTX, list );
con.weightx = 0.0;
gui.addLabel( new JLabel( "Y", SwingConstants.RIGHT ));
con.weightx = 0.17;
gui.addParamField( ggPointY, GG_POINTY, list );
con.gridwidth = GridBagConstraints.REMAINDER;
gui.addLabel( new JLabel() );
// -------- Ok/Cancel Gadgets --------
buttonBar = new JPanel();
buttonBar.setLayout( new BorderLayout( 2, 2 ));
ggCancel = new JButton( " Cancel " );
gui.registerGadget( ggCancel, GG_CANCEL );
ggCancel.addActionListener( list );
ggOk = new JButton( " OK ");
gui.registerGadget( ggOk, GG_OK );
ggOk.addActionListener( list );
buttonBar.add( ggCancel, "West" );
buttonBar.add( ggOk, "East" );
con.gridwidth = GridBagConstraints.REMAINDER;
con.weightx = 0.0;
lay.setConstraints( buttonBar, con );
gui.add( buttonBar );
// Gadgets an die Envelope anpassen
envelopeToGUI();
getContentPane().add( gui );
// Position und Groesse aus dem Preferences ermitteln
setResizable( true );
addWindowListener( new WindowAdapter() {
public void windowClosing( WindowEvent e )
{
closeMe();
}
});
super.initDialog();
}
protected void closeMe()
{
this.setVisible( false );
try {
this.getPresets().store(); // Presets ggf. speichern
} catch( IOException e2 ) {
// vorerst egal XXX
System.err.println( "error storing presets : " + e2.getLocalizedMessage() );
}
this.dispose();
}
/**
* GUI an die Envelope anpassen
* (sie befindet sich in pr.envl[ PR_ENV ])
*/
public void envelopeToGUI()
{
CurvePanel curvePanel;
JCheckBox checkBox;
ParamField paramField;
ParamSpace xSpace;
Curve curve = null;
boolean state = false;
Envelope env = pr.envl[ PR_ENV ];
for( int i = 0; i < 3; i++ ) {
switch( i ) {
case 0:
curve = env.atkCurve;
state = env.atkState;
break;
case 1:
curve = env.susCurve;
state = env.susState;
break;
case 2:
curve = env.rlsCurve;
state = env.rlsState;
break;
default:
break;
}
curvePanel = (CurvePanel) gui.getItemObj( GG_ATKCURVE + i );
checkBox = (JCheckBox) gui.getItemObj( GG_ATK + i );
paramField = (ParamField) gui.getItemObj( GG_ATKTIME + i );
if( (curvePanel != null) && (curve != null) &&
(checkBox != null) && (paramField != null) ) {
curvePanel.setCurve( curve );
curvePanel.setEnabled( state );
checkBox.setSelected( state );
xSpace = curvePanel.getHSpace();
paramField.setParam( new Param( xSpace.max, xSpace.unit ));
paramField.setEnabled( state );
}
}
}
/**
* Envelope aus dem GUI beziehen
*/
public void GUIToEnvelope()
{
CurvePanel curvePanel;
Envelope env;
Curve atkCurve = null;
Curve susCurve = null;
Curve rlsCurve = null;
boolean atkState = false;
boolean susState = false;
boolean rlsState = false;
curvePanel = (CurvePanel) gui.getItemObj( GG_ATKCURVE );
if( curvePanel != null ) {
atkCurve = curvePanel.getCurve();
atkState = curvePanel.isEnabled();
}
curvePanel = (CurvePanel) gui.getItemObj( GG_SUSCURVE );
if( curvePanel != null ) {
susCurve = curvePanel.getCurve();
susState = curvePanel.isEnabled();
}
curvePanel = (CurvePanel) gui.getItemObj( GG_RLSCURVE );
if( curvePanel != null ) {
rlsCurve = curvePanel.getCurve();
rlsState = curvePanel.isEnabled();
}
env = new Envelope( atkCurve, susCurve, rlsCurve );
env.atkState = atkState;
env.susState = susState;
env.rlsState = rlsState;
pr.envl[ PR_ENV ] = env;
}
/**
* Besorgt die Parameter des Dialogs in Form eines PropertyArray Objekts
*/
public PropertyArray getPropertyArray()
{
return pr;
}
/**
* Liefert die Presets der Envelopes
*/
public Presets getPresets()
{
return presets;
}
private void addPreset() {
final JComboBox ggPresets = (JComboBox) gui.getItemObj(EditEnvDlg.GG_PRESETS);
if (ggPresets != null) {
final String name = JOptionPane.showInputDialog( enc_this, "Enter preset name" );
if( name != null && name.length() > 0 ) {
if( name.equals( Presets.DEFAULT )) {
JOptionPane.showMessageDialog( enc_this, "Cannot overwrite defaults!" );
return; // break topLevel;
}
boolean exists = false;
for (int i = ggPresets.getItemCount() - 1;
(i >= 0) && !exists; i--) {
exists = ggPresets.getItemAt(i).equals(name); // existiert schon?
}
if (exists) {
final int res = JOptionPane.showConfirmDialog(enc_this, "Overwrite existing preset\n\"" +
name + "\"", "Confirm", JOptionPane.YES_NO_OPTION);
if (res != 0) return; // break topLevel; // nicht ueberschreiben
}
GUIToEnvelope();
final PropertyArray pa = getPropertyArray();
final Properties preset = pa.toProperties(false);
if (!preset.isEmpty()) { // erfolgreich?
if (getPresets().setPreset(name, preset) != null) {
if (!exists) {
ggPresets.addItem(name); // neues JComboBox-Item
}
ggPresets.setSelectedItem(name);
final Component ggDel = gui.getItemObj(EditEnvDlg.GG_DELPRESET);
if( ggDel != null ) {
ggDel.setEnabled( true ); // enable del
}
} else {
// vorerst keine Fehlermeldung XXX
}
} else {
// vorerst keine Fehlermeldung XXX
}
}
}
}
private void removePreset() {
final JComboBox ggPresets = (JComboBox) gui.getItemObj( EditEnvDlg.GG_PRESETS );
if( ggPresets != null) {
final String name = ggPresets.getSelectedItem().toString();
if( name != null ) {
if( name.equals( Presets.DEFAULT )) {
JOptionPane.showMessageDialog( enc_this, "Cannot delete defaults!" );
return; // break topLevel;
}
if (getPresets().removePreset(name) != null) {
ggPresets.removeItem( name );
if( ggPresets.getItemCount() == 0 ||
ggPresets.getSelectedItem().equals( Presets.DEFAULT )) {
final Component ggDel = gui.getItemObj( EditEnvDlg.GG_DELPRESET );
if( ggDel != null ) {
ggDel.setEnabled( false ); // cannot del default
}
}
} else {
// vorerst keine Fehlermeldung XXX
}
}
}
}
/**
* Dialog-Ergebnis ermitteln
*
* @return modifizierte Envelope oder null bei Cancel
*/
public Envelope getEnvelope()
{
if( choice ) {
return pr.envl[ PR_ENV ];
} else {
return null;
}
}
// -------- quasi-protected methods --------
/*
* NUR FUER DEN LISTENER
*/
public void setJComboBox( boolean choice )
{
this.choice = choice;
}
/*
* Implementation der Listener
*/
private class EditEnvDlgListener
implements ActionListener, AdjustmentListener,
ItemListener, MouseListener, ParamListener {
// -------- private variables --------
private EditEnvDlg dlg; // Edit-Dialog, der den Listener installiert
private CurvePanel curvePanel = null; // derzeit aktives
// -------- public methods --------
/**
* @param dlg Edit-Dialog, der den Listener installiert
*/
public EditEnvDlgListener(EditEnvDlg dlg) {
this.dlg = dlg;
}
// -------- Action methods --------
public void actionPerformed( ActionEvent e )
{
int ID = gui.getItemID( e );
Component associate, associate2;
Param xPara, yPara;
ParamSpace xSpace, ySpace;
ParamSpace spaces[];
DoublePoint pt;
String cmd = e.getActionCommand();
switch( ID ) {
case EditEnvDlg.GG_ATKCURVE: // ---------- Curve geaendert ----------
case EditEnvDlg.GG_SUSCURVE:
case EditEnvDlg.GG_RLSCURVE:
associate = gui.getItemObj( EditEnvDlg.GG_POINTX );
associate2 = gui.getItemObj( EditEnvDlg.GG_POINTY );
if( (associate != null) && (associate2 != null) ) {
// neue Werte laden, ggf. Space aendern, Gadget enablen
if( (cmd.equals(CurvePanel.ACTION_POINTSELECTED)) ||
(cmd.equals(CurvePanel.ACTION_POINTCHANGED)) ) {
pt = ((CurvePanel) e.getSource()).getPoint();
if( pt == null ) break;
if( curvePanel != e.getSource() ) { // different panel, adjust spaces
xSpace = ((CurvePanel) e.getSource()).getHSpace();
spaces = new ParamSpace[ 1 ];
spaces[ 0 ] = xSpace;
((ParamField) associate).setSpaces( spaces );
}
xSpace = ((ParamField) associate).getSpace();
xPara = new Param( pt.x, xSpace.unit );
ySpace = ((ParamField) associate2).getSpace();
yPara = new Param( pt.y, ySpace.unit );
associate.setEnabled( true );
((ParamField) associate).setParam( xPara );
associate2.setEnabled( true );
((ParamField) associate2).setParam( yPara );
} else if(cmd.equals(CurvePanel.ACTION_POINTDESELECTED)) {
associate.setEnabled( false );
associate2.setEnabled( false );
} else if(cmd.equals(CurvePanel.ACTION_SPACECHANGED)) {
xSpace = ((CurvePanel) e.getSource()).getHSpace();
spaces = new ParamSpace[ 1 ];
spaces[ 0 ] = xSpace;
((ParamField) associate).setSpaces( spaces );
}
}
curvePanel = (CurvePanel) e.getSource();
break;
case EditEnvDlg.GG_OK: // ---------- OK / Cancel ----------
dlg.GUIToEnvelope();
dlg.setJComboBox( true );
// THRU
case EditEnvDlg.GG_CANCEL:
dlg.closeMe();
break;
default:
break;
}
}
// -------- ParamListener interface --------
public void paramChanged( ParamEvent e )
{
int ID = gui.getItemID( e );
int ID2;
Component associate, associate2;
Param xPara, yPara;
ParamSpace xSpace;
DoublePoint pt;
switch( ID ) {
case EditEnvDlg.GG_ATKTIME: // ---------- Curve-Time ----------
case EditEnvDlg.GG_SUSTIME:
case EditEnvDlg.GG_RLSTIME:
ID2 = ID - EditEnvDlg.GG_ATKTIME + EditEnvDlg.GG_ATKCURVE;
associate = gui.getItemObj( ID2 );
if( associate != null ) {
xSpace = ((ParamField) e.getSource()).getSpace();
xPara = ((ParamField) e.getSource()).getParam();
xSpace = new ParamSpace( 0.0, xPara.value, xSpace.inc, xSpace.unit );
((CurvePanel) associate).rescale( xSpace, null );
}
break;
case EditEnvDlg.GG_POINTX: // ---------- Punkt-Koordinaten ----------
case EditEnvDlg.GG_POINTY:
associate = gui.getItemObj( EditEnvDlg.GG_POINTX );
associate2 = gui.getItemObj( EditEnvDlg.GG_POINTY );
if( (associate != null) && (associate2 != null) && (curvePanel != null) ) {
// neue Werte uebermitteln
// if( cmd == ParamField.ACTION_VALUECHANGED ) {
xPara = ((ParamField) associate).getParam();
yPara = ((ParamField) associate2).getParam();
pt = new DoublePoint( xPara.value, yPara.value);
curvePanel.setPoint( pt );
// }
}
break;
default:
break;
}
}
// -------- Adjustment methods --------
public void adjustmentValueChanged( AdjustmentEvent e ) {}
// -------- Item methods --------
public void itemStateChanged( ItemEvent e )
{
int ID = gui.getItemID( e );
int ID2, ID3;
Component associate, associate2;
String name;
PropertyArray pa;
Properties preset;
switch( ID ) {
case EditEnvDlg.GG_ATK: // ---------- Curventeile (de)aktiviert ----------
case EditEnvDlg.GG_SUS:
case EditEnvDlg.GG_RLS:
ID2 = ID - EditEnvDlg.GG_ATK + EditEnvDlg.GG_ATKCURVE;
ID3 = ID - EditEnvDlg.GG_ATK + EditEnvDlg.GG_ATKTIME;
associate = gui.getItemObj( ID2 );
associate2 = gui.getItemObj( ID3 );
if( (associate != null) && (associate2 != null) ) {
associate.setEnabled( ((JCheckBox) e.getSource()).isSelected() );
associate2.setEnabled( ((JCheckBox) e.getSource()).isSelected() );
}
break;
case EditEnvDlg.GG_PRESETS: // ------------------------------ Switch Preset ----------------
associate = gui.getItemObj( EditEnvDlg.GG_PRESETS );
if( associate != null ) {
name = ((JComboBox) associate).getSelectedItem().toString();
if( name != null ) {
pa = dlg.getPropertyArray();
preset = dlg.getPresets().getPreset( name );
pa.fromProperties( false, preset );
dlg.envelopeToGUI();
associate = gui.getItemObj( EditEnvDlg.GG_DELPRESET );
if( associate != null ) { // enable or disable del
associate.setEnabled( !name.equals( Presets.DEFAULT ));
}
}
}
break;
default:
break;
}
}
// -------- Mouse methods --------
public void mouseClicked(MouseEvent e) {
}
public void mousePressed(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {
}
public void mouseEntered(MouseEvent e) {
}
public void mouseExited(MouseEvent e) {
}
}
// class EditEnvDlgListener
}