/* * Tiled Map Editor, (c) 2004-2006 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Adam Turk <aturk@biggeruniverse.com> * Bjorn Lindeijer <bjorn@lindeijer.nl> */ package tiled.mapeditor.dialogs; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.GridLayout; import java.awt.Insets; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.prefs.Preferences; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSlider; import javax.swing.JTabbedPane; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.SwingConstants; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import tiled.core.Tile; import tiled.io.MapHelper; import tiled.io.MapReader; import tiled.mapeditor.MapEditor; import tiled.mapeditor.Resources; import tiled.mapeditor.brush.AbstractBrush; import tiled.mapeditor.brush.Brush; import tiled.mapeditor.brush.CustomBrush; import tiled.mapeditor.brush.RandomBrush; import tiled.mapeditor.brush.ShapeBrush; import tiled.mapeditor.plugin.PluginClassLoader; import tiled.mapeditor.util.LayerTableModel; import tiled.mapeditor.util.TiledFileFilter; import tiled.mapeditor.widget.BrushBrowser; import tiled.mapeditor.widget.IntegerSpinner; import tiled.mapeditor.widget.MiniMapViewer; import tiled.mapeditor.widget.VerticalStaticJPanel; import tiled.util.TiledConfiguration; public class BrushDialog extends JDialog implements ActionListener, ItemListener, ChangeListener, PropertyChangeListener, ListSelectionListener { /** * */ private static final long serialVersionUID = 6660894004923093431L; private AbstractBrush myBrush; private final MapEditor editor; private JCheckBox cbRandomBrush; private IntegerSpinner affectLayers, brushSize; private JSlider sRandomAmount; private JButton okButton, bApply, bCancel; private BrushBrowser brushes; private static final String DIALOG_TITLE = Resources.getString("dialog.brush.title"); private static final String OK_BUTTON = Resources.getString("general.button.ok"); private static final String APPLY_BUTTON = Resources.getString("general.button.apply"); private static final String CANCEL_BUTTON = Resources.getString("general.button.cancel"); private static final String SHAPE_TAB = Resources.getString("dialog.brush.tab.shape"); private static final String CUSTOM_TAB = Resources.getString("dialog.brush.tab.custom"); private static final String PRESETS_TITLE = Resources.getString("dialog.brush.presets.title"); private static final String BRUSH_SIZE_TOOLTIP = Resources.getString("dialog.brush.size.tooltip"); private static final String RANDOM_BRUSH_TOOLTIP = Resources.getString("dialog.brush.random.brush.tooltip"); private static final String RANDOM_AMOUNT_TOOLTIP = Resources.getString("dialog.brush.random.amount.tooltip"); private static final String RANDOM_CHECKBOX = Resources.getString("dialog.brush.random.checkbox"); private static final String OPTIONS_TITLE = Resources.getString("dialog.brush.options.title"); private static final String BRUSH_SIZE_LABEL = Resources.getString("dialog.brush.brush.size.label"); private static final String AFFECTED_LAYERS_LABEL = Resources.getString("dialog.brush.affected.layers.label"); private static final String CREATE_BUTTON = Resources.getString("dialog.brush.create.button"); private static final String LOAD_BUTTON = Resources.getString("dialog.brush.load.button"); public BrushDialog(MapEditor editor, JFrame parent, AbstractBrush currentBrush) { super(parent, DIALOG_TITLE, false); myBrush = currentBrush; this.editor = editor; init(); update(); pack(); setLocationRelativeTo(parent); } private JPanel createShapePanel() { // Brush presets brushes = new BrushBrowser(); JScrollPane brushScrollPane = new JScrollPane(brushes); brushScrollPane.setPreferredSize(new Dimension(100, 100)); brushes.addPropertyChangeListener(this); brushes.setSelectedBrush(myBrush); JPanel presets = new JPanel(); presets.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createTitledBorder(PRESETS_TITLE), BorderFactory.createEmptyBorder(0, 5, 5, 5))); presets.setLayout(new GridLayout(1, 1)); presets.add(brushScrollPane); // Brush size brushSize = new IntegerSpinner(1, 1); if (myBrush != null) { Rectangle r = myBrush.getBounds(); brushSize.setValue(r.width); } brushSize.addChangeListener(this); brushSize.setToolTipText(BRUSH_SIZE_TOOLTIP); // Number of affected layers affectLayers = new IntegerSpinner(myBrush.getAffectedLayers(), 1); affectLayers.addChangeListener(this); // Randomize tile placement cbRandomBrush = new JCheckBox(RANDOM_CHECKBOX); cbRandomBrush.setToolTipText(RANDOM_BRUSH_TOOLTIP); cbRandomBrush.addItemListener(this); sRandomAmount = new JSlider(); sRandomAmount.setPreferredSize(new Dimension( 50, sRandomAmount.getPreferredSize().height)); sRandomAmount.setToolTipText(RANDOM_AMOUNT_TOOLTIP); sRandomAmount.addChangeListener(this); // Brush options section JPanel opts = new VerticalStaticJPanel(); opts.setLayout(new GridBagLayout()); opts.setBorder(BorderFactory.createCompoundBorder( BorderFactory.createTitledBorder(OPTIONS_TITLE), BorderFactory.createEmptyBorder(0, 5, 5, 5))); GridBagConstraints c = new GridBagConstraints(); c.fill = GridBagConstraints.NONE; c.anchor = GridBagConstraints.NORTHWEST; c.weightx = 0; c.insets = new Insets(0, 0, 5, 0); opts.add(new JLabel(BRUSH_SIZE_LABEL), c); c.gridy = 1; opts.add(new JLabel(AFFECTED_LAYERS_LABEL), c); c.gridy = 2; opts.add(cbRandomBrush, c); c.gridy = 0; c.gridx = 1; c.weightx = 0.3; c.fill = GridBagConstraints.HORIZONTAL; opts.add(brushSize, c); c.gridy = 1; opts.add(affectLayers, c); c.gridy = 2; opts.add(sRandomAmount, c); JPanel shapePanel = new JPanel(); shapePanel.setLayout(new BoxLayout(shapePanel, BoxLayout.Y_AXIS)); shapePanel.add(presets); shapePanel.add(opts); return shapePanel; } private JPanel createCustomPanel() { JPanel customPanel = new JPanel(); MiniMapViewer mmv = new MiniMapViewer(); if (myBrush instanceof CustomBrush) { //mmv.setView(((CustomBrush)myBrush)); } JScrollPane miniSp = new JScrollPane(); miniSp.getViewport().setView(mmv); miniSp.setPreferredSize(new Dimension(100, 100)); JButton bCreate = new JButton(CREATE_BUTTON); bCreate.addActionListener(this); //TODO: create functionality is not available yet bCreate.setEnabled(false); JButton bLoad = new JButton(LOAD_BUTTON); bLoad.addActionListener(this); JTable layerTable = new JTable(new LayerTableModel(myBrush)); layerTable.getColumnModel().getColumn(0).setPreferredWidth(32); layerTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); layerTable.getSelectionModel().addListSelectionListener(this); customPanel.setLayout(new GridBagLayout()); GridBagConstraints c = new GridBagConstraints(); c.anchor = GridBagConstraints.NORTH; c.fill = GridBagConstraints.NONE; c.weightx = 2; c.weighty = 2; customPanel.add(miniSp, c); c.weightx = 1; c.weighty = 1; c.gridx=2; customPanel.add(bCreate, c); c.gridy=1; customPanel.add(bLoad, c); c.gridx=0; c.gridy=2; customPanel.add(layerTable, c); return customPanel; } private void init() { JTabbedPane tabs = new JTabbedPane(SwingConstants.TOP); tabs.addTab(SHAPE_TAB, createShapePanel()); tabs.addTab(CUSTOM_TAB, createCustomPanel()); tabs.setEnabledAt(1, false); okButton = new JButton(OK_BUTTON); bApply = new JButton(APPLY_BUTTON); bCancel = new JButton(CANCEL_BUTTON); okButton.addActionListener(this); bApply.addActionListener(this); bCancel.addActionListener(this); bApply.setEnabled(false); /* BUTTONS PANEL */ JPanel buttons = new VerticalStaticJPanel(); buttons.setLayout(new BoxLayout(buttons, BoxLayout.X_AXIS)); buttons.add(Box.createGlue()); buttons.add(okButton); buttons.add(Box.createRigidArea(new Dimension(5, 0))); buttons.add(bApply); buttons.add(Box.createRigidArea(new Dimension(5, 0))); buttons.add(bCancel); JPanel mainPanel = new JPanel(); mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS)); mainPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); mainPanel.add(tabs); mainPanel.add(Box.createRigidArea(new Dimension(0, 5))); mainPanel.add(buttons); getContentPane().add(mainPanel); getRootPane().setDefaultButton(okButton); } private void createFromOptions() { Tile t = null; if (myBrush instanceof ShapeBrush) { t = ((ShapeBrush) myBrush).getTile(); } ShapeBrush sel = (ShapeBrush) brushes.getSelectedBrush(); sel.setSize((Integer) brushSize.getValue()); if (cbRandomBrush.isSelected()) { RandomBrush randomBrush = new RandomBrush(sel); randomBrush.setRatio( sRandomAmount.getValue() / (double) sRandomAmount.getMaximum()); myBrush = randomBrush; } else { myBrush = new ShapeBrush(sel); } ((ShapeBrush)myBrush).setTile(t); myBrush.setAffectedLayers((Integer) affectLayers.getValue()); update(); } private void update() { if (myBrush instanceof CustomBrush) { // Custom brush brushSize.setEnabled(false); affectLayers.setEnabled(false); cbRandomBrush.setEnabled(false); } else if (myBrush instanceof RandomBrush) { // Random brush cbRandomBrush.setSelected(true); sRandomAmount.setValue( (int)(((RandomBrush)myBrush).getRatio() * 100)); } sRandomAmount.setEnabled(cbRandomBrush.isSelected()); } public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if (source == okButton) { createFromOptions(); editor.setBrush(myBrush); dispose(); } else if (source == bApply) { createFromOptions(); editor.setBrush(myBrush); bApply.setEnabled(false); } else if (source == bCancel) { dispose(); } else if (e.getActionCommand().equals(LOAD_BUTTON)) { try { openMap(); //mmv.setView(((CustomBrush)myBrush)); } catch (Exception e1) { e1.printStackTrace(); JOptionPane.showMessageDialog(this, e1.toString(), "Load Brush", JOptionPane.WARNING_MESSAGE); } repaint(); } } public void stateChanged(ChangeEvent e) { bApply.setEnabled(true); } public void itemStateChanged(ItemEvent event) { Object source = event.getItemSelectable(); if (source == cbRandomBrush) { sRandomAmount.setEnabled(cbRandomBrush.isSelected()); } bApply.setEnabled(true); } public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equals("selectedbrush")) { Brush b = brushes.getSelectedBrush(); if (b != null) { brushSize.setValue(b.getBounds().width); } } bApply.setEnabled(true); } public void valueChanged(ListSelectionEvent e) { // TODO Auto-generated method stub } private void openMap() throws Exception { // Start at the location of the most recently loaded map file Preferences prefs = TiledConfiguration.node("recent"); String startLocation = prefs.get("file0", ""); JFileChooser ch = new JFileChooser(startLocation); try { MapReader[] readers = PluginClassLoader.getInstance().getReaders(); for (MapReader reader : readers) { ch.addChoosableFileFilter(new TiledFileFilter( reader.getFilter(), reader.getName())); } } catch (Exception e) { JOptionPane.showMessageDialog(this, "Error while loading plugins: " + e.getMessage(), "Error while loading map", JOptionPane.ERROR_MESSAGE); e.printStackTrace(); } ch.addChoosableFileFilter( new TiledFileFilter(TiledFileFilter.FILTER_TMX)); int ret = ch.showOpenDialog(this); if (ret == JFileChooser.APPROVE_OPTION) { myBrush = new CustomBrush( MapHelper.loadMap(ch.getSelectedFile().getAbsolutePath())); } } }