/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package org.pepsoft.worldpainter.heightMaps.gui;
import org.pepsoft.worldpainter.HeightMap;
import org.pepsoft.worldpainter.heightMaps.*;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
/**
*
* @author pepijn
*/
public class HeightMapPropertiesPanel extends JPanel {
public HeightMapPropertiesPanel() {
setLayout(new GridBagLayout());
}
public HeightMap getHeightMap() {
return heightMap;
}
public void setHeightMap(HeightMap heightMap) {
this.heightMap = heightMap;
removeAll();
addField("Type:", heightMap.getClass().getSimpleName());
addField("Name:", heightMap, "name");
if (heightMap instanceof ConstantHeightMap) {
addField("Height: ", heightMap, "height");
} else if (heightMap instanceof NinePatchHeightMap) {
addField("Height:", heightMap, "height");
addField("Inner size X:", heightMap, "innerSizeX", 0, null);
addField("Inner size Y:", heightMap, "innerSizeY", 0, null);
addField("Border size:", heightMap, "borderSize", 0, null);
addField("Coast size:", heightMap, "coastSize", 0, null);
} else if (heightMap instanceof NoiseHeightMap) {
addField("Height:", heightMap, "height", 0f, null);
addField("Scale:", heightMap, "scale", 0.0, null);
addField("Octaves:", heightMap, "octaves", 1, 8);
} else if (heightMap instanceof TransformingHeightMap) {
addField("X scale:", heightMap, "scaleX", 0, null);
addField("Y scale:", heightMap, "scaleY", 0, null);
addField("X offset:", heightMap, "offsetX");
addField("Y offset:", heightMap, "offsetY");
addField("Rotation:", heightMap, "rotation");
} else if (heightMap instanceof BitmapHeightMap) {
BufferedImage image = ((BitmapHeightMap) heightMap).getImage();
int noOfChannels = image.getColorModel().getNumComponents();
addField("Channel:", heightMap, "channel", 0, noOfChannels - 1);
addField("Repeat:", heightMap, "repeat");
addField("Bicubic scaling:", heightMap, "smoothScaling");
} else if (heightMap instanceof BandedHeightMap) {
addField("Segment 1 length:", heightMap, "segment1Length");
addField("Segment 1 end height:", heightMap, "segment1EndHeight");
addField("Segment 2 length:", heightMap, "segment2Length");
addField("Segment 2 end height:", heightMap, "segment2EndHeight");
addField("Smooth:", heightMap, "smooth");
} else if (heightMap instanceof ShelvingHeightMap) {
addField("Shelve height:", heightMap, "shelveHeight");
addField("Shelve strength:", heightMap, "shelveStrength");
}
float[] range = heightMap.getRange();
addField("Range:", "[" + range[0] + ", " + range[1] + "]");
GridBagConstraints constraints = new GridBagConstraints();
constraints.weighty = 1.0;
add(Box.createGlue(), constraints);
validate();
repaint();
}
public HeightMapListener getListener() {
return listener;
}
public void setListener(HeightMapListener listener) {
this.listener = listener;
}
private void addField(String name, String text) {
addField(name, null, null, null, null, text);
}
private void addField(String name, Object bean, String propertyName) {
addField(name, bean, propertyName, null, null, null);
}
private void addField(String name, Object bean, String propertyName, Number min, Number max) {
addField(name, bean, propertyName, min, max, null);
}
private void addField(String name, Object bean, String propertyName, Number min, Number max, String text) {
GridBagConstraints constraints = new GridBagConstraints();
constraints.anchor = GridBagConstraints.NORTHWEST;
constraints.insets = new Insets(2, 2, 2, 2);
constraints.fill = GridBagConstraints.HORIZONTAL;
constraints.anchor = GridBagConstraints.BASELINE_LEADING;
JLabel label = new JLabel(name);
add(label, constraints);
if (text != null) {
constraints.gridwidth = GridBagConstraints.REMAINDER;
constraints.weightx = 1.0;
JLabel valueLabel = new JLabel();
valueLabel.setText(text);
add(valueLabel, constraints);
return;
}
try {
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
for (PropertyDescriptor propertyDescriptor: beanInfo.getPropertyDescriptors()) {
if (propertyDescriptor.getName().equalsIgnoreCase(propertyName)) {
constraints.gridwidth = GridBagConstraints.REMAINDER;
constraints.weightx = 1.0;
if (propertyDescriptor.getWriteMethod() == null) {
JLabel valueLabel = new JLabel();
Object value = propertyDescriptor.getReadMethod().invoke(bean);
if (value != null) {
valueLabel.setText(value.toString());
}
add(valueLabel, constraints);
return;
}
Class<?> propertyType = propertyDescriptor.getPropertyType();
if (propertyType == String.class) {
JTextField field = new JTextField();
field.setText((String) propertyDescriptor.getReadMethod().invoke(bean));
field.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent event) {
updateProperty();
}
@Override
public void removeUpdate(DocumentEvent event) {
updateProperty();
}
@Override
public void changedUpdate(DocumentEvent event) {
updateProperty();
}
private void updateProperty() {
try {
propertyDescriptor.getWriteMethod().invoke(bean, field.getText());
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
updateListener(propertyName);
}
});
add(field, constraints);
} else if ((propertyType == boolean.class) || (propertyType == Boolean.class)) {
JCheckBox checkBox = new JCheckBox(" ");
checkBox.setSelected(Boolean.TRUE.equals(propertyDescriptor.getReadMethod().invoke(bean)));
checkBox.addActionListener(event -> {
try {
propertyDescriptor.getWriteMethod().invoke(bean, checkBox.isSelected());
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
updateListener(propertyName);
});
add(checkBox, constraints);
} else if ((Number.class.isAssignableFrom(propertyType)) || (propertyType.isPrimitive() && (propertyType != boolean.class) && (propertyType != char.class))) {
JSpinner spinner = new JSpinner(new SpinnerNumberModel((Number) propertyDescriptor.getReadMethod().invoke(bean), (Comparable) min, (Comparable) max, 1));
spinner.addChangeListener(event -> {
try {
propertyDescriptor.getWriteMethod().invoke(bean, spinner.getValue());
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
updateListener(propertyName);
});
add(spinner, constraints);
} else {
throw new IllegalArgumentException("Property " + propertyName + " of type " + propertyType.getSimpleName() + " not supported");
}
return;
}
}
throw new IllegalArgumentException("Bean of type " + bean.getClass().getSimpleName() + " has no property named " + propertyName);
} catch (IntrospectionException | InvocationTargetException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
private void updateListener(String propertyName) {
if (listener != null) {
listener.heightMapChanged(heightMap, propertyName);
}
}
private HeightMap heightMap;
private HeightMapListener listener;
public interface HeightMapListener {
void heightMapChanged(HeightMap heightMap, String propertyName);
}
}