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