/**
*
*/
package de.danielsenff.radds.view.canvas;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.Hashtable;
import javax.swing.DefaultComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.event.AncestorEvent;
import javax.swing.event.AncestorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import model.TextureImage;
import net.miginfocom.swing.MigLayout;
import org.jdesktop.application.ApplicationContext;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.TaskService;
import ddsutil.BIUtil;
import ddsutil.ImageOperations;
import de.danielsenff.radds.Radds;
import de.danielsenff.radds.RaddsView;
import de.danielsenff.radds.models.ColorChannel;
import de.danielsenff.radds.tasks.LoadImageTask;
import de.danielsenff.radds.util.FileDrop;
/**
* Control-Panel for the {@link BICanvas}.
* This contains controls and components to manipulate the canvas.
* @author Daniel Senff
*
*/
public class CanvasControlsPanel extends JPanel {
/**
*
*/
private static final long serialVersionUID = -3204480115770320549L;
private BICanvas canvas;
private JComboBox<Integer> zoomCombo;
private JSlider zoomSlider;
private RaddsView view;
private JComboBox<Integer> mipMapCombo;
private JScrollPane scrollViewPane;
private boolean fitSize;
/**
* @param view
*/
public CanvasControlsPanel(final RaddsView view) {
this.view = view;
setLayout(new BorderLayout());
scrollViewPane = initScrollCanvas();
final JPanel navigateCanvas = initNavigationPanel();
getCanvas().addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent pChangeEvent) {
if(pChangeEvent.getPropertyName().equals("zoomFactor")){
float newValue = (Float) pChangeEvent.getNewValue();
Integer percentage = Integer.valueOf((int) (newValue * 100));
zoomSlider.setValue(percentage);
zoomCombo.setSelectedItem("" +percentage);
}
}
});
new FileDrop( scrollViewPane, new FileDrop.Listener(){
@Override
public void filesDropped( java.io.File[] files ) {
// handle first file
openImage(files[0]);
} // end filesDropped
}); // end FileDrop.Listener
this.add(scrollViewPane, BorderLayout.CENTER);
this.add(navigateCanvas, BorderLayout.SOUTH);
}
private void openImage(File file) {
LoadImageTask convertTask = new LoadImageTask(file);
TaskService ts = Radds.getApplication().getContext().getTaskService();
ts.execute(convertTask);
}
/**
* Initialize components in the navigation panel for this BICanvas.
* @return
*/
private JPanel initNavigationPanel() {
// Action buttons
MigLayout miglayout = new MigLayout("nogrid, fillx, wrap, gap 0, ins 0");
final JPanel panel = new JPanel();
panel.setLayout(miglayout);
final JButton copyButton = new JButton(view.getAction("copy"));
panel.add(copyButton, "sg");
final JButton bgColorButton = initTransparencyColorButton();
panel.add(bgColorButton, "sg");
// Color Channel
final JLabel lblChannelCombo = new JLabel(getResourceMap().getString("Channels")+":");
panel.add(lblChannelCombo, "gap push");
final JComboBox<ColorChannel> channelCombo = initColorChannelCombo();
panel.add(channelCombo, "sg");
// MipMaps
JLabel lblMipMap = new JLabel(getResourceMap().getString("MipMap")+":");
panel.add(lblMipMap, "gap push");
initMipmapCombo();
panel.add(mipMapCombo, "sg, wrap");
// ZO_om
JLabel lblZoom = new JLabel(getResourceMap().getString("Zoom")+":");
panel.add(lblZoom, "");
initZoomCombo();
panel.add(zoomCombo, "");
initZoomSlider();
panel.add(zoomSlider, "");
JCheckBox chkZoomFitSize = initFitZoomCheckbox();
panel.add(chkZoomFitSize, "");
return panel;
}
private JCheckBox initFitZoomCheckbox() {
JCheckBox chkZoomFitSize = new JCheckBox(getResourceString("Zoom_to_fit"));
chkZoomFitSize.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
fitSize = ((JCheckBox)e.getSource()).isSelected();
resizeCanvasToFit(fitSize);
}
});
return chkZoomFitSize;
}
private JButton initTransparencyColorButton() {
final JButton bgColorButton = new JButton(getResourceString("Background"));
bgColorButton.setToolTipText(getResourceString("set_background_color"));
bgColorButton.setIcon(initColorImageIcon(canvas.getTransparencyColor()));
bgColorButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
BICanvas canvas = getCanvas();
Color returnValue = null;
try {
returnValue = JColorChooser.showDialog(canvas,
getResourceString("set_background_color"),
canvas.getTransparencyColor());
if(returnValue != null) {
canvas.setTransparencyColor(returnValue);
canvas.repaint();
bgColorButton.setIcon(initColorImageIcon(returnValue));
bgColorButton.repaint();
}
} catch (Exception ex) {
}
}
});
return bgColorButton;
}
private JComboBox<ColorChannel> initColorChannelCombo() {
final JComboBox<ColorChannel> channelCombo = new JComboBox<ColorChannel>(composeColorChannelModel());
channelCombo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent event) {
final JComboBox<ColorChannel> channelCombo = (JComboBox<ColorChannel>) event.getSource();
final ColorChannel channel = (ColorChannel) channelCombo.getSelectedItem();
canvas.setChannelMode(channel.getChannel());
}
});
return channelCombo;
}
private ImageIcon initColorImageIcon(Color color) {
BufferedImage colorImage = new BufferedImage(16, 16, BufferedImage.TYPE_4BYTE_ABGR);
for (int y = 0; y < colorImage.getHeight(); y++) {
for (int x = 0; x < colorImage.getWidth(); x++) {
colorImage.setRGB(x, y, color.getRGB());
}
}
return new ImageIcon(colorImage);
}
private void initZoomSlider() {
zoomSlider = new JSlider(0, 500, 100);
Hashtable<Integer, JComponent> labels = new Hashtable<Integer, JComponent>();
labels.put(10, new JLabel("0.1x"));
labels.put(100, new JLabel("1x"));
labels.put(250, new JLabel("2.5x"));
labels.put(500, new JLabel("5x"));
zoomSlider.setLabelTable(labels);
zoomSlider.setMajorTickSpacing(100);
zoomSlider.setMinorTickSpacing(25);
zoomSlider.setPaintTicks(true);
zoomSlider.setPaintLabels(true);
zoomSlider.setPreferredSize(new Dimension(250, 14));
zoomSlider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(final ChangeEvent e) {
final int zoomValue = ((JSlider)e.getSource()).getValue();
canvas.setZoomFactor( (Float.valueOf(zoomValue)) * 0.01f);
canvas.revalidate();
}
});
}
private void initMipmapCombo() {
mipMapCombo = new JComboBox<Integer>();
updateNumMipMaps();
mipMapCombo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
if(mipMapCombo.getItemCount() > 0) {
int index = (Integer) ((JComboBox<Integer>)e.getSource()).getSelectedItem();
TextureImage textureImage = view.getTextureImage();
if(index < textureImage.getNumMipMaps()) {
BufferedImage bi = textureImage.getMipMap(index-1);
canvas.setSourceBI(bi);
canvas.revalidate();
}
}
}
});
}
private void initZoomCombo() {
final String[] defaultZooms = { "25", "50", "100", "150", "200", "400"};
zoomCombo = new JComboBox(defaultZooms);
zoomCombo.setSelectedIndex(2);
zoomCombo.setEditable(true);
zoomCombo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
float zoomValue = (Float.valueOf((String) zoomCombo.getSelectedItem())) / 100;
canvas.setZoomFactor( zoomValue);
canvas.repaint();
}
});
zoomCombo.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_ENTER) {
float zoomValue = (Float.valueOf((String) zoomCombo.getSelectedItem())) / 100;
canvas.setZoomFactor( zoomValue);
canvas.repaint();
}
}
});
}
private void resizeCanvasToFit(boolean fitSize) {
float zoomValue;
if (fitSize) {
zoomValue= calculateZoomfactorFitWidth();
} else {
zoomValue = (Float.valueOf((String) zoomCombo.getSelectedItem())) * 0.01f;
}
canvas.setZoomFactor( zoomValue);
canvas.repaint();
}
public float calculateZoomfactorFitWidth() {
Insets insets = scrollViewPane.getBorder().getBorderInsets(canvas);
float factorWidth = (float) ( (scrollViewPane.getSize().getWidth()-insets.left-insets.right) / canvas.getSource().getWidth());
float factorHeight = (float) ( (scrollViewPane.getSize().getHeight()-insets.bottom-insets.top) / canvas.getSource().getHeight());
return (factorWidth < factorHeight) ? factorWidth : factorHeight;
}
private String getResourceString(final String text) {
return getResourceMap().getString(text);
}
/**
* Number of MipMaps of the currently displayed texture.
*/
public void updateNumMipMaps() {
TextureImage textureImage = view.getTextureImage();
if(textureImage != null) {
mipMapCombo.removeAllItems();
for (int i = 0; i < textureImage.getNumMipMaps(); i++) {
mipMapCombo.addItem(i+1);
}
}
}
/**
* Init ComboBox for selecting different Color Channels of an Image.
* @return
*/
private DefaultComboBoxModel<ColorChannel> composeColorChannelModel() {
final DefaultComboBoxModel<ColorChannel> combo = new DefaultComboBoxModel<ColorChannel>();
combo.addElement(new ColorChannel(ImageOperations.ChannelMode.RGB, getResourceMap().getString("rgb_channels")));
combo.addElement(new ColorChannel(ImageOperations.ChannelMode.RED, getResourceMap().getString("r_channel")));
combo.addElement(new ColorChannel(ImageOperations.ChannelMode.GREEN, getResourceMap().getString("g_channel")));
combo.addElement(new ColorChannel(ImageOperations.ChannelMode.BLUE, getResourceMap().getString("b_channel")));
combo.addElement(new ColorChannel(ImageOperations.ChannelMode.ALPHA, getResourceMap().getString("a_channel")));
combo.addElement(new ColorChannel(ImageOperations.ChannelMode.RGBA, getResourceMap().getString("rgba_transparent")));
return combo;
}
private ResourceMap getResourceMap() {
final Radds instance = Radds.getInstance(Radds.class);
final ApplicationContext context = instance.getContext();
final org.jdesktop.application.ResourceMap resourceMap = context.getResourceMap(RaddsView.class);
return resourceMap;
}
private ImageIcon getResourceIcon(String file){
return new ImageIcon(Class.class.getResource(file));
}
private JScrollPane initScrollCanvas() {
final ImageIcon defaultImage = (ImageIcon)getResourceMap().getIcon("Canvas.default_image");
canvas = new BICanvas(BIUtil.convertImageToBufferedImage(defaultImage.getImage(),
BufferedImage.TYPE_4BYTE_ABGR));
// JScrollPane
final JScrollPane scrollViewPane = new JScrollPane(canvas);
scrollViewPane.setPreferredSize(new Dimension(700,300));
scrollViewPane.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent event) {
resizeCanvasToFit(fitSize);
}
});
final ScrollCanvasListener scrollCanvasListener = new ScrollCanvasListener(scrollViewPane);
canvas.addMouseMotionListener(scrollCanvasListener);
// canvas.addMouseWheelListener(scrollCanvasListener);
canvas.addKeyListener(scrollCanvasListener);
canvas.setFocusable(true);
canvas.requestFocus();
canvas.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
canvas.requestFocus();
}
});
canvas.addRenderedChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
resizeCanvasToFit(fitSize);
}
});
canvas.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
canvas.addAncestorListener(new AncestorListener() {
@Override
public void ancestorAdded(final AncestorEvent arg0) {}
@Override
public void ancestorMoved(final AncestorEvent arg0) {
scrollViewPane.repaint();
}
@Override
public void ancestorRemoved(final AncestorEvent arg0) { }
});
return scrollViewPane;
}
/**
* Returns the BufferedImage drawing canvas
* @return
*/
public BICanvas getCanvas() {
return this.canvas;
}
}