001package plugins.kernel.canvas;
002
003import icy.gui.component.IcyTextField;
004import icy.gui.component.IcyTextField.TextChangeListener;
005import icy.gui.component.NumberTextField;
006import icy.gui.component.button.ColorChooserButton;
007import icy.gui.component.button.ColorChooserButton.ColorChangeListener;
008import icy.gui.component.button.IcyToggleButton;
009import icy.resource.ResourceUtil;
010import icy.resource.icon.IcyIcon;
011import icy.vtk.VtkImageVolume;
012import icy.vtk.VtkImageVolume.VtkVolumeBlendType;
013
014import java.awt.Color;
015import java.awt.GridBagConstraints;
016import java.awt.GridBagLayout;
017import java.awt.Image;
018import java.awt.Insets;
019import java.awt.event.ActionEvent;
020import java.awt.event.ActionListener;
021import java.beans.PropertyChangeEvent;
022import java.util.EventListener;
023
024import javax.swing.DefaultComboBoxModel;
025import javax.swing.JCheckBox;
026import javax.swing.JComboBox;
027import javax.swing.JLabel;
028import javax.swing.JPanel;
029import javax.swing.border.EmptyBorder;
030
031public class VtkSettingPanel extends JPanel implements ActionListener, TextChangeListener, ColorChangeListener
032
033{
034    /**
035     * 
036     */
037    private static final long serialVersionUID = 6433369095311474470L;
038
039    protected static final Image ICON_GPU = ResourceUtil.getAlphaIconAsImage("gpu.png");
040    protected static final Image ICON_SHADING = ResourceUtil.getColorIconAsImage("shading.png");
041
042    public static final String PROPERTY_BG_COLOR = "renderBGColor";
043    public static final String PROPERTY_MAPPER = "volumeMapper";
044    public static final String PROPERTY_BLENDING = "volumeBlending";
045    public static final String PROPERTY_SAMPLE = "volumeSample";
046    public static final String PROPERTY_INTERPOLATION = "volumeInterpolation";
047    public static final String PROPERTY_SHADING = "shading";
048    public static final String PROPERTY_AMBIENT = "volumeAmbient";
049    public static final String PROPERTY_DIFFUSE = "volumeDiffuse";
050    public static final String PROPERTY_SPECULAR = "volumeSpecular";
051
052    /**
053     * GUI
054     */
055    private ColorChooserButton bgColorButton;
056    private JCheckBox gpuMapperCheckBox;
057    private JComboBox volumeBlendingComboBox;
058    private JComboBox volumeSampleComboBox;
059    private JComboBox volumeInterpolationComboBox;
060    private IcyToggleButton shadingButton;
061    private NumberTextField volumeAmbientField;
062    private NumberTextField volumeSpecularField;
063    private NumberTextField volumeDiffuseField;
064
065    /**
066     * Create the panel.
067     */
068    public VtkSettingPanel()
069    {
070        super();
071
072        initialize();
073
074        updateState();
075
076        bgColorButton.addColorChangeListener(this);
077        gpuMapperCheckBox.addActionListener(this);
078        volumeBlendingComboBox.addActionListener(this);
079        volumeInterpolationComboBox.addActionListener(this);
080        volumeSampleComboBox.addActionListener(this);
081        shadingButton.addActionListener(this);
082
083        volumeAmbientField.addTextChangeListener(this);
084        volumeDiffuseField.addTextChangeListener(this);
085        volumeSpecularField.addTextChangeListener(this);
086    }
087
088    protected void initialize()
089    {
090        setBorder(new EmptyBorder(2, 0, 2, 0));
091        GridBagLayout gridBagLayout = new GridBagLayout();
092        gridBagLayout.columnWidths = new int[] {0, 0, 0, 0, 0};
093        gridBagLayout.rowHeights = new int[] {0, 0, 0, 0, 0, 0};
094        gridBagLayout.columnWeights = new double[] {0.0, 1.0, 1.0, 1.0, Double.MIN_VALUE};
095        gridBagLayout.rowWeights = new double[] {0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
096        setLayout(gridBagLayout);
097
098        final JLabel lblBackground = new JLabel("Background color ");
099        lblBackground.setToolTipText("Change background color");
100        GridBagConstraints gbc_lblBackground = new GridBagConstraints();
101        gbc_lblBackground.anchor = GridBagConstraints.WEST;
102        gbc_lblBackground.insets = new Insets(0, 0, 5, 5);
103        gbc_lblBackground.gridx = 0;
104        gbc_lblBackground.gridy = 0;
105        add(lblBackground, gbc_lblBackground);
106
107        bgColorButton = new ColorChooserButton();
108        bgColorButton.setToolTipText("Change background color");
109        GridBagConstraints gbc_bgColorButton = new GridBagConstraints();
110        gbc_bgColorButton.anchor = GridBagConstraints.WEST;
111        gbc_bgColorButton.insets = new Insets(0, 0, 5, 5);
112        gbc_bgColorButton.gridx = 1;
113        gbc_bgColorButton.gridy = 0;
114        add(bgColorButton, gbc_bgColorButton);
115
116        gpuMapperCheckBox = new JCheckBox("New check box");
117        gpuMapperCheckBox.setFocusable(false);
118        gpuMapperCheckBox.setIconTextGap(8);
119        gpuMapperCheckBox.setText("GPU rendering");
120        gpuMapperCheckBox.setToolTipText("Enable GPU volume rendering");
121        GridBagConstraints gbc_gpuMapperCheckBox = new GridBagConstraints();
122        gbc_gpuMapperCheckBox.anchor = GridBagConstraints.EAST;
123        gbc_gpuMapperCheckBox.gridwidth = 2;
124        gbc_gpuMapperCheckBox.insets = new Insets(0, 0, 5, 0);
125        gbc_gpuMapperCheckBox.gridx = 2;
126        gbc_gpuMapperCheckBox.gridy = 0;
127        add(gpuMapperCheckBox, gbc_gpuMapperCheckBox);
128
129        final JLabel lblInterpolation = new JLabel("Interpolation  ");
130        lblInterpolation.setToolTipText("Select volume rendering interpolation method");
131        GridBagConstraints gbc_lblInterpolation = new GridBagConstraints();
132        gbc_lblInterpolation.anchor = GridBagConstraints.WEST;
133        gbc_lblInterpolation.insets = new Insets(0, 0, 5, 5);
134        gbc_lblInterpolation.gridx = 0;
135        gbc_lblInterpolation.gridy = 1;
136        add(lblInterpolation, gbc_lblInterpolation);
137
138        volumeInterpolationComboBox = new JComboBox();
139        volumeInterpolationComboBox.setToolTipText("Select volume rendering interpolation method");
140        volumeInterpolationComboBox.setMaximumRowCount(7);
141        volumeInterpolationComboBox.setModel(new DefaultComboBoxModel(new String[] {"Nearest (Fast)", "Linear",
142                "Cubic (Slow)"}));
143        volumeInterpolationComboBox.setSelectedIndex(1);
144        GridBagConstraints gbc_volumeInterpolationComboBox = new GridBagConstraints();
145        gbc_volumeInterpolationComboBox.fill = GridBagConstraints.HORIZONTAL;
146        gbc_volumeInterpolationComboBox.gridwidth = 3;
147        gbc_volumeInterpolationComboBox.insets = new Insets(0, 0, 5, 0);
148        gbc_volumeInterpolationComboBox.gridx = 1;
149        gbc_volumeInterpolationComboBox.gridy = 1;
150        add(volumeInterpolationComboBox, gbc_volumeInterpolationComboBox);
151
152        JLabel lblBlending = new JLabel("Blending");
153        lblBlending.setToolTipText("Select volume rendering blending method");
154        GridBagConstraints gbc_lblBlending = new GridBagConstraints();
155        gbc_lblBlending.anchor = GridBagConstraints.WEST;
156        gbc_lblBlending.insets = new Insets(0, 0, 5, 5);
157        gbc_lblBlending.gridx = 0;
158        gbc_lblBlending.gridy = 2;
159        add(lblBlending, gbc_lblBlending);
160
161        volumeBlendingComboBox = new JComboBox();
162        volumeBlendingComboBox.setToolTipText("Select volume rendering blending method");
163        volumeBlendingComboBox.setModel(new DefaultComboBoxModel(VtkVolumeBlendType.values()));
164        GridBagConstraints gbc_volumeBlendingComboBox = new GridBagConstraints();
165        gbc_volumeBlendingComboBox.fill = GridBagConstraints.HORIZONTAL;
166        gbc_volumeBlendingComboBox.gridwidth = 3;
167        gbc_volumeBlendingComboBox.insets = new Insets(0, 0, 5, 0);
168        gbc_volumeBlendingComboBox.gridx = 1;
169        gbc_volumeBlendingComboBox.gridy = 2;
170        add(volumeBlendingComboBox, gbc_volumeBlendingComboBox);
171
172        final JLabel lblSample = new JLabel("Sample");
173        lblSample.setToolTipText("Set volume sample resolution (raycaster mapper only)");
174        GridBagConstraints gbc_lblSample = new GridBagConstraints();
175        gbc_lblSample.anchor = GridBagConstraints.WEST;
176        gbc_lblSample.insets = new Insets(0, 0, 5, 5);
177        gbc_lblSample.gridx = 0;
178        gbc_lblSample.gridy = 3;
179        add(lblSample, gbc_lblSample);
180
181        volumeSampleComboBox = new JComboBox();
182        volumeSampleComboBox
183                .setToolTipText("Use low value for fine (but slow) rendering and high value for fast (but coarse) rendering");
184        volumeSampleComboBox.setMaximumRowCount(11);
185        volumeSampleComboBox.setModel(new DefaultComboBoxModel(new String[] {"Auto", "1 (Slow)", "2", "3", "4", "5",
186                "6", "7", "8", "9", "10 (Fast)"}));
187        volumeSampleComboBox.setSelectedIndex(0);
188        GridBagConstraints gbc_volumeSampleComboBox = new GridBagConstraints();
189        gbc_volumeSampleComboBox.fill = GridBagConstraints.HORIZONTAL;
190        gbc_volumeSampleComboBox.gridwidth = 3;
191        gbc_volumeSampleComboBox.insets = new Insets(0, 0, 5, 0);
192        gbc_volumeSampleComboBox.gridx = 1;
193        gbc_volumeSampleComboBox.gridy = 3;
194        add(volumeSampleComboBox, gbc_volumeSampleComboBox);
195
196        shadingButton = new IcyToggleButton(new IcyIcon(ICON_SHADING, false));
197        shadingButton.setIconTextGap(8);
198        shadingButton.setText("Shading");
199        shadingButton.setFocusable(false);
200        shadingButton.setToolTipText("Enable volume shading");
201        GridBagConstraints gbc_shadingBtn = new GridBagConstraints();
202        gbc_shadingBtn.anchor = GridBagConstraints.WEST;
203        gbc_shadingBtn.insets = new Insets(0, 0, 0, 5);
204        gbc_shadingBtn.gridx = 0;
205        gbc_shadingBtn.gridy = 4;
206        add(shadingButton, gbc_shadingBtn);
207
208        volumeAmbientField = new NumberTextField();
209        volumeAmbientField.setToolTipText("Ambient lighting coefficient");
210        GridBagConstraints gbc_volumeAmbientField = new GridBagConstraints();
211        gbc_volumeAmbientField.fill = GridBagConstraints.HORIZONTAL;
212        gbc_volumeAmbientField.insets = new Insets(0, 0, 0, 5);
213        gbc_volumeAmbientField.gridx = 1;
214        gbc_volumeAmbientField.gridy = 4;
215        add(volumeAmbientField, gbc_volumeAmbientField);
216        volumeAmbientField.setColumns(3);
217
218        volumeDiffuseField = new NumberTextField();
219        volumeDiffuseField.setToolTipText("Diffuse lighting coefficient");
220        GridBagConstraints gbc_volumeDiffuseField = new GridBagConstraints();
221        gbc_volumeDiffuseField.insets = new Insets(0, 0, 0, 5);
222        gbc_volumeDiffuseField.fill = GridBagConstraints.HORIZONTAL;
223        gbc_volumeDiffuseField.gridx = 2;
224        gbc_volumeDiffuseField.gridy = 4;
225        add(volumeDiffuseField, gbc_volumeDiffuseField);
226        volumeDiffuseField.setColumns(3);
227
228        volumeSpecularField = new NumberTextField();
229        volumeSpecularField.setToolTipText("Specular lighting coefficient");
230        GridBagConstraints gbc_volumeSpecularField = new GridBagConstraints();
231        gbc_volumeSpecularField.fill = GridBagConstraints.HORIZONTAL;
232        gbc_volumeSpecularField.gridx = 3;
233        gbc_volumeSpecularField.gridy = 4;
234        add(volumeSpecularField, gbc_volumeSpecularField);
235        volumeSpecularField.setColumns(3);
236    }
237
238    protected void updateState()
239    {
240        // if (isBoundingBoxVisible())
241        // {
242        // boundingBoxGridCheckBox.setEnabled(true);
243        // boundingBoxRulerCheckBox.setEnabled(true);
244        // }
245        // else
246        // {
247        // boundingBoxGridCheckBox.setEnabled(false);
248        // boundingBoxRulerCheckBox.setEnabled(false);
249        // }
250
251        // switch (getVolumeMapperType())
252        // {
253        // case RAYCAST_CPU_FIXEDPOINT:
254        // case RAYCAST_GPU_OPENGL:
255        // volumeSampleComboBox.setEnabled(true);
256        // volumeBlendingComboBox.setEnabled(true);
257        // break;
258        // case TEXTURE2D_OPENGL:
259        // case TEXTURE3D_OPENGL:
260        // volumeSampleComboBox.setEnabled(false);
261        // volumeBlendingComboBox.setEnabled(false);
262        // break;
263        // }
264    }
265
266    public Color getBackgroundColor()
267    {
268        return bgColorButton.getColor();
269    }
270
271    public void setBackgroundColor(Color value)
272    {
273        bgColorButton.setColor(value);
274    }
275
276    public boolean getGPURendering()
277    {
278        return gpuMapperCheckBox.isSelected();
279    }
280
281    public void setGPURendering(boolean value)
282    {
283        gpuMapperCheckBox.setSelected(value);
284    }
285
286    public int getVolumeInterpolation()
287    {
288        return volumeInterpolationComboBox.getSelectedIndex();
289    }
290
291    public void setVolumeInterpolation(int value)
292    {
293        volumeInterpolationComboBox.setSelectedIndex(value);
294    }
295
296    public VtkVolumeBlendType getVolumeBlendingMode()
297    {
298        if (volumeBlendingComboBox.getSelectedIndex() == -1)
299            return null;
300
301        return (VtkVolumeBlendType) volumeBlendingComboBox.getSelectedItem();
302    }
303
304    public void setVolumeBlendingMode(VtkVolumeBlendType value)
305    {
306        volumeBlendingComboBox.setSelectedItem(value);
307    }
308
309    public int getVolumeSample()
310    {
311        return volumeSampleComboBox.getSelectedIndex();
312    }
313
314    public void setVolumeSample(int value)
315    {
316        volumeSampleComboBox.setSelectedIndex(value);
317    }
318
319    public double getVolumeAmbient()
320    {
321        return volumeAmbientField.getNumericValue();
322    }
323
324    public void setVolumeAmbient(double value)
325    {
326        volumeAmbientField.setNumericValue(value);
327    }
328
329    public double getVolumeDiffuse()
330    {
331        return volumeDiffuseField.getNumericValue();
332    }
333
334    public void setVolumeDiffuse(double value)
335    {
336        volumeDiffuseField.setNumericValue(value);
337    }
338
339    public double getVolumeSpecular()
340    {
341        return volumeSpecularField.getNumericValue();
342    }
343
344    public void setVolumeSpecular(double value)
345    {
346        volumeSpecularField.setNumericValue(value);
347    }
348
349    /**
350     * @see VtkImageVolume#getShade()
351     */
352    public boolean getVolumeShading()
353    {
354        return shadingButton.isSelected();
355    }
356
357    /**
358     * @see VtkImageVolume#setShade(boolean)
359     */
360    public void setVolumeShading(boolean value)
361    {
362        if (shadingButton.isSelected() != value)
363            shadingButton.doClick();
364    }
365
366    /**
367     * Add a SettingChange listener
368     */
369    public void addSettingChangeListener(SettingChangeListener listener)
370    {
371        listenerList.add(SettingChangeListener.class, listener);
372    }
373
374    /**
375     * Remove a SettingChange listener
376     */
377    public void removeSettingChangeListener(SettingChangeListener listener)
378    {
379        listenerList.remove(SettingChangeListener.class, listener);
380    }
381
382    public void fireSettingChange(Object source, String propertyName, Object oldValue, Object newValue)
383    {
384        if ((oldValue != null) && (newValue != null) && oldValue.equals(newValue))
385            return;
386
387        final PropertyChangeEvent event = new PropertyChangeEvent(source, propertyName, oldValue, newValue);
388        final SettingChangeListener[] listeners = getListeners(SettingChangeListener.class);
389
390        for (int i = 0; i < listeners.length; i++)
391            listeners[i].settingChange(event);
392    }
393
394    @Override
395    public void colorChanged(ColorChooserButton source)
396    {
397        if (source == bgColorButton)
398            fireSettingChange(source, PROPERTY_BG_COLOR, null, source.getColor());
399    }
400
401    @Override
402    public void actionPerformed(ActionEvent e)
403    {
404        final Object source = e.getSource();
405
406        if (source == gpuMapperCheckBox)
407            fireSettingChange(source, PROPERTY_MAPPER, Boolean.valueOf(!gpuMapperCheckBox.isSelected()),
408                    Boolean.valueOf(gpuMapperCheckBox.isSelected()));
409        else if (source == volumeBlendingComboBox)
410            fireSettingChange(source, PROPERTY_BLENDING, null, volumeBlendingComboBox.getSelectedItem());
411        else if (source == volumeSampleComboBox)
412            fireSettingChange(source, PROPERTY_SAMPLE, Integer.valueOf(-1),
413                    Integer.valueOf(volumeSampleComboBox.getSelectedIndex()));
414        else if (source == volumeInterpolationComboBox)
415            fireSettingChange(source, PROPERTY_INTERPOLATION, Integer.valueOf(-1),
416                    Integer.valueOf(volumeInterpolationComboBox.getSelectedIndex()));
417        else if (source == shadingButton)
418            fireSettingChange(source, PROPERTY_SHADING, Integer.valueOf(-1),
419                    Boolean.valueOf(shadingButton.isSelected()));
420
421        updateState();
422    }
423
424    @Override
425    public void textChanged(IcyTextField source, boolean validate)
426    {
427        if (!validate)
428            return;
429
430        if (source == volumeAmbientField)
431            fireSettingChange(source, PROPERTY_AMBIENT, Double.valueOf(-1d),
432                    Double.valueOf(volumeAmbientField.getNumericValue()));
433        else if (source == volumeDiffuseField)
434            fireSettingChange(source, PROPERTY_DIFFUSE, Double.valueOf(-1d),
435                    Double.valueOf(volumeDiffuseField.getNumericValue()));
436        else if (source == volumeSpecularField)
437            fireSettingChange(source, PROPERTY_SPECULAR, Double.valueOf(-1d),
438                    Double.valueOf(volumeSpecularField.getNumericValue()));
439
440        updateState();
441    }
442
443    public static interface SettingChangeListener extends EventListener
444    {
445        public void settingChange(PropertyChangeEvent evt);
446    }
447}