package org.jwildfire.create.tina.swing;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JToggleButton;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.jwildfire.base.Prefs;
import org.jwildfire.base.Tools;
import org.jwildfire.create.tina.base.XForm;
import org.jwildfire.create.tina.variation.Variation;
import org.jwildfire.create.tina.variation.VariationFuncList;
public class TinaNonlinearControlsRow {
private TinaController tinaController;
private final int index;
private final JPanel rootPanel;
private final JComboBox nonlinearVarCmb;
private final JComboBox nonlinearParamsCmb;
private final JWFNumberField nonlinearVarREd;
private final JWFNumberField nonlinearParamsREd;
private final JButton nonlinearParamsLeftButton;
private final JToggleButton nonlinearParamsPreButton;
private final JToggleButton nonlinearParamsPostButton;
private final JButton nonlinearParamsUpButton;
private final JToggleButton toggleParamsPnlButton;
private final List<JComponent> paramsPnlComponents = new ArrayList<>();
private final Map<String, JWFNumberField> paramsPnlNumberFields = new HashMap<>();
private final Map<String, JSlider> paramsPnlSliders = new HashMap<>();
private final int rootPnlBaseWidth, rootPnlBaseHeight;
private int extraPanelSize;
private boolean noRefresh;
public TinaNonlinearControlsRow(int pIndex, JPanel pRootPanel, JComboBox pNonlinearVarCmb, JComboBox pNonlinearParamsCmb, JWFNumberField pNonlinearVarREd, JWFNumberField pNonlinearParamsREd,
JButton pNonlinearParamsLeftButton, JToggleButton pNonlinearParamsPreButton, JToggleButton pNonlinearParamsPostButton, JButton pNonlinearParamsUpButton,
JToggleButton pToggleParamsPnlButton) {
index = pIndex;
rootPanel = pRootPanel;
rootPnlBaseWidth = rootPanel.getPreferredSize().width;
rootPnlBaseHeight = rootPanel.getPreferredSize().height;
nonlinearVarCmb = pNonlinearVarCmb;
nonlinearParamsCmb = pNonlinearParamsCmb;
nonlinearVarREd = pNonlinearVarREd;
nonlinearParamsREd = pNonlinearParamsREd;
nonlinearParamsLeftButton = pNonlinearParamsLeftButton;
nonlinearParamsPreButton = pNonlinearParamsPreButton;
nonlinearParamsPostButton = pNonlinearParamsPostButton;
nonlinearParamsUpButton = pNonlinearParamsUpButton;
toggleParamsPnlButton = pToggleParamsPnlButton;
}
public void initControls() {
nonlinearVarCmb.removeAllItems();
List<String> nameList = new ArrayList<String>();
nameList.addAll(VariationFuncList.getNameList());
Collections.sort(nameList);
nonlinearVarCmb.addItem(null);
for (String name : nameList) {
nonlinearVarCmb.addItem(name);
}
nonlinearVarCmb.setSelectedIndex(-1);
nonlinearParamsCmb.removeAllItems();
nonlinearParamsCmb.setSelectedIndex(-1);
nonlinearParamsPreButton.setSelected(false);
nonlinearParamsPostButton.setSelected(false);
}
public JComboBox getNonlinearVarCmb() {
return nonlinearVarCmb;
}
public JComboBox getNonlinearParamsCmb() {
return nonlinearParamsCmb;
}
public JWFNumberField getNonlinearVarREd() {
return nonlinearVarREd;
}
public JWFNumberField getNonlinearParamsREd() {
return nonlinearParamsREd;
}
public JButton getNonlinearParamsLeftButton() {
return nonlinearParamsLeftButton;
}
public JToggleButton getNonlinearParamsPreButton() {
return nonlinearParamsPreButton;
}
public JToggleButton getNonlinearParamsPostButton() {
return nonlinearParamsPostButton;
}
public JButton getNonlinearParamsUpButton() {
return nonlinearParamsUpButton;
}
public JToggleButton getToggleParamsPnlButton() {
return toggleParamsPnlButton;
}
private void removeParamsPnlComponents() {
for (JComponent comp : paramsPnlComponents) {
try {
rootPanel.remove(comp);
}
catch (Exception ex) {
ex.printStackTrace();
}
}
paramsPnlComponents.clear();
paramsPnlNumberFields.clear();
paramsPnlSliders.clear();
}
private void refreshView() {
rootPanel.invalidate();
rootPanel.validate();
rootPanel.repaint();
rootPanel.getParent().invalidate();
rootPanel.getParent().validate();
rootPanel.getParent().repaint();
rootPanel.getParent().getParent().invalidate();
rootPanel.getParent().getParent().validate();
rootPanel.getParent().getParent().repaint();
}
public void rebuildParamsPnl(XForm pXForm, Variation pVar) {
removeParamsPnlComponents();
resizeRootPnl(rootPnlBaseHeight);
if (toggleParamsPnlButton.isSelected() && pXForm != null && pVar != null) {
createParamsPnlComponents(pXForm, pVar);
}
refreshView();
}
private final int ROW_HEIGHT = 22;
private final int LBL_WIDTH = 72;
private final int LBL_H_OFFSET = 12;
private final int LBL_V_OFFSET = -2;
private final int NUMBERFIELD_WIDTH = 72;
private final int NUMBERFIELD_H_OFFSET = 92;
private final int NUMBERFIELD_V_OFFSET = -2;
private final int SLIDER_WIDTH = 112;
private final int SLIDER_H_OFFSET = 170;
private final int SLIDER_V_OFFSET = 0;
private final int SLIDER_SCALE = 1000;
private void createParamsPnlComponents(XForm pXForm, Variation pVar) {
if (pXForm != null && pVar != null) {
String[] paramNames = pVar.getFunc().getParameterNames();
if (paramNames != null && paramNames.length > 1) {
int pnlHeight = rootPnlBaseHeight;
Object[] paramValues = pVar.getFunc().getParameterValues();
for (int i = 0; i < paramNames.length; i++) {
addLabel(paramNames[i], pnlHeight);
addNumberField(paramNames[i], paramValues[i], pnlHeight);
addSlider(paramNames[i], paramValues[i], pnlHeight);
pnlHeight += ROW_HEIGHT;
}
pnlHeight += 2;
resizeRootPnl(pnlHeight);
}
}
}
private void resizeRootPnl(int pnlHeight) {
rootPanel.setSize(rootPnlBaseWidth, pnlHeight);
rootPanel.setPreferredSize(new Dimension(rootPnlBaseWidth, pnlHeight));
extraPanelSize = pnlHeight - rootPnlBaseHeight;
}
private void addLabel(String pName, int pOffset) {
JLabel lbl = new JLabel();
lbl.setPreferredSize(new Dimension(50, 22));
lbl.setText(pName);
lbl.setSize(new Dimension(LBL_WIDTH, 22));
lbl.setLocation(new Point(LBL_H_OFFSET, LBL_V_OFFSET + pOffset));
lbl.setFont(Prefs.getPrefs().getFont("Dialog", Font.BOLD, 10));
rootPanel.add(lbl, null);
paramsPnlComponents.add(lbl);
}
private void addNumberField(final String pParamName, Object pParamValue, int pOffset) {
final JWFNumberField field = new JWFNumberField();
field.setValueStep(0.01);
field.setPreferredSize(new Dimension(56, 24));
field.setText("");
field.setSize(new Dimension(NUMBERFIELD_WIDTH, 24));
field.setLocation(new Point(NUMBERFIELD_H_OFFSET, NUMBERFIELD_V_OFFSET + pOffset));
field.setFont(Prefs.getPrefs().getFont("Dialog", Font.PLAIN, 10));
if (pParamValue != null) {
if (pParamValue instanceof Integer) {
field.setOnlyIntegers(true);
field.setValue((Integer) pParamValue);
}
else {
field.setValue((Double) pParamValue);
}
}
rootPanel.add(field, null);
paramsPnlComponents.add(field);
paramsPnlNumberFields.put(pParamName, field);
field.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
if (tinaController != null && !isNoRefresh()) {
if (!field.isMouseAdjusting() || field.getMouseChangeCount() == 0) {
tinaController.saveUndoPoint();
}
double doubleVal = 0.0;
Object fieldVal = field.getValue();
if (fieldVal != null) {
if (fieldVal instanceof Integer) {
doubleVal = (Integer) fieldVal;
}
else {
doubleVal = (Double) fieldVal;
}
}
tinaController.propertyPnlValueChanged(index, pParamName, doubleVal);
refreshSliderWithoutRefresh(pParamName, doubleVal);
refreshNonlinearParamsCmbWithoutRefresh(pParamName, doubleVal);
}
}
});
}
private void refreshSliderWithoutRefresh(String pParamName, double pValue) {
boolean oldNoRefresh = isNoRefresh();
setNoRefresh(true);
try {
JSlider slider = paramsPnlSliders.get(pParamName);
if (slider != null) {
int val = Tools.FTOI(pValue * SLIDER_SCALE);
refreshSliderLimits(slider, val);
slider.setValue(val);
}
}
finally {
setNoRefresh(oldNoRefresh);
}
}
private void refreshNumberFieldWithoutRefresh(String pParamName, double pValue) {
boolean oldNoRefresh = isNoRefresh();
setNoRefresh(true);
try {
JWFNumberField field = paramsPnlNumberFields.get(pParamName);
if (field != null) {
if (field.isOnlyIntegers()) {
field.setValue(Tools.FTOI(pValue));
}
else {
field.setValue(pValue);
}
}
}
finally {
setNoRefresh(oldNoRefresh);
}
}
private void refreshNonlinearParamsCmbWithoutRefresh(String pParamName, double pValue) {
if (nonlinearParamsCmb.getSelectedItem() != null && pParamName.equals(nonlinearParamsCmb.getSelectedItem())) {
boolean oldNoRefresh = isNoRefresh();
setNoRefresh(true);
try {
boolean oldCtrlRefresh = tinaController.cmbRefreshing;
tinaController.cmbRefreshing = true;
try {
if (nonlinearParamsREd.isOnlyIntegers()) {
nonlinearParamsREd.setValue(Tools.FTOI(pValue));
}
else {
nonlinearParamsREd.setValue(pValue);
}
}
finally {
tinaController.cmbRefreshing = oldCtrlRefresh;
}
}
finally {
setNoRefresh(oldNoRefresh);
}
}
}
private void addSlider(final String pParamName, final Object pParamValue, int pOffset) {
final JSlider slider = new JSlider();
slider.setSize(new Dimension(SLIDER_WIDTH, 19));
slider.setLocation(new Point(SLIDER_H_OFFSET, SLIDER_V_OFFSET + pOffset));
double min = -5.0;
double max = 5.0;
double val = 0.0;
if (pParamValue != null) {
if (pParamValue instanceof Integer) {
Integer iVal = (Integer) pParamValue;
val = iVal;
min = val - 5;
max = val + 5;
}
else {
val = (Double) pParamValue;
if (val < min + 1.0) {
min = Tools.FTOI(val - 1.0);
}
if (val > max - 1.0) {
max = Tools.FTOI(val + 1.0);
}
}
}
slider.setMinimum(Tools.FTOI(SLIDER_SCALE * min));
slider.setMaximum(Tools.FTOI(SLIDER_SCALE * max));
slider.setValue(Tools.FTOI(SLIDER_SCALE * val));
slider.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
tinaController.saveUndoPoint();
}
});
slider.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent e) {
if (!isNoRefresh()) {
double sliderVal = (double) slider.getValue() / (double) SLIDER_SCALE;
tinaController.propertyPnlValueChanged(index, pParamName, sliderVal);
refreshNumberFieldWithoutRefresh(pParamName, sliderVal);
refreshNonlinearParamsCmbWithoutRefresh(pParamName, sliderVal);
}
}
});
rootPanel.add(slider, null);
paramsPnlComponents.add(slider);
paramsPnlSliders.put(pParamName, slider);
}
public void refreshParamWithoutRefresh(String pParamName, double pValue) {
JWFNumberField field = paramsPnlNumberFields.get(pParamName);
JSlider slider = paramsPnlSliders.get(pParamName);
if (field != null || slider != null) {
boolean oldNoRefresh = isNoRefresh();
setNoRefresh(true);
try {
if (field != null) {
if (field.isOnlyIntegers()) {
field.setValue(Tools.FTOI(pValue));
}
else {
field.setValue(pValue);
}
}
if (slider != null) {
int val = Tools.FTOI(pValue * SLIDER_WIDTH);
refreshSliderLimits(slider, val);
slider.setValue(val);
}
}
finally {
setNoRefresh(oldNoRefresh);
}
}
}
private void refreshSliderLimits(JSlider pSlider, int pValue) {
if (pValue < pSlider.getMinimum() + 10) {
pSlider.setMinimum(pValue - 100);
}
else if (pValue > pSlider.getMaximum() - 10) {
pSlider.setMaximum(pValue + 100);
}
}
public void setTinaController(TinaController pTinaController) {
tinaController = pTinaController;
}
public int getExtraPanelSize() {
return extraPanelSize;
}
public JPanel getRootPanel() {
return rootPanel;
}
public boolean isNoRefresh() {
return noRefresh;
}
public void setNoRefresh(boolean pNoRefresh) {
noRefresh = pNoRefresh;
}
}