Home | History | Annotate | Download | only in effects
      1 /*******************************************************************************
      2  * Copyright 2011 See AUTHORS file.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *   http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  ******************************************************************************/
     16 
     17 package com.badlogic.gdx.tools.hiero.unicodefont.effects;
     18 
     19 import java.awt.AlphaComposite;
     20 import java.awt.Color;
     21 import java.awt.Dimension;
     22 import java.awt.EventQueue;
     23 import java.awt.Graphics2D;
     24 import java.awt.GridBagConstraints;
     25 import java.awt.GridBagLayout;
     26 import java.awt.Insets;
     27 import java.awt.event.ActionEvent;
     28 import java.awt.event.ActionListener;
     29 import java.awt.image.BufferedImage;
     30 
     31 import javax.swing.BorderFactory;
     32 import javax.swing.DefaultComboBoxModel;
     33 import javax.swing.JButton;
     34 import javax.swing.JCheckBox;
     35 import javax.swing.JColorChooser;
     36 import javax.swing.JComboBox;
     37 import javax.swing.JComponent;
     38 import javax.swing.JDialog;
     39 import javax.swing.JLabel;
     40 import javax.swing.JPanel;
     41 import javax.swing.JSpinner;
     42 import javax.swing.JTextArea;
     43 import javax.swing.SpinnerNumberModel;
     44 
     45 import com.badlogic.gdx.tools.hiero.unicodefont.GlyphPage;
     46 import com.badlogic.gdx.tools.hiero.unicodefont.effects.ConfigurableEffect.Value;
     47 
     48 /** Provides utility methods for effects.
     49  * @author Nathan Sweet */
     50 public class EffectUtil {
     51 	static private BufferedImage scratchImage = new BufferedImage(GlyphPage.MAX_GLYPH_SIZE, GlyphPage.MAX_GLYPH_SIZE,
     52 		BufferedImage.TYPE_INT_ARGB);
     53 
     54 	/** Returns an image that can be used by effects as a temp image. */
     55 	static public BufferedImage getScratchImage () {
     56 		Graphics2D g = (Graphics2D)scratchImage.getGraphics();
     57 		g.setComposite(AlphaComposite.Clear);
     58 		g.fillRect(0, 0, GlyphPage.MAX_GLYPH_SIZE, GlyphPage.MAX_GLYPH_SIZE);
     59 		g.setComposite(AlphaComposite.SrcOver);
     60 		g.setColor(java.awt.Color.white);
     61 		return scratchImage;
     62 	}
     63 
     64 	/** Returns a value that represents a color. */
     65 	static public Value colorValue (String name, Color currentValue) {
     66 		return new DefaultValue(name, EffectUtil.toString(currentValue)) {
     67 			public void showDialog () {
     68 				Color newColor = JColorChooser.showDialog(null, "Choose a color", EffectUtil.fromString(value));
     69 				if (newColor != null) value = EffectUtil.toString(newColor);
     70 			}
     71 
     72 			public Object getObject () {
     73 				return EffectUtil.fromString(value);
     74 			}
     75 		};
     76 	}
     77 
     78 	/** Returns a value that represents an int. */
     79 	static public Value intValue (String name, final int currentValue, final String description) {
     80 		return new DefaultValue(name, String.valueOf(currentValue)) {
     81 			public void showDialog () {
     82 				JSpinner spinner = new JSpinner(new SpinnerNumberModel(currentValue, Short.MIN_VALUE, Short.MAX_VALUE, 1));
     83 				if (showValueDialog(spinner, description)) value = String.valueOf(spinner.getValue());
     84 			}
     85 
     86 			public Object getObject () {
     87 				return Integer.valueOf(value);
     88 			}
     89 		};
     90 	}
     91 
     92 	/** Returns a value that represents a float, from 0 to 1 (inclusive). */
     93 	static public Value floatValue (String name, final float currentValue, final float min, final float max,
     94 		final String description) {
     95 		return new DefaultValue(name, String.valueOf(currentValue)) {
     96 			public void showDialog () {
     97 				JSpinner spinner = new JSpinner(new SpinnerNumberModel(currentValue, min, max, 0.1f));
     98 				if (showValueDialog(spinner, description)) value = String.valueOf(((Double)spinner.getValue()).floatValue());
     99 			}
    100 
    101 			public Object getObject () {
    102 				return Float.valueOf(value);
    103 			}
    104 		};
    105 	}
    106 
    107 	/** Returns a value that represents a boolean. */
    108 	static public Value booleanValue (String name, final boolean currentValue, final String description) {
    109 		return new DefaultValue(name, String.valueOf(currentValue)) {
    110 			public void showDialog () {
    111 				JCheckBox checkBox = new JCheckBox();
    112 				checkBox.setSelected(currentValue);
    113 				if (showValueDialog(checkBox, description)) value = String.valueOf(checkBox.isSelected());
    114 			}
    115 
    116 			public Object getObject () {
    117 				return Boolean.valueOf(value);
    118 			}
    119 		};
    120 	}
    121 
    122 	/** Returns a value that represents a fixed number of options. All options are strings.
    123 	 * @param options The first array has an entry for each option. Each entry is either a String[1] that is both the display value
    124 	 *           and actual value, or a String[2] whose first element is the display value and second element is the actual value. */
    125 	static public Value optionValue (String name, final String currentValue, final String[][] options, final String description) {
    126 		return new DefaultValue(name, currentValue.toString()) {
    127 			public void showDialog () {
    128 				int selectedIndex = -1;
    129 				DefaultComboBoxModel model = new DefaultComboBoxModel();
    130 				for (int i = 0; i < options.length; i++) {
    131 					model.addElement(options[i][0]);
    132 					if (getValue(i).equals(currentValue)) selectedIndex = i;
    133 				}
    134 				JComboBox comboBox = new JComboBox(model);
    135 				comboBox.setSelectedIndex(selectedIndex);
    136 				if (showValueDialog(comboBox, description)) value = getValue(comboBox.getSelectedIndex());
    137 			}
    138 
    139 			private String getValue (int i) {
    140 				if (options[i].length == 1) return options[i][0];
    141 				return options[i][1];
    142 			}
    143 
    144 			public String toString () {
    145 				for (int i = 0; i < options.length; i++)
    146 					if (getValue(i).equals(value)) return options[i][0].toString();
    147 				return "";
    148 			}
    149 
    150 			public Object getObject () {
    151 				return value;
    152 			}
    153 		};
    154 	}
    155 
    156 	/** Convers a color to a string. */
    157 	static public String toString (Color color) {
    158 		if (color == null) throw new IllegalArgumentException("color cannot be null.");
    159 		String r = Integer.toHexString(color.getRed());
    160 		if (r.length() == 1) r = "0" + r;
    161 		String g = Integer.toHexString(color.getGreen());
    162 		if (g.length() == 1) g = "0" + g;
    163 		String b = Integer.toHexString(color.getBlue());
    164 		if (b.length() == 1) b = "0" + b;
    165 		return r + g + b;
    166 	}
    167 
    168 	/** Converts a string to a color. */
    169 	static public Color fromString (String rgb) {
    170 		if (rgb == null || rgb.length() != 6) return Color.white;
    171 		return new Color(Integer.parseInt(rgb.substring(0, 2), 16), Integer.parseInt(rgb.substring(2, 4), 16), Integer.parseInt(
    172 			rgb.substring(4, 6), 16));
    173 	}
    174 
    175 	/** Provides generic functionality for an effect's configurable value. */
    176 	static private abstract class DefaultValue implements Value {
    177 		String value;
    178 		String name;
    179 
    180 		public DefaultValue (String name, String value) {
    181 			this.value = value;
    182 			this.name = name;
    183 		}
    184 
    185 		public void setString (String value) {
    186 			this.value = value;
    187 		}
    188 
    189 		public String getString () {
    190 			return value;
    191 		}
    192 
    193 		public String getName () {
    194 			return name;
    195 		}
    196 
    197 		public String toString () {
    198 			if (value == null) return "";
    199 			return value.toString();
    200 		}
    201 
    202 		public boolean showValueDialog (final JComponent component, String description) {
    203 			ValueDialog dialog = new ValueDialog(component, name, description);
    204 			dialog.setTitle(name);
    205 			dialog.setLocationRelativeTo(null);
    206 			EventQueue.invokeLater(new Runnable() {
    207 				public void run () {
    208 					JComponent focusComponent = component;
    209 					if (focusComponent instanceof JSpinner)
    210 						focusComponent = ((JSpinner.DefaultEditor)((JSpinner)component).getEditor()).getTextField();
    211 					focusComponent.requestFocusInWindow();
    212 				}
    213 			});
    214 			dialog.setVisible(true);
    215 			return dialog.okPressed;
    216 		}
    217 	};
    218 
    219 	/** Provides generic functionality for a dialog to configure a value. */
    220 	static private class ValueDialog extends JDialog {
    221 		public boolean okPressed = false;
    222 
    223 		public ValueDialog (JComponent component, String name, String description) {
    224 			setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
    225 			setLayout(new GridBagLayout());
    226 			setModal(true);
    227 
    228 			if (component instanceof JSpinner)
    229 				((JSpinner.DefaultEditor)((JSpinner)component).getEditor()).getTextField().setColumns(4);
    230 
    231 			JPanel descriptionPanel = new JPanel();
    232 			descriptionPanel.setLayout(new GridBagLayout());
    233 			getContentPane().add(
    234 				descriptionPanel,
    235 				new GridBagConstraints(0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0,
    236 					0), 0, 0));
    237 			descriptionPanel.setBackground(Color.white);
    238 			descriptionPanel.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, Color.black));
    239 			{
    240 				JTextArea descriptionText = new JTextArea(description);
    241 				descriptionPanel.add(descriptionText, new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0, GridBagConstraints.CENTER,
    242 					GridBagConstraints.BOTH, new Insets(5, 5, 5, 5), 0, 0));
    243 				descriptionText.setWrapStyleWord(true);
    244 				descriptionText.setLineWrap(true);
    245 				descriptionText.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
    246 				descriptionText.setEditable(false);
    247 			}
    248 
    249 			JPanel panel = new JPanel();
    250 			getContentPane().add(
    251 				panel,
    252 				new GridBagConstraints(0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.NONE, new Insets(5, 5, 0,
    253 					5), 0, 0));
    254 			panel.add(new JLabel(name + ":"));
    255 			panel.add(component);
    256 
    257 			JPanel buttonPanel = new JPanel();
    258 			getContentPane().add(
    259 				buttonPanel,
    260 				new GridBagConstraints(0, 2, 2, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE,
    261 					new Insets(0, 0, 0, 0), 0, 0));
    262 			{
    263 				JButton okButton = new JButton("OK");
    264 				buttonPanel.add(okButton);
    265 				okButton.addActionListener(new ActionListener() {
    266 					public void actionPerformed (ActionEvent evt) {
    267 						okPressed = true;
    268 						setVisible(false);
    269 					}
    270 				});
    271 			}
    272 			{
    273 				JButton cancelButton = new JButton("Cancel");
    274 				buttonPanel.add(cancelButton);
    275 				cancelButton.addActionListener(new ActionListener() {
    276 					public void actionPerformed (ActionEvent evt) {
    277 						setVisible(false);
    278 					}
    279 				});
    280 			}
    281 
    282 			setSize(new Dimension(320, 175));
    283 		}
    284 	}
    285 }
    286