mirror of
				https://github.com/hyperion-project/hyperion.ng.git
				synced 2025-03-01 10:33:28 +00:00 
			
		
		
		
	Finished the effect argument table (with storage to HyperCon settings)
Former-commit-id: e0e397b9df8c8dc1eb30f0a0fb5d2df0f7187809
This commit is contained in:
		| @@ -1,5 +1,6 @@ | ||||
| package org.hyperion.hypercon; | ||||
|  | ||||
| import java.awt.Color; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| @@ -12,9 +13,19 @@ import java.lang.reflect.ParameterizedType; | ||||
| import java.util.Properties; | ||||
| import java.util.Vector; | ||||
|  | ||||
| /** | ||||
|  * Class for supporting the serialisation and deserialisation of HyperCon settings. | ||||
|  */ | ||||
| public class ConfigurationFile { | ||||
| 	 | ||||
| 	/** Temporary storage of the HyperCon configuration */ | ||||
| 	private final Properties mProps = new Properties(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Loads the configuration of HyperCon from the given filename into this {@link ConfigurationFile} | ||||
| 	 *  | ||||
| 	 * @param pFilename The absolute filename containing the configuration | ||||
| 	 */ | ||||
| 	public void load(String pFilename) { | ||||
| 		mProps.clear(); | ||||
| //		try (InputStream in = new InflaterInputStream(new FileInputStream(pFilename))){ | ||||
| @@ -27,6 +38,11 @@ public class ConfigurationFile { | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Saves the configuration of this {@link ConfigurationFile} to the given filename | ||||
| 	 *  | ||||
| 	 * @param pFilename The absolute filename to which to save the HyperCon configuration | ||||
| 	 */ | ||||
| 	public void save(String pFilename) { | ||||
| //		try (OutputStream out = new DeflaterOutputStream(new FileOutputStream(pFilename))) { | ||||
| //		try (OutputStream out = new GZIPOutputStream(new FileOutputStream(pFilename))) { | ||||
| @@ -37,9 +53,22 @@ public class ConfigurationFile { | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Stores the given object to the local properties object | ||||
| 	 *  | ||||
| 	 * @param pObj The object to store | ||||
| 	 */ | ||||
| 	public void store(Object pObj) { | ||||
| 		store(pObj, pObj.getClass().getSimpleName(), ""); | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Stores the given object to the local properties object (with given preamble and postamble) | ||||
| 	 *  | ||||
| 	 * @param pObj The object to store | ||||
| 	 * @param preamble The preamble prepended to the key of the object members  | ||||
| 	 * @param postamble The postamble appended to the key of the object members | ||||
| 	 */ | ||||
| 	public void store(Object pObj, String preamble, String postamble) { | ||||
| 		String className = pObj.getClass().getSimpleName(); | ||||
| 		// Retrieve the member variables | ||||
| @@ -55,37 +84,80 @@ public class ConfigurationFile { | ||||
| 			try { | ||||
| 				Object value = field.get(pObj); | ||||
| 				 | ||||
| 				if (value.getClass().isEnum()) { | ||||
| 				if (field.getType() == boolean.class) { | ||||
| 					mProps.setProperty(key, Boolean.toString((boolean) value)); | ||||
| 				} else if (field.getType() == int.class) { | ||||
| 					mProps.setProperty(key, Integer.toString((int) value)); | ||||
| 				} else if (field.getType() == double.class) { | ||||
| 					mProps.setProperty(key, Double.toString((double) value)); | ||||
| 				} else if (field.getType() == String.class) { | ||||
| 					mProps.setProperty(key, (String)value); | ||||
| 				} else if (field.getType() == Color.class) { | ||||
| 					Color color = (Color)value; | ||||
| 					mProps.setProperty(key, String.format("[%d; %d; %d]", color.getRed(), color.getGreen(), color.getBlue())); | ||||
| 				} else if (value.getClass().isEnum()) { | ||||
| 					mProps.setProperty(key, ((Enum<?>)value).name()); | ||||
| 				} else if (value.getClass().isAssignableFrom(Vector.class)) { | ||||
| 				} else if (value instanceof Vector) { | ||||
| 					@SuppressWarnings("unchecked") | ||||
| 					Vector<Object> v = (Vector<Object>) value;  | ||||
| 					for (int i=0; i<v.size(); ++i) { | ||||
| 						store(v.get(i), key + "[" + i + "]", ""); | ||||
| 					} | ||||
| 				} else if (field.getType() == Object.class) { | ||||
| 					if (value instanceof Boolean) { | ||||
| 						mProps.setProperty(key, Boolean.toString((boolean) value)); | ||||
| 					} if (value instanceof Integer) { | ||||
| 						mProps.setProperty(key, Integer.toString((int) value)); | ||||
| 					} else if (value instanceof Double) { | ||||
| 						mProps.setProperty(key, Double.toString((double) value)); | ||||
| 					} else if (value instanceof Color) { | ||||
| 						Color color = (Color)value; | ||||
| 						mProps.setProperty(key, String.format("[%d; %d; %d]", color.getRed(), color.getGreen(), color.getBlue())); | ||||
| 					} else if (value instanceof String) { | ||||
| 						mProps.setProperty(key, '"' + (String)value + '"'); | ||||
| 					} | ||||
| 				} else { | ||||
| 					System.out.println("Might not be able to load: " + key + " = " + value.toString()); | ||||
| 					mProps.setProperty(key, value.toString()); | ||||
| 				} | ||||
| 			} catch (Throwable t) {}  | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Restores the object from the local properties object | ||||
| 	 *  | ||||
| 	 * @param pObj The object to restore | ||||
| 	 */ | ||||
| 	public void restore(Object pObj) { | ||||
| 		restore(pObj, mProps); | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Restores the object from the given object object | ||||
| 	 *  | ||||
| 	 * @param pObj  The object to restore | ||||
| 	 * @param pProps The properties containing values for the members of obj | ||||
| 	 */ | ||||
| 	public void restore(Object pObj, Properties pProps) { | ||||
| 		String className = pObj.getClass().getSimpleName(); | ||||
| 		restore(pObj, pProps, className + "."); | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Restores the object from the given settings object, using the given preamble | ||||
| 	 *  | ||||
| 	 * @param pObj The object to restore | ||||
| 	 * @param pProps The properties containing values for the members of obj | ||||
| 	 * @param pPreamble The preamble to use  | ||||
| 	 */ | ||||
| 	@SuppressWarnings("unchecked") | ||||
| 	public void restore(Object pObj, Properties pProps, String pPreamble) { | ||||
| 		// Retrieve the member variables | ||||
| 		Field[] fields = pObj.getClass().getDeclaredFields(); | ||||
| 		// Iterate each variable | ||||
| 		for (Field field : fields) { | ||||
| 			if (field.getType().isAssignableFrom(Vector.class)) { | ||||
| 			if (field.getType().equals(Vector.class)) { | ||||
| 				// Obtain the Vector | ||||
| 				Vector<Object> vector; | ||||
| 				try { | ||||
| @@ -157,19 +229,56 @@ public class ConfigurationFile { | ||||
| 					field.set(pObj, Integer.parseInt(value)); | ||||
| 				} else if (field.getType() == double.class) { | ||||
| 					field.set(pObj, Double.parseDouble(value)); | ||||
| 				} else if (field.getType() == Color.class) { | ||||
| 					String[] channelValues = value.substring(1, value.length()-1).split(";"); | ||||
| 					field.set(pObj, new Color(Integer.parseInt(channelValues[0].trim()), Integer.parseInt(channelValues[1].trim()), Integer.parseInt(channelValues[2].trim()))); | ||||
| 				} else if (field.getType() == String.class) { | ||||
| 					field.set(pObj, value); | ||||
| 				} else if (field.getType().isEnum()) { | ||||
| 					Method valMet = field.getType().getMethod("valueOf", String.class); | ||||
| 					Object enumVal = valMet.invoke(null, value); | ||||
| 					field.set(pObj, enumVal); | ||||
| 				} else { | ||||
| 					field.set(pObj, value); | ||||
| 				} else if (field.getType() == Object.class) { | ||||
| 					// We can not infer from the type of the field, let's try the actual stored value | ||||
| 					if (value.isEmpty()) { | ||||
| 						// We will never known ... | ||||
| 					} else if (value.startsWith("[") && value.endsWith("]")) { | ||||
| 						String[] channelValues = value.substring(1, value.length()-1).split(";"); | ||||
| 						field.set(pObj, new Color(Integer.parseInt(channelValues[0].trim()), Integer.parseInt(channelValues[1].trim()), Integer.parseInt(channelValues[2].trim()))); | ||||
| 					} else if (value.startsWith("\"") && value.endsWith("\"")) { | ||||
| 						field.set(pObj, value.substring(1, value.length()-1)); | ||||
| 					} else { | ||||
| 						try { | ||||
| 							int i = Integer.parseInt(value); | ||||
| 							field.set(pObj, i); | ||||
| 						} catch (Throwable t1) { | ||||
| 							try { | ||||
| 								double d = Double.parseDouble(value); | ||||
| 								field.set(pObj, d); | ||||
| 							} catch (Throwable t2) { | ||||
| 								try { | ||||
| 									boolean bool = Boolean.parseBoolean(value); | ||||
| 									field.set(pObj, bool); | ||||
| 								} catch (Throwable t3) { | ||||
| 									 | ||||
| 								} | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 			} catch (Throwable t) { | ||||
| 				System.out.println("Failed to parse value(" + value + ") for " + key); | ||||
| 				t.printStackTrace(); | ||||
| 			} | ||||
| 		}		 | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Returns a String representation of this ConfigurationFile, which is the {@link #toString()}  | ||||
| 	 * of the underlying {@link Properties} | ||||
| 	 *  | ||||
| 	 * @return The String representation of this ConfigurationFile | ||||
| 	 */ | ||||
| 	@Override | ||||
| 	public String toString() { | ||||
| 		return mProps.toString(); | ||||
|   | ||||
| @@ -16,7 +16,6 @@ import org.hyperion.hypercon.spec.MiscConfig; | ||||
|  * The full configuration of Hyperion with sub-items for device, color and miscelanuous items.  | ||||
|  */ | ||||
| public class LedString { | ||||
| 	 | ||||
| 	/** The configuration of the output device */ | ||||
| 	public final DeviceConfig mDeviceConfig = new DeviceConfig(); | ||||
|  | ||||
|   | ||||
| @@ -16,6 +16,9 @@ import org.hyperion.hypercon.gui.ConfigPanel; | ||||
|  */ | ||||
| public class Main { | ||||
| 	public static final String configFilename = "hypercon.dat"; | ||||
| 	 | ||||
| 	/** Some application settings (for easy/dirty access) */ | ||||
| 	public static final HyperConConfig HyperConConfig = new HyperConConfig(); | ||||
|  | ||||
| 	/** | ||||
| 	 * Entry point to start HyperCon  | ||||
| @@ -42,11 +45,13 @@ public class Main { | ||||
| 			@Override | ||||
| 			public void windowClosing(WindowEvent e) { | ||||
| 				ConfigurationFile configFile = new ConfigurationFile(); | ||||
| 				configFile.store(Main.HyperConConfig); | ||||
| 				configFile.store(ledString.mDeviceConfig); | ||||
| 				configFile.store(ledString.mLedFrameConfig); | ||||
| 				configFile.store(ledString.mProcessConfig); | ||||
| 				configFile.store(ledString.mColorConfig); | ||||
| 				configFile.store(ledString.mMiscConfig); | ||||
| 				configFile.store(ledString.mEffectEngineConfig); | ||||
| 				configFile.save(configFilename); | ||||
| 			} | ||||
| 		}); | ||||
| @@ -54,11 +59,18 @@ public class Main { | ||||
| 		if (new File(configFilename).exists()) { | ||||
| 			ConfigurationFile configFile = new ConfigurationFile(); | ||||
| 			configFile.load(configFilename); | ||||
| 			configFile.restore(Main.HyperConConfig); | ||||
| 			configFile.restore(ledString.mDeviceConfig); | ||||
| 			configFile.restore(ledString.mLedFrameConfig); | ||||
| 			configFile.restore(ledString.mProcessConfig); | ||||
| 			configFile.restore(ledString.mColorConfig); | ||||
| 			configFile.restore(ledString.mMiscConfig); | ||||
| 			configFile.restore(ledString.mEffectEngineConfig); | ||||
| 			 | ||||
| 			if (HyperConConfig.loadDefaultEffect) { | ||||
| 				ledString.mEffectEngineConfig.loadDefault(); | ||||
| 				HyperConConfig.loadDefaultEffect = false; | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		// Add the HyperCon configuration panel | ||||
|   | ||||
| @@ -21,6 +21,7 @@ import org.hyperion.hypercon.ConfigurationFile; | ||||
| import org.hyperion.hypercon.LedFrameFactory; | ||||
| import org.hyperion.hypercon.LedString; | ||||
| import org.hyperion.hypercon.Main; | ||||
| import org.hyperion.hypercon.gui.effectengine.EffectEnginePanel; | ||||
|  | ||||
| /** | ||||
|  * The main-config panel of HyperCon. Includes the configuration and the panels to edit and  | ||||
|   | ||||
| @@ -1,69 +0,0 @@ | ||||
| package org.hyperion.hypercon.gui; | ||||
|  | ||||
| import java.awt.Color; | ||||
| import java.awt.Component; | ||||
|  | ||||
| import javax.swing.AbstractCellEditor; | ||||
| import javax.swing.JCheckBox; | ||||
| import javax.swing.JColorChooser; | ||||
| import javax.swing.JSpinner; | ||||
| import javax.swing.JTable; | ||||
| import javax.swing.JTextField; | ||||
| import javax.swing.SpinnerNumberModel; | ||||
| import javax.swing.table.TableCellEditor; | ||||
|  | ||||
| public class EffectArgumentCellEditor extends AbstractCellEditor implements TableCellEditor { | ||||
|  | ||||
| 	int selEditor = 0; | ||||
| 	 | ||||
| 	private JSpinner mIntegerSpinner = new JSpinner(new SpinnerNumberModel(0, Integer.MIN_VALUE, Integer.MAX_VALUE, 1)); | ||||
| 	private JSpinner mDoubleSpinner  = new JSpinner(new SpinnerNumberModel(0.0, -Double.MAX_VALUE, Double.MAX_VALUE, 1.0)); | ||||
| 	private JCheckBox mBooleanCheck = new JCheckBox(); | ||||
| 	private JColorChooser mColorChooser = new JColorChooser(); | ||||
| 	private JTextField mStringEditor = new JTextField(); | ||||
| 	 | ||||
| 	 | ||||
| 	 | ||||
| 	@Override | ||||
| 	public Object getCellEditorValue() { | ||||
| 		switch (selEditor) { | ||||
| 		case 0: | ||||
| 			return mIntegerSpinner.getValue(); | ||||
| 		case 1: | ||||
| 			return mDoubleSpinner.getValue(); | ||||
| 		case 2: | ||||
| 			return mBooleanCheck.isSelected(); | ||||
| 		case 3: | ||||
| 			return mStringEditor.getText(); | ||||
| 		case 4: | ||||
| 			return mColorChooser.getColor(); | ||||
| 		} | ||||
| 		 | ||||
| 		return null; | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { | ||||
| 		if (value instanceof Integer) { | ||||
| 			selEditor = 0; | ||||
| 			mIntegerSpinner.setValue((Integer)value); | ||||
| 			return mIntegerSpinner; | ||||
| 		} else if (value instanceof Double) { | ||||
| 			selEditor = 1; | ||||
| 			mDoubleSpinner.setValue((Double)value); | ||||
| 			return mDoubleSpinner; | ||||
| 		} else if (value instanceof Boolean) { | ||||
| 			selEditor = 2; | ||||
| 			mBooleanCheck.setSelected((Boolean)value); | ||||
| 			return mBooleanCheck; | ||||
| 		} else if (value instanceof Color) { | ||||
| 			selEditor = 4; | ||||
| //			return mColorCombo; | ||||
| 		} | ||||
| 		 | ||||
| 		selEditor = 3; | ||||
| 		mStringEditor.setText('"' + value.toString() + '"'); | ||||
| 		return mStringEditor; | ||||
| 	} | ||||
|  | ||||
| } | ||||
| @@ -1,364 +0,0 @@ | ||||
| package org.hyperion.hypercon.gui; | ||||
|  | ||||
| import java.awt.BorderLayout; | ||||
| import java.awt.Component; | ||||
| import java.awt.Dimension; | ||||
| import java.awt.event.ActionEvent; | ||||
| import java.awt.event.ActionListener; | ||||
| import java.util.Vector; | ||||
|  | ||||
| import javax.swing.BorderFactory; | ||||
| import javax.swing.BoxLayout; | ||||
| import javax.swing.ComboBoxEditor; | ||||
| import javax.swing.DefaultComboBoxModel; | ||||
| import javax.swing.JButton; | ||||
| import javax.swing.JComboBox; | ||||
| import javax.swing.JLabel; | ||||
| import javax.swing.JOptionPane; | ||||
| import javax.swing.JPanel; | ||||
| import javax.swing.JScrollPane; | ||||
| import javax.swing.JTable; | ||||
| import javax.swing.JTextField; | ||||
| import javax.swing.table.AbstractTableModel; | ||||
| import javax.swing.table.TableColumn; | ||||
|  | ||||
| import org.hyperion.hypercon.spec.EffectConfig; | ||||
| import org.hyperion.hypercon.spec.EffectEngineConfig; | ||||
|  | ||||
| public class EffectEnginePanel extends JPanel { | ||||
|  | ||||
| 	private final EffectEngineConfig mEffectEngingeConfig; | ||||
| 	 | ||||
| 	private final DefaultComboBoxModel<EffectConfig> mEffectModel; | ||||
| 	 | ||||
| 	private JPanel mControlPanel; | ||||
| 	private JComboBox<EffectConfig> mEffectCombo; | ||||
| 	private JButton mCloneButton; | ||||
| 	private JButton mAddButton; | ||||
| 	private JButton mDelButton; | ||||
| 	 | ||||
| 	private JPanel mEffectPanel; | ||||
| 	private JLabel mPythonLabel; | ||||
| 	private JComboBox<String> mPythonCombo; | ||||
| 	private JPanel mEffectArgumentPanel; | ||||
| 	private JTable mEffectArgumentTable; | ||||
| 	 | ||||
| 	private AbstractTableModel mEffectArgumentTableModel = new AbstractTableModel() { | ||||
| 		 | ||||
| 		@Override | ||||
| 		public boolean isCellEditable(int rowIndex, int columnIndex) { | ||||
| 			EffectConfig effect = (EffectConfig) mEffectModel.getSelectedItem(); | ||||
| 			if (effect == null) { | ||||
| 				return false; | ||||
| 			} | ||||
| 			if (rowIndex == effect.mArgs.size()) { | ||||
| 				return columnIndex == 0; | ||||
| 			} | ||||
| 			return true; | ||||
| 		}; | ||||
| 		 | ||||
| 		@Override | ||||
| 		public int getColumnCount() { | ||||
| 			return 2; | ||||
| 		} | ||||
| 		 | ||||
| 		@Override | ||||
| 		public String getColumnName(int column) { | ||||
| 			switch (column) { | ||||
| 			case 0: | ||||
| 				return "name"; | ||||
| 			case 1: | ||||
| 				return "value"; | ||||
| 			} | ||||
| 			return ""; | ||||
| 		}; | ||||
| 		 | ||||
| 		@Override | ||||
| 		public int getRowCount() { | ||||
| 			EffectConfig effect = (EffectConfig) mEffectModel.getSelectedItem(); | ||||
| 			if (effect == null) { | ||||
| 				return 0; | ||||
| 			} | ||||
| 			return effect.mArgs.size() + 1; | ||||
| 		} | ||||
| 		 | ||||
| 		@Override | ||||
| 		public Object getValueAt(int rowIndex, int columnIndex) { | ||||
| 			EffectConfig effect = (EffectConfig) mEffectModel.getSelectedItem(); | ||||
| 			if (effect == null) { | ||||
| 				return ""; | ||||
| 			} | ||||
| 			if (rowIndex == effect.mArgs.size()) { | ||||
| 				if (columnIndex == 0) { | ||||
| 					return "[key]"; | ||||
| 				} | ||||
| 				return ""; | ||||
| 			} | ||||
| 			if (columnIndex == 0) { | ||||
| 				return effect.mArgs.get(rowIndex).key; | ||||
| 			} else if (columnIndex == 1){ | ||||
| 				return effect.mArgs.get(rowIndex).value; | ||||
| 				 | ||||
| 			} | ||||
| 			return ""; | ||||
| 		} | ||||
| 		 | ||||
| 		@Override | ||||
| 		public void setValueAt(Object aValue, int rowIndex, int columnIndex) { | ||||
| 			EffectConfig effect = (EffectConfig) mEffectModel.getSelectedItem(); | ||||
| 			if (effect == null) { | ||||
| 				return; | ||||
| 			} | ||||
| 			 | ||||
| 			if (rowIndex == effect.mArgs.size()) { | ||||
| 				String key = aValue.toString().trim(); | ||||
| 				if (key.isEmpty() || key.equals("[key]")) { | ||||
| 					return; | ||||
| 				} | ||||
| 				 | ||||
| 				effect.mArgs.addElement(new EffectConfig.EffectArg(aValue.toString(), "")); | ||||
| 				return; | ||||
| 			} | ||||
| 			if (columnIndex == 0) { | ||||
| 				String key = aValue.toString().trim(); | ||||
| 				if (key.isEmpty()) { | ||||
| 					effect.mArgs.remove(rowIndex); | ||||
| 				} else { | ||||
| 					effect.mArgs.get(rowIndex).key = (String)aValue; | ||||
| 				} | ||||
| 			} else { | ||||
| 				if (aValue instanceof String) { | ||||
| 					// Get the value without any trailing or leading spaces | ||||
| 					String str = ((String)aValue).trim(); | ||||
| 					if (str.charAt(0) == '"' && str.charAt(str.length()-1) == '"') { | ||||
| 						// If the string is quoted it is an actual string  | ||||
| 						String actStr = str.substring(1, str.length()-1); | ||||
| 						if (actStr.contains("\"")) { | ||||
| 							// String can not contain quotes | ||||
| 						} else { | ||||
| 							effect.mArgs.get(rowIndex).value = actStr; | ||||
| 						} | ||||
| 					} else { | ||||
| 						// The string is not a string, let's find out what it is | ||||
| 						if (str.equalsIgnoreCase("true") || str.equalsIgnoreCase("false")) { | ||||
| 							// It is a BOOLEAN | ||||
| 							effect.mArgs.get(rowIndex).value = str.equalsIgnoreCase("true"); | ||||
| 						} else { | ||||
| 							try { | ||||
| 								int intVal = Integer.parseInt(str); | ||||
| 								// It is an INT | ||||
| 								effect.mArgs.get(rowIndex).value = intVal; | ||||
| 							} catch (Throwable t1) { | ||||
| 								// It was not an integer apparently | ||||
| 								try { | ||||
| 									double doubleVal = Double.parseDouble(str); | ||||
| 									effect.mArgs.get(rowIndex).value = doubleVal; | ||||
| 								} catch (Throwable t2) { | ||||
| 									// It was not an double apparently .... | ||||
| 								} | ||||
| 											 | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 						 | ||||
| 				} else { | ||||
| 					effect.mArgs.get(rowIndex).value = aValue; | ||||
| 				} | ||||
| 			} | ||||
| 		}; | ||||
| 	}; | ||||
| 	 | ||||
| 	public EffectEnginePanel(final EffectEngineConfig pEffectEngineConfig) { | ||||
| 		super(); | ||||
| 		 | ||||
| 		mEffectEngingeConfig = pEffectEngineConfig; | ||||
| 		mEffectModel = new DefaultComboBoxModel<EffectConfig>(mEffectEngingeConfig.mEffects); | ||||
| 		 | ||||
| 		initialise(); | ||||
| 		 | ||||
| 		effectSelectionChanged(); | ||||
| 	} | ||||
| 	 | ||||
| 	private void initialise() { | ||||
| 		setLayout(new BorderLayout()); | ||||
| 		 | ||||
| 		add(getControlPanel(), BorderLayout.NORTH); | ||||
| 		add(getEffectPanel(), BorderLayout.CENTER); | ||||
| 	} | ||||
| 	 | ||||
| 	private void effectSelectionChanged() { | ||||
| 		EffectConfig effect = (EffectConfig)mEffectModel.getSelectedItem(); | ||||
| 		 | ||||
| 		// Enable option for the selected effect or disable if none selected | ||||
| 		mEffectPanel.setEnabled(effect != null); | ||||
| 		mPythonLabel.setEnabled(effect != null); | ||||
| 		mPythonCombo.setEnabled(effect != null); | ||||
| 		mEffectArgumentTable.setEnabled(effect != null); | ||||
| 		 | ||||
| 		 | ||||
| 		if (effect == null) { | ||||
| 			// Clear all fields | ||||
| 			mPythonCombo.setSelectedIndex(-1); | ||||
| 			mEffectArgumentTableModel.fireTableDataChanged(); | ||||
| 			return; | ||||
| 		} else { | ||||
| 			// Update fields based on the selected effect | ||||
| 			mPythonCombo.setSelectedItem(effect.mScript); | ||||
| 			mEffectArgumentTableModel.fireTableDataChanged(); | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	private JPanel getControlPanel() { | ||||
| 		if (mControlPanel == null) { | ||||
| 			mControlPanel = new JPanel(); | ||||
| 			mControlPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 2, 5)); | ||||
| 			mControlPanel.setPreferredSize(new Dimension(150, 25)); | ||||
| 			mControlPanel.setLayout(new BoxLayout(mControlPanel, BoxLayout.LINE_AXIS)); | ||||
| 			 | ||||
| 			mEffectCombo = new JComboBox<>(mEffectModel); | ||||
| 			mEffectCombo.setEditable(true); | ||||
| 			mEffectCombo.setEditor(new ComboBoxEditor() { | ||||
| 				private final JTextField mTextField = new JTextField(); | ||||
| 				 | ||||
| 				private EffectConfig mCurrentEffect = null; | ||||
| 				 | ||||
| 				@Override | ||||
| 				public void setItem(Object anObject) { | ||||
| 					if (anObject instanceof EffectConfig) { | ||||
| 						mCurrentEffect = (EffectConfig) anObject; | ||||
| 						mTextField.setText(mCurrentEffect.mId); | ||||
| 					} | ||||
| 				} | ||||
| 				 | ||||
| 				@Override | ||||
| 				public void selectAll() { | ||||
| 					if (mCurrentEffect == null) { | ||||
| 						return; | ||||
| 					} | ||||
| 					mTextField.setText(mCurrentEffect.mId); | ||||
| 					mTextField.setSelectionStart(0); | ||||
| 					mTextField.setSelectionEnd(mCurrentEffect.mId.length()-1); | ||||
| 				} | ||||
| 				 | ||||
| 				@Override | ||||
| 				public Object getItem() { | ||||
| 					String newId = mTextField.getText().trim(); | ||||
| 					if (newId.isEmpty() || newId.contains("\"")) { | ||||
| 						return mCurrentEffect; | ||||
| 					} | ||||
| 					mCurrentEffect.mId = newId; | ||||
| 					return mCurrentEffect;				} | ||||
| 				 | ||||
| 				@Override | ||||
| 				public Component getEditorComponent() { | ||||
| 					return mTextField; | ||||
| 				} | ||||
| 				 | ||||
| 				private final Vector<ActionListener> mActionListeners = new Vector<>(); | ||||
| 				@Override | ||||
| 				public void addActionListener(ActionListener l) { | ||||
| 					mActionListeners.add(l); | ||||
| 				} | ||||
| 				@Override | ||||
| 				public void removeActionListener(ActionListener l) { | ||||
| 					mActionListeners.remove(l); | ||||
| 				} | ||||
| 			}); | ||||
| 			mEffectCombo.addActionListener(new ActionListener() { | ||||
| 				@Override | ||||
| 				public void actionPerformed(ActionEvent e) { | ||||
| 					effectSelectionChanged(); | ||||
| 				} | ||||
| 			}); | ||||
| 			mControlPanel.add(mEffectCombo); | ||||
| 			 | ||||
| 			mCloneButton = new JButton("Clone"); | ||||
| 			mCloneButton.addActionListener(new ActionListener() { | ||||
| 				@Override | ||||
| 				public void actionPerformed(ActionEvent e) { | ||||
| 					EffectConfig effect = (EffectConfig) mEffectModel.getSelectedItem(); | ||||
| 					EffectConfig effectClone = effect.clone(); | ||||
| 					effectClone.mId += " [clone]"; | ||||
| 					mEffectModel.addElement(effectClone); | ||||
| 					mEffectModel.setSelectedItem(effectClone); | ||||
| 				} | ||||
| 			}); | ||||
| 			mControlPanel.add(mCloneButton); | ||||
| 			 | ||||
| 			mAddButton = new JButton("Add"); | ||||
| 			mAddButton.addActionListener(new ActionListener() { | ||||
| 				@Override | ||||
| 				public void actionPerformed(ActionEvent e) { | ||||
| 					String newId = JOptionPane.showInputDialog(mAddButton, "Name of the new effect: ", "Effect Name", JOptionPane.QUESTION_MESSAGE); | ||||
| 					// Make that an ID is set | ||||
| 					if (newId == null || newId.isEmpty()) { | ||||
| 						return; | ||||
| 					} | ||||
| 					// Make sure the ID does not yet exist | ||||
| 					for (EffectConfig effect : mEffectEngingeConfig.mEffects) { | ||||
| 						if (effect.mId.equalsIgnoreCase(newId)) { | ||||
| 							JOptionPane.showMessageDialog(mAddButton, "Given name(" + effect.mId + ") allready exists", "Duplicate effect name", JOptionPane.ERROR_MESSAGE); | ||||
| 							return; | ||||
| 						} | ||||
| 					} | ||||
| 					 | ||||
| 					EffectConfig newConfig = new EffectConfig(); | ||||
| 					newConfig.mId = newId; | ||||
| 					mEffectModel.addElement(newConfig); | ||||
| 					mEffectModel.setSelectedItem(newConfig); | ||||
| 				} | ||||
| 			}); | ||||
| 			mControlPanel.add(mAddButton); | ||||
| 			 | ||||
| 			mDelButton = new JButton("Del"); | ||||
| 			mDelButton.setEnabled(mEffectModel.getSize() > 0); | ||||
| 			mDelButton.addActionListener(new ActionListener() { | ||||
| 				@Override | ||||
| 				public void actionPerformed(ActionEvent e) { | ||||
| 					if (mEffectModel.getSelectedItem() != null) { | ||||
| 						mEffectModel.removeElement(mEffectModel.getSelectedItem()); | ||||
| 					} | ||||
| 					mDelButton.setEnabled(mEffectModel.getSize() > 0); | ||||
| 				} | ||||
| 			}); | ||||
| 			mControlPanel.add(mDelButton); | ||||
| 		} | ||||
| 		return mControlPanel; | ||||
| 	} | ||||
| 	 | ||||
| 	private JPanel getEffectPanel() { | ||||
| 		if (mEffectPanel == null) { | ||||
| 			mEffectPanel = new JPanel(); | ||||
| 			mEffectPanel.setBorder(BorderFactory.createTitledBorder("")); | ||||
| 			mEffectPanel.setLayout(new BoxLayout(mEffectPanel, BoxLayout.PAGE_AXIS)); | ||||
| 			 | ||||
| 			JPanel subPanel = new JPanel(new BorderLayout()); | ||||
| 			subPanel.setPreferredSize(new Dimension(150, 25)); | ||||
| 			subPanel.setMaximumSize(new Dimension(20000, 20)); | ||||
| 			mEffectPanel.add(subPanel); | ||||
| 			 | ||||
| 			mPythonLabel = new JLabel("Python: "); | ||||
| 			subPanel.add(mPythonLabel, BorderLayout.WEST); | ||||
| 			 | ||||
| 			mPythonCombo = new JComboBox<>(new String[] {"test.py", "rainbow-swirl.py", "rainbow-mood.py"}); | ||||
| //			mPythonCombo.setEditable(true); | ||||
| 			mPythonCombo.setMaximumSize(new Dimension(150, 25)); | ||||
| 			subPanel.add(mPythonCombo); | ||||
|  | ||||
| 			mEffectArgumentPanel = new JPanel(); | ||||
| 			mEffectArgumentPanel.setBorder(BorderFactory.createTitledBorder("Arguments")); | ||||
| 			mEffectArgumentPanel.setLayout(new BorderLayout()); | ||||
| 			 | ||||
| 			mEffectArgumentTable = new JTable(mEffectArgumentTableModel); | ||||
| 			mEffectArgumentPanel.add(new JScrollPane(mEffectArgumentTable)); | ||||
| 			 | ||||
| 			mEffectPanel.add(mEffectArgumentPanel); | ||||
| 			 | ||||
| 			TableColumn col = mEffectArgumentTable.getColumnModel().getColumn(1); | ||||
| 			col.setCellEditor(new EffectArgumentCellEditor()); | ||||
|  | ||||
| 			mEffectArgumentTable.setCellEditor(new EffectArgumentCellEditor()); | ||||
| 		} | ||||
| 		return mEffectPanel; | ||||
| 	} | ||||
| } | ||||
| @@ -18,14 +18,29 @@ public class EffectConfig { | ||||
| 	/** The arguments (key-value) of the python-script */ | ||||
| 	public final Vector<EffectArg> mArgs = new Vector<>(); | ||||
| 	 | ||||
| 	/** | ||||
| 	 * The effect argument contains a key-value combination that holds a single argument of an  | ||||
| 	 * effect | ||||
| 	 */ | ||||
| 	static public class EffectArg { | ||||
| 		/** The key of the effect argument */ | ||||
| 		public String key; | ||||
| 		/** The value of the effect argument */ | ||||
| 		public Object value; | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Constructs an new effect argument with empty key and value | ||||
| 		 */ | ||||
| 		public EffectArg() { | ||||
| 			key = ""; | ||||
| 			value = ""; | ||||
| 			this("", ""); | ||||
| 		} | ||||
| 		 | ||||
| 		/** | ||||
| 		 * Constructs an effect argument with the given key and value | ||||
| 		 *   | ||||
| 		 * @param pKey The key of the new argument | ||||
| 		 * @param pValue The value of the new argument | ||||
| 		 */ | ||||
| 		public EffectArg(String pKey, Object pValue) { | ||||
| 			key = pKey; | ||||
| 			value = pValue; | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| package org.hyperion.hypercon.spec; | ||||
|  | ||||
| import java.awt.Color; | ||||
| import java.util.Vector; | ||||
|  | ||||
| import org.hyperion.hypercon.JsonStringBuffer; | ||||
| @@ -12,7 +11,18 @@ import org.hyperion.hypercon.JsonStringBuffer; | ||||
| public class EffectEngineConfig { | ||||
|  | ||||
| 	public final Vector<EffectConfig> mEffects = new Vector<>(); | ||||
| 	{ | ||||
| 	 | ||||
| 	public void appendTo(JsonStringBuffer pJsonBuf) { | ||||
| 		pJsonBuf.startObject("effects"); | ||||
| 		 | ||||
| 		for (EffectConfig effect : mEffects) { | ||||
| 			effect.append(pJsonBuf, effect.equals(mEffects.get(mEffects.size()-1))); | ||||
| 		} | ||||
| 		 | ||||
| 		pJsonBuf.stopObject(); | ||||
| 	} | ||||
|  | ||||
| 	public void loadDefault() { | ||||
| 		EffectConfig rainbowSwirl = new EffectConfig(); | ||||
| 		rainbowSwirl.mId = "Rainbow swirl"; | ||||
| 		rainbowSwirl.mScript = "rainbow-swirl.py"; | ||||
| @@ -26,20 +36,8 @@ public class EffectEngineConfig { | ||||
| 		rainbowMood.mArgs.add(new EffectConfig.EffectArg("rotation-time", 10.0));  | ||||
| 		rainbowMood.mArgs.add(new EffectConfig.EffectArg("brightness", 1.0));  | ||||
| 		rainbowMood.mArgs.add(new EffectConfig.EffectArg("reverse", false));  | ||||
| 		rainbowMood.mArgs.add(new EffectConfig.EffectArg("test", "test"));  | ||||
| 		rainbowMood.mArgs.add(new EffectConfig.EffectArg("AColor", Color.RED)); | ||||
| 		 | ||||
| 		mEffects.add(rainbowSwirl); | ||||
| 		mEffects.add(rainbowMood); | ||||
| 	} | ||||
| 	 | ||||
| 	public void appendTo(JsonStringBuffer pJsonBuf) { | ||||
| 		pJsonBuf.startObject("effects"); | ||||
| 		 | ||||
| 		for (EffectConfig effect : mEffects) { | ||||
| 			effect.append(pJsonBuf, effect.equals(mEffects.get(mEffects.size()-1))); | ||||
| 		} | ||||
| 		 | ||||
| 		pJsonBuf.stopObject(); | ||||
| 	} | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user