Created PApplet and PConstants wrapper classes.

Also removed unused ColorSelector and CreateFont to reduce wrappers
size to the minimum.
This commit is preparatory for dropping dependency on processing-core.
This commit is contained in:
Cristian Maglie 2014-08-19 11:50:51 +02:00
parent 21de7bdea3
commit 18a8d4d627
4 changed files with 751 additions and 1422 deletions

View File

@ -0,0 +1,729 @@
package processing.app.legacy;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public class PApplet {
/** Path to sketch folder */
public String sketchPath; //folder;
/**
* Full name of the Java version (i.e. 1.5.0_11).
* Prior to 0125, this was only the first three digits.
*/
public static final String javaVersionName =
System.getProperty("java.version");
/**
* Version of Java that's in use, whether 1.1 or 1.3 or whatever,
* stored as a float.
* <P>
* Note that because this is stored as a float, the values may
* not be <EM>exactly</EM> 1.3 or 1.4. Instead, make sure you're
* comparing against 1.3f or 1.4f, which will have the same amount
* of error (i.e. 1.40000001). This could just be a double, but
* since Processing only uses floats, it's safer for this to be a float
* because there's no good way to specify a double with the preproc.
*/
public static final float javaVersion =
new Float(javaVersionName.substring(0, 3)).floatValue();
/**
* Current platform in use, one of the
* PConstants WINDOWS, MACOSX, MACOS9, LINUX or OTHER.
*/
static public int platform;
/**
* Name associated with the current 'platform' (see PConstants.platformNames)
*/
//static public String platformName;
static {
String osname = System.getProperty("os.name");
if (osname.indexOf("Mac") != -1) {
platform = PConstants.MACOSX;
} else if (osname.indexOf("Windows") != -1) {
platform = PConstants.WINDOWS;
} else if (osname.equals("Linux")) { // true for the ibm vm
platform = PConstants.LINUX;
} else {
platform = PConstants.OTHER;
}
}
/**
* GIF image of the Processing logo.
*/
static public final byte[] ICON_IMAGE = {
71, 73, 70, 56, 57, 97, 16, 0, 16, 0, -60, 0, 0, 0, 0, 0,
0, 0, -127, 0, -127, 0, 0, -127, -127, -127, 0, 0, -127, 0, -127, -127,
-127, 0, -127, -127, -127, -63, -63, -63, 0, 0, -1, 0, -1, 0, 0, -1,
-1, -1, 0, 0, -1, 0, -1, -1, -1, 0, -1, -1, -1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, -7, 4,
9, 0, 0, 16, 0, 44, 0, 0, 0, 0, 16, 0, 16, 0, 0, 5,
75, 32, 36, -118, -57, 96, 14, -57, -88, 66, -27, -23, -90, -86, 43, -97,
99, 59, -65, -30, 125, -77, 3, -14, -4, 8, -109, 15, -120, -22, 61, 78,
15, -124, 15, 25, 28, 28, 93, 63, -45, 115, -22, -116, 90, -83, 82, 89,
-44, -103, 61, 44, -91, -54, -89, 19, -111, 50, 18, -51, -55, 1, 73, -121,
-53, -79, 77, 43, -101, 12, -74, -30, -99, -24, -94, 16, 0, 59,
};
/**
* Split the provided String at wherever whitespace occurs. Multiple
* whitespace (extra spaces or tabs or whatever) between items will count as a
* single break.
* <P>
* The whitespace characters are "\t\n\r\f", which are the defaults for
* java.util.StringTokenizer, plus the unicode non-breaking space character,
* which is found commonly on files created by or used in conjunction with Mac
* OS X (character 160, or 0x00A0 in hex).
*
* <PRE>
* i.e. splitTokens("a b") -> { "a", "b" }
* splitTokens("a b") -> { "a", "b" }
* splitTokens("a\tb") -> { "a", "b" }
* splitTokens("a \t b ") -> { "a", "b" }
* </PRE>
*/
static public String[] splitTokens(String what) {
return splitTokens(what, PConstants.WHITESPACE);
}
/**
* Splits a string into pieces, using any of the chars in the String 'delim'
* as separator characters. For instance, in addition to white space, you
* might want to treat commas as a separator. The delimeter characters won't
* appear in the returned String array.
*
* <PRE>
* i.e. splitTokens("a, b", " ,") -> { "a", "b" }
* </PRE>
*
* To include all the whitespace possibilities, use the variable WHITESPACE,
* found in PConstants:
*
* <PRE>
* i.e. splitTokens("a | b", WHITESPACE + "|"); -> { "a", "b" }
* </PRE>
*/
static public String[] splitTokens(String what, String delim) {
StringTokenizer toker = new StringTokenizer(what, delim);
String pieces[] = new String[toker.countTokens()];
int index = 0;
while (toker.hasMoreTokens()) {
pieces[index++] = toker.nextToken();
}
return pieces;
}
/**
* Split a string into pieces along a specific character. Most commonly used
* to break up a String along a space or a tab character.
* <P>
* This operates differently than the others, where the single delimeter is
* the only breaking point, and consecutive delimeters will produce an empty
* string (""). This way, one can split on tab characters, but maintain the
* column alignments (of say an excel file) where there are empty columns.
*/
static public String[] split(String what, char delim) {
// do this so that the exception occurs inside the user's
// program, rather than appearing to be a bug inside split()
if (what == null)
return null;
char chars[] = what.toCharArray();
int splitCount = 0; // 1;
for (int i = 0; i < chars.length; i++) {
if (chars[i] == delim)
splitCount++;
}
if (splitCount == 0) {
String splits[] = new String[1];
splits[0] = new String(what);
return splits;
}
String splits[] = new String[splitCount + 1];
int splitIndex = 0;
int startIndex = 0;
for (int i = 0; i < chars.length; i++) {
if (chars[i] == delim) {
splits[splitIndex++] = new String(chars, startIndex, i - startIndex);
startIndex = i + 1;
}
}
splits[splitIndex] = new String(chars, startIndex, chars.length
- startIndex);
return splits;
}
static public String[] subset(String list[], int start, int count) {
String output[] = new String[count];
System.arraycopy(list, start, output, 0, count);
return output;
}
/**
* Join an array of Strings together as a single String,
* separated by the whatever's passed in for the separator.
*/
static public String join(String str[], char separator) {
return join(str, String.valueOf(separator));
}
/**
* Join an array of Strings together as a single String,
* separated by the whatever's passed in for the separator.
* <P>
* To use this on numbers, first pass the array to nf() or nfs()
* to get a list of String objects, then use join on that.
* <PRE>
* e.g. String stuff[] = { "apple", "bear", "cat" };
* String list = join(stuff, ", ");
* // list is now "apple, bear, cat"</PRE>
*/
static public String join(String str[], String separator) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < str.length; i++) {
if (i != 0) buffer.append(separator);
buffer.append(str[i]);
}
return buffer.toString();
}
/**
* Parse a String into an int value. Returns 0 if the value is bad.
*/
static final public int parseInt(String what) {
return parseInt(what, 0);
}
/**
* Parse a String to an int, and provide an alternate value that
* should be used when the number is invalid.
*/
static final public int parseInt(String what, int otherwise) {
try {
int offset = what.indexOf('.');
if (offset == -1) {
return Integer.parseInt(what);
} else {
return Integer.parseInt(what.substring(0, offset));
}
} catch (NumberFormatException e) { }
return otherwise;
}
/**
* Make an array of int elements from an array of String objects.
* If the String can't be parsed as a number, it will be set to zero.
*
* String s[] = { "1", "300", "44" };
* int numbers[] = parseInt(s);
*
* numbers will contain { 1, 300, 44 }
*/
static public int[] parseInt(String what[]) {
return parseInt(what, 0);
}
/**
* Make an array of int elements from an array of String objects.
* If the String can't be parsed as a number, its entry in the
* array will be set to the value of the "missing" parameter.
*
* String s[] = { "1", "300", "apple", "44" };
* int numbers[] = parseInt(s, 9999);
*
* numbers will contain { 1, 300, 9999, 44 }
*/
static public int[] parseInt(String what[], int missing) {
int output[] = new int[what.length];
for (int i = 0; i < what.length; i++) {
try {
output[i] = Integer.parseInt(what[i]);
} catch (NumberFormatException e) {
output[i] = missing;
}
}
return output;
}
static public String[] loadStrings(File file) {
InputStream is = createInput(file);
if (is != null) return loadStrings(is);
return null;
}
static public String[] loadStrings(InputStream input) {
try {
BufferedReader reader =
new BufferedReader(new InputStreamReader(input, "UTF-8"));
String lines[] = new String[100];
int lineCount = 0;
String line = null;
while ((line = reader.readLine()) != null) {
if (lineCount == lines.length) {
String temp[] = new String[lineCount << 1];
System.arraycopy(lines, 0, temp, 0, lineCount);
lines = temp;
}
lines[lineCount++] = line;
}
reader.close();
if (lineCount == lines.length) {
return lines;
}
// resize array to appropriate amount for these lines
String output[] = new String[lineCount];
System.arraycopy(lines, 0, output, 0, lineCount);
return output;
} catch (IOException e) {
e.printStackTrace();
//throw new RuntimeException("Error inside loadStrings()");
}
return null;
}
public void saveStrings(String filename, String strings[]) {
saveStrings(saveFile(filename), strings);
}
static public void saveStrings(File file, String strings[]) {
saveStrings(createOutput(file), strings);
}
static public void saveStrings(OutputStream output, String strings[]) {
PrintWriter writer = createWriter(output);
for (int i = 0; i < strings.length; i++) {
writer.println(strings[i]);
}
writer.flush();
writer.close();
}
static public int[] expand(int list[]) {
return expand(list, list.length << 1);
}
static public int[] expand(int list[], int newSize) {
int temp[] = new int[newSize];
System.arraycopy(list, 0, temp, 0, Math.min(newSize, list.length));
return temp;
}
static final public String hex(int what, int digits) {
String stuff = Integer.toHexString(what).toUpperCase();
int length = stuff.length();
if (length > digits) {
return stuff.substring(length - digits);
} else if (length < digits) {
return "00000000".substring(8 - (digits-length)) + stuff;
}
return stuff;
}
static public final int constrain(int amt, int low, int high) {
return (amt < low) ? low : ((amt > high) ? high : amt);
}
static public final float constrain(float amt, float low, float high) {
return (amt < low) ? low : ((amt > high) ? high : amt);
}
/**
* Attempts to open an application or file using your platform's launcher. The <b>file</b> parameter is a String specifying the file name and location. The location parameter must be a full path name, or the name of an executable in the system's PATH. In most cases, using a full path is the best option, rather than relying on the system PATH. Be sure to make the file executable before attempting to open it (chmod +x).
* <br><br>
* The <b>args</b> parameter is a String or String array which is passed to the command line. If you have multiple parameters, e.g. an application and a document, or a command with multiple switches, use the version that takes a String array, and place each individual item in a separate element.
* <br><br>
* If args is a String (not an array), then it can only be a single file or application with no parameters. It's not the same as executing that String using a shell. For instance, open("jikes -help") will not work properly.
* <br><br>
* This function behaves differently on each platform. On Windows, the parameters are sent to the Windows shell via "cmd /c". On Mac OS X, the "open" command is used (type "man open" in Terminal.app for documentation). On Linux, it first tries gnome-open, then kde-open, but if neither are available, it sends the command to the shell without any alterations.
* <br><br>
* For users familiar with Java, this is not quite the same as Runtime.exec(), because the launcher command is prepended. Instead, the <b>exec(String[])</b> function is a shortcut for Runtime.getRuntime.exec(String[]).
*
* @webref input:files
* @param filename name of the file
* @usage Application
*/
static public void open(String filename) {
open(new String[] { filename });
}
static String openLauncher;
/**
* Launch a process using a platforms shell. This version uses an array
* to make it easier to deal with spaces in the individual elements.
* (This avoids the situation of trying to put single or double quotes
* around different bits).
*
* @param list of commands passed to the command line
*/
static public Process open(String argv[]) {
String[] params = null;
if (platform == PConstants.WINDOWS) {
// just launching the .html file via the shell works
// but make sure to chmod +x the .html files first
// also place quotes around it in case there's a space
// in the user.dir part of the url
params = new String[] { "cmd", "/c" };
} else if (platform == PConstants.MACOSX) {
params = new String[] { "open" };
} else if (platform == PConstants.LINUX) {
if (openLauncher == null) {
// Attempt to use gnome-open
try {
Process p = Runtime.getRuntime().exec(new String[] { "gnome-open" });
/*int result =*/ p.waitFor();
// Not installed will throw an IOException (JDK 1.4.2, Ubuntu 7.04)
openLauncher = "gnome-open";
} catch (Exception e) { }
}
if (openLauncher == null) {
// Attempt with kde-open
try {
Process p = Runtime.getRuntime().exec(new String[] { "kde-open" });
/*int result =*/ p.waitFor();
openLauncher = "kde-open";
} catch (Exception e) { }
}
if (openLauncher == null) {
System.err.println("Could not find gnome-open or kde-open, " +
"the open() command may not work.");
}
if (openLauncher != null) {
params = new String[] { openLauncher };
}
//} else { // give up and just pass it to Runtime.exec()
//open(new String[] { filename });
//params = new String[] { filename };
}
if (params != null) {
// If the 'open', 'gnome-open' or 'cmd' are already included
if (params[0].equals(argv[0])) {
// then don't prepend those params again
return exec(argv);
} else {
params = concat(params, argv);
return exec(params);
}
} else {
return exec(argv);
}
}
static public Process exec(String[] argv) {
try {
return Runtime.getRuntime().exec(argv);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Could not open " + join(argv, ' '));
}
}
static public String[] concat(String a[], String b[]) {
String c[] = new String[a.length + b.length];
System.arraycopy(a, 0, c, 0, a.length);
System.arraycopy(b, 0, c, a.length, b.length);
return c;
}
/**
* Identical to match(), except that it returns an array of all matches in
* the specified String, rather than just the first.
*/
static public String[][] matchAll(String what, String regexp) {
Pattern p = Pattern.compile(regexp, Pattern.MULTILINE | Pattern.DOTALL);
Matcher m = p.matcher(what);
ArrayList<String[]> results = new ArrayList<String[]>();
int count = m.groupCount() + 1;
while (m.find()) {
String[] groups = new String[count];
for (int i = 0; i < count; i++) {
groups[i] = m.group(i);
}
results.add(groups);
}
if (results.isEmpty()) {
return null;
}
String[][] matches = new String[results.size()][count];
for (int i = 0; i < matches.length; i++) {
matches[i] = (String[]) results.get(i);
}
return matches;
}
/**
* Match a string with a regular expression, and returns the match as an
* array. The first index is the matching expression, and array elements
* [1] and higher represent each of the groups (sequences found in parens).
*
* This uses multiline matching (Pattern.MULTILINE) and dotall mode
* (Pattern.DOTALL) by default, so that ^ and $ match the beginning and
* end of any lines found in the source, and the . operator will also
* pick up newline characters.
*/
static public String[] match(String what, String regexp) {
Pattern p = Pattern.compile(regexp, Pattern.MULTILINE | Pattern.DOTALL);
Matcher m = p.matcher(what);
if (m.find()) {
int count = m.groupCount() + 1;
String[] groups = new String[count];
for (int i = 0; i < count; i++) {
groups[i] = m.group(i);
}
return groups;
}
return null;
}
/**
* Integer number formatter.
*/
static private NumberFormat int_nf;
static private int int_nf_digits;
static private boolean int_nf_commas;
static public String[] nf(int num[], int digits) {
String formatted[] = new String[num.length];
for (int i = 0; i < formatted.length; i++) {
formatted[i] = nf(num[i], digits);
}
return formatted;
}
static public String nf(int num, int digits) {
if ((int_nf != null) &&
(int_nf_digits == digits) &&
!int_nf_commas) {
return int_nf.format(num);
}
int_nf = NumberFormat.getInstance();
int_nf.setGroupingUsed(false); // no commas
int_nf_commas = false;
int_nf.setMinimumIntegerDigits(digits);
int_nf_digits = digits;
return int_nf.format(num);
}
static final public String[] str(int x[]) {
String s[] = new String[x.length];
for (int i = 0; i < x.length; i++) s[i] = String.valueOf(x[i]);
return s;
}
/**
* I want to print lines to a file. I have RSI from typing these
* eight lines of code so many times.
*/
static public PrintWriter createWriter(File file) {
try {
createPath(file); // make sure in-between folders exist
OutputStream output = new FileOutputStream(file);
if (file.getName().toLowerCase().endsWith(".gz")) {
output = new GZIPOutputStream(output);
}
return createWriter(output);
} catch (Exception e) {
if (file == null) {
throw new RuntimeException("File passed to createWriter() was null");
} else {
e.printStackTrace();
throw new RuntimeException("Couldn't create a writer for " +
file.getAbsolutePath());
}
}
//return null;
}
/**
* I want to print lines to a file. Why am I always explaining myself?
* It's the JavaSoft API engineers who need to explain themselves.
*/
static public PrintWriter createWriter(OutputStream output) {
try {
OutputStreamWriter osw = new OutputStreamWriter(output, "UTF-8");
return new PrintWriter(osw);
} catch (UnsupportedEncodingException e) { } // not gonna happen
return null;
}
static public InputStream createInput(File file) {
if (file == null) {
throw new IllegalArgumentException("File passed to createInput() was null");
}
try {
InputStream input = new FileInputStream(file);
if (file.getName().toLowerCase().endsWith(".gz")) {
return new GZIPInputStream(input);
}
return input;
} catch (IOException e) {
System.err.println("Could not createInput() for " + file);
e.printStackTrace();
return null;
}
}
/**
* Returns a path inside the applet folder to save to. Like sketchPath(),
* but creates any in-between folders so that things save properly.
* <p/>
* All saveXxxx() functions use the path to the sketch folder, rather than
* its data folder. Once exported, the data folder will be found inside the
* jar file of the exported application or applet. In this case, it's not
* possible to save data into the jar file, because it will often be running
* from a server, or marked in-use if running from a local file system.
* With this in mind, saving to the data path doesn't make sense anyway.
* If you know you're running locally, and want to save to the data folder,
* use <TT>saveXxxx("data/blah.dat")</TT>.
*/
public String savePath(String where) {
if (where == null) return null;
String filename = sketchPath(where);
createPath(filename);
return filename;
}
/**
* Identical to savePath(), but returns a File object.
*/
public File saveFile(String where) {
return new File(savePath(where));
}
/**
* Similar to createInput() (formerly openStream), this creates a Java
* OutputStream for a given filename or path. The file will be created in
* the sketch folder, or in the same folder as an exported application.
* <p/>
* If the path does not exist, intermediate folders will be created. If an
* exception occurs, it will be printed to the console, and null will be
* returned.
* <p/>
* Future releases may also add support for handling HTTP POST via this
* method (for better symmetry with createInput), however that's maybe a
* little too clever (and then we'd have to add the same features to the
* other file functions like createWriter). Who you callin' bloated?
*/
public OutputStream createOutput(String filename) {
return createOutput(saveFile(filename));
}
static public OutputStream createOutput(File file) {
try {
createPath(file); // make sure the path exists
FileOutputStream fos = new FileOutputStream(file);
if (file.getName().toLowerCase().endsWith(".gz")) {
return new GZIPOutputStream(fos);
}
return fos;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* Prepend the sketch folder path to the filename (or path) that is
* passed in. External libraries should use this function to save to
* the sketch folder.
* <p/>
* Note that when running as an applet inside a web browser,
* the sketchPath will be set to null, because security restrictions
* prevent applets from accessing that information.
* <p/>
* This will also cause an error if the sketch is not inited properly,
* meaning that init() was never called on the PApplet when hosted
* my some other main() or by other code. For proper use of init(),
* see the examples in the main description text for PApplet.
*/
public String sketchPath(String where) {
if (sketchPath == null) {
return where;
// throw new RuntimeException("The applet was not inited properly, " +
// "or security restrictions prevented " +
// "it from determining its path.");
}
// isAbsolute() could throw an access exception, but so will writing
// to the local disk using the sketch path, so this is safe here.
// for 0120, added a try/catch anyways.
try {
if (new File(where).isAbsolute()) return where;
} catch (Exception e) { }
return sketchPath + File.separator + where;
}
/**
* Takes a path and creates any in-between folders if they don't
* already exist. Useful when trying to save to a subfolder that
* may not actually exist.
*/
static public void createPath(String path) {
createPath(new File(path));
}
static public void createPath(File file) {
try {
String parent = file.getParent();
if (parent != null) {
File unit = new File(parent);
if (!unit.exists()) unit.mkdirs();
}
} catch (SecurityException se) {
System.err.println("You don't have permissions to create " +
file.getAbsolutePath());
}
}
}

View File

@ -0,0 +1,22 @@
package processing.app.legacy;
public class PConstants {
// platform IDs for PApplet.platform
public static final int OTHER = 0;
public static final int WINDOWS = 1;
public static final int MACOSX = 2;
public static final int LINUX = 3;
public static final String[] platformNames = {
"other", "windows", "macosx", "linux"
};
// used by split, all the standard whitespace chars
// (also includes unicode nbsp, that little bostage)
static final String WHITESPACE = " \t\n\r\f\u00A0";
}

View File

@ -1,609 +0,0 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2006-08 Ben Fry and Casey Reas
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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package processing.app.tools;
import processing.app.*;
import processing.core.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
import javax.swing.text.*;
/**
* Color selector tool for the Tools menu.
* <p/>
* Using the keyboard shortcuts, you can copy/paste the values for the
* colors and paste them into your program. We didn't do any sort of
* auto-insert of colorMode() or fill() or stroke() code cuz we couldn't
* decide on a good way to do this.. your contributions welcome).
*/
public class ColorSelector implements Tool, DocumentListener {
Editor editor;
JFrame frame;
int hue, saturation, brightness; // range 360, 100, 100
int red, green, blue; // range 256, 256, 256
ColorRange range;
ColorSlider slider;
JTextField hueField, saturationField, brightnessField;
JTextField redField, greenField, blueField;
JTextField hexField;
JPanel colorPanel;
public String getMenuTitle() {
return "Color Selector";
}
public void init(Editor editor) {
this.editor = editor;
frame = new JFrame("Color Selector");
frame.getContentPane().setLayout(new BorderLayout());
Box box = Box.createHorizontalBox();
box.setBorder(new EmptyBorder(12, 12, 12, 12));
range = new ColorRange();
range.init();
Box rangeBox = new Box(BoxLayout.Y_AXIS);
rangeBox.setAlignmentY(0);
rangeBox.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
rangeBox.add(range);
box.add(rangeBox);
box.add(Box.createHorizontalStrut(10));
slider = new ColorSlider();
slider.init();
Box sliderBox = new Box(BoxLayout.Y_AXIS);
sliderBox.setAlignmentY(0);
sliderBox.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
sliderBox.add(slider);
box.add(sliderBox);
box.add(Box.createHorizontalStrut(10));
box.add(createColorFields());
box.add(Box.createHorizontalStrut(10));
frame.getContentPane().add(box, BorderLayout.CENTER);
frame.pack();
frame.setResizable(false);
// these don't help either.. they fix the component size but
// leave a gap where the component is located
//range.setSize(256, 256);
//slider.setSize(256, 20);
Dimension size = frame.getSize();
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
frame.setLocation((screen.width - size.width) / 2,
(screen.height - size.height) / 2);
frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
frame.setVisible(false);
}
});
Base.registerWindowCloseKeys(frame.getRootPane(), new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
frame.setVisible(false);
}
});
Base.setIcon(frame);
hueField.getDocument().addDocumentListener(this);
saturationField.getDocument().addDocumentListener(this);
brightnessField.getDocument().addDocumentListener(this);
redField.getDocument().addDocumentListener(this);
greenField.getDocument().addDocumentListener(this);
blueField.getDocument().addDocumentListener(this);
hexField.getDocument().addDocumentListener(this);
hexField.setText("FFFFFF");
}
public void run() {
frame.setVisible(true);
// You've got to be f--ing kidding me.. why did the following line
// get deprecated for the pile of s-- that follows it?
//frame.setCursor(Cursor.CROSSHAIR_CURSOR);
frame.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
}
public void changedUpdate(DocumentEvent e) {
//System.out.println("changed");
}
public void removeUpdate(DocumentEvent e) {
//System.out.println("remove");
}
boolean updating;
public void insertUpdate(DocumentEvent e) {
if (updating) return; // don't update forever recursively
updating = true;
Document doc = e.getDocument();
if (doc == hueField.getDocument()) {
hue = bounded(hue, hueField, 359);
updateRGB();
updateHex();
} else if (doc == saturationField.getDocument()) {
saturation = bounded(saturation, saturationField, 99);
updateRGB();
updateHex();
} else if (doc == brightnessField.getDocument()) {
brightness = bounded(brightness, brightnessField, 99);
updateRGB();
updateHex();
} else if (doc == redField.getDocument()) {
red = bounded(red, redField, 255);
updateHSB();
updateHex();
} else if (doc == greenField.getDocument()) {
green = bounded(green, greenField, 255);
updateHSB();
updateHex();
} else if (doc == blueField.getDocument()) {
blue = bounded(blue, blueField, 255);
updateHSB();
updateHex();
} else if (doc == hexField.getDocument()) {
String str = hexField.getText();
while (str.length() < 6) {
str += "0";
}
if (str.length() > 6) {
str = str.substring(0, 6);
}
updateRGB2(Integer.parseInt(str, 16));
updateHSB();
}
range.redraw();
slider.redraw();
colorPanel.repaint();
updating = false;
}
/**
* Set the RGB values based on the current HSB values.
*/
protected void updateRGB() {
int rgb = Color.HSBtoRGB((float)hue / 359f,
(float)saturation / 99f,
(float)brightness / 99f);
updateRGB2(rgb);
}
/**
* Set the RGB values based on a calculated ARGB int.
* Used by both updateRGB() to set the color from the HSB values,
* and by updateHex(), to unpack the hex colors and assign them.
*/
protected void updateRGB2(int rgb) {
red = (rgb >> 16) & 0xff;
green = (rgb >> 8) & 0xff;
blue = rgb & 0xff;
redField.setText(String.valueOf(red));
greenField.setText(String.valueOf(green));
blueField.setText(String.valueOf(blue));
}
/**
* Set the HSB values based on the current RGB values.
*/
protected void updateHSB() {
float hsb[] = new float[3];
Color.RGBtoHSB(red, green, blue, hsb);
hue = (int) (hsb[0] * 359.0f);
saturation = (int) (hsb[1] * 99.0f);
brightness = (int) (hsb[2] * 99.0f);
hueField.setText(String.valueOf(hue));
saturationField.setText(String.valueOf(saturation));
brightnessField.setText(String.valueOf(brightness));
}
protected void updateHex() {
hexField.setText(PApplet.hex(red, 2) +
PApplet.hex(green, 2) +
PApplet.hex(blue, 2));
}
/**
* Get the bounded value for a specific range. If the value is outside
* the max, you can't edit right away, so just act as if it's already
* been bounded and return the bounded value, then fire an event to set
* it to the value that was just returned.
*/
protected int bounded(int current, final JTextField field, final int max) {
String text = field.getText();
if (text.length() == 0) {
return 0;
}
try {
int value = Integer.parseInt(text);
if (value > max) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
field.setText(String.valueOf(max));
}
});
return max;
}
return value;
} catch (NumberFormatException e) {
return current; // should not be reachable
}
}
protected Container createColorFields() {
Box box = Box.createVerticalBox();
box.setAlignmentY(0);
colorPanel = new JPanel() {
public void paintComponent(Graphics g) {
g.setColor(new Color(red, green, blue));
Dimension size = getSize();
g.fillRect(0, 0, size.width, size.height);
}
};
colorPanel.setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
Dimension dim = new Dimension(60, 40);
colorPanel.setMinimumSize(dim);
//colorPanel.setMaximumSize(dim);
//colorPanel.setPreferredSize(dim);
box.add(colorPanel);
box.add(Box.createVerticalStrut(10));
Box row;
row = Box.createHorizontalBox();
row.add(createFixedLabel("H:"));
row.add(hueField = new NumberField(4, false));
row.add(new JLabel(" \u00B0")); // degree symbol
row.add(Box.createHorizontalGlue());
box.add(row);
box.add(Box.createVerticalStrut(5));
row = Box.createHorizontalBox();
row.add(createFixedLabel("S:"));
row.add(saturationField = new NumberField(4, false));
row.add(new JLabel(" %"));
row.add(Box.createHorizontalGlue());
box.add(row);
box.add(Box.createVerticalStrut(5));
row = Box.createHorizontalBox();
row.add(createFixedLabel("B:"));
row.add(brightnessField = new NumberField(4, false));
row.add(new JLabel(" %"));
row.add(Box.createHorizontalGlue());
box.add(row);
box.add(Box.createVerticalStrut(10));
//
row = Box.createHorizontalBox();
row.add(createFixedLabel("R:"));
row.add(redField = new NumberField(4, false));
row.add(Box.createHorizontalGlue());
box.add(row);
box.add(Box.createVerticalStrut(5));
row = Box.createHorizontalBox();
row.add(createFixedLabel("G:"));
row.add(greenField = new NumberField(4, false));
row.add(Box.createHorizontalGlue());
box.add(row);
box.add(Box.createVerticalStrut(5));
row = Box.createHorizontalBox();
row.add(createFixedLabel("B:"));
row.add(blueField = new NumberField(4, false));
row.add(Box.createHorizontalGlue());
box.add(row);
box.add(Box.createVerticalStrut(10));
//
row = Box.createHorizontalBox();
row.add(createFixedLabel("#"));
row.add(hexField = new NumberField(5, true));
row.add(Box.createHorizontalGlue());
box.add(row);
box.add(Box.createVerticalStrut(10));
box.add(Box.createVerticalGlue());
return box;
}
int labelH;
/**
* return a label of a fixed width
*/
protected JLabel createFixedLabel(String title) {
JLabel label = new JLabel(title);
if (labelH == 0) {
labelH = label.getPreferredSize().height;
}
Dimension dim = new Dimension(20, labelH);
label.setPreferredSize(dim);
label.setMinimumSize(dim);
label.setMaximumSize(dim);
return label;
}
public class ColorRange extends PApplet {
static final int WIDE = 256;
static final int HIGH = 256;
int lastX, lastY;
public void setup() {
size(WIDE, HIGH, P3D);
noLoop();
colorMode(HSB, 360, 256, 256);
noFill();
rectMode(CENTER);
}
public void draw() {
if ((g == null) || (g.pixels == null)) return;
if ((width != WIDE) || (height < HIGH)) {
//System.out.println("bad size " + width + " " + height);
return;
}
int index = 0;
for (int j = 0; j < 256; j++) {
for (int i = 0; i < 256; i++) {
g.pixels[index++] = color(hue, i, 255 - j);
}
}
stroke((brightness > 50) ? 0 : 255);
rect(lastX, lastY, 9, 9);
}
public void mousePressed() {
updateMouse();
}
public void mouseDragged() {
updateMouse();
}
public void updateMouse() {
if ((mouseX >= 0) && (mouseX < 256) &&
(mouseY >= 0) && (mouseY < 256)) {
int nsaturation = (int) (100 * (mouseX / 255.0f));
int nbrightness = 100 - ((int) (100 * (mouseY / 255.0f)));
saturationField.setText(String.valueOf(nsaturation));
brightnessField.setText(String.valueOf(nbrightness));
lastX = mouseX;
lastY = mouseY;
}
}
public Dimension getPreferredSize() {
return new Dimension(WIDE, HIGH);
}
public Dimension getMinimumSize() {
return new Dimension(WIDE, HIGH);
}
public Dimension getMaximumSize() {
return new Dimension(WIDE, HIGH);
}
public void keyPressed() {
if (key == ESC) {
ColorSelector.this.frame.setVisible(false);
// don't quit out of processing
// http://dev.processing.org/bugs/show_bug.cgi?id=1006
key = 0;
}
}
}
public class ColorSlider extends PApplet {
static final int WIDE = 20;
static final int HIGH = 256;
public void setup() {
size(WIDE, HIGH, P3D);
colorMode(HSB, 255, 100, 100);
noLoop();
}
public void draw() {
if ((g == null) || (g.pixels == null)) return;
if ((width != WIDE) || (height < HIGH)) {
//System.out.println("bad size " + width + " " + height);
return;
}
int index = 0;
int sel = 255 - (int) (255 * (hue / 359f));
for (int j = 0; j < 256; j++) {
int c = color(255 - j, 100, 100);
if (j == sel) c = 0xFF000000;
for (int i = 0; i < WIDE; i++) {
g.pixels[index++] = c;
}
}
}
public void mousePressed() {
updateMouse();
}
public void mouseDragged() {
updateMouse();
}
public void updateMouse() {
if ((mouseX >= 0) && (mouseX < 256) &&
(mouseY >= 0) && (mouseY < 256)) {
int nhue = 359 - (int) (359 * (mouseY / 255.0f));
hueField.setText(String.valueOf(nhue));
}
}
public Dimension getPreferredSize() {
return new Dimension(WIDE, HIGH);
}
public Dimension getMinimumSize() {
return new Dimension(WIDE, HIGH);
}
public Dimension getMaximumSize() {
return new Dimension(WIDE, HIGH);
}
public void keyPressed() {
if (key == ESC) {
ColorSelector.this.frame.setVisible(false);
// don't quit out of processing
// http://dev.processing.org/bugs/show_bug.cgi?id=1006
key = 0;
}
}
}
/**
* Extension of JTextField that only allows numbers
*/
class NumberField extends JTextField {
public boolean allowHex;
public NumberField(int cols, boolean allowHex) {
super(cols);
this.allowHex = allowHex;
}
protected Document createDefaultModel() {
return new NumberDocument(this);
}
public Dimension getPreferredSize() {
if (!allowHex) {
return new Dimension(45, super.getPreferredSize().height);
}
return super.getPreferredSize();
}
public Dimension getMinimumSize() {
return getPreferredSize();
}
public Dimension getMaximumSize() {
return getPreferredSize();
}
}
/**
* Document model to go with JTextField that only allows numbers.
*/
class NumberDocument extends PlainDocument {
NumberField parentField;
public NumberDocument(NumberField parentField) {
this.parentField = parentField;
//System.out.println("setting parent to " + parentSelector);
}
public void insertString(int offs, String str, AttributeSet a)
throws BadLocationException {
if (str == null) return;
char chars[] = str.toCharArray();
int charCount = 0;
// remove any non-digit chars
for (int i = 0; i < chars.length; i++) {
boolean ok = Character.isDigit(chars[i]);
if (parentField.allowHex) {
if ((chars[i] >= 'A') && (chars[i] <= 'F')) ok = true;
if ((chars[i] >= 'a') && (chars[i] <= 'f')) ok = true;
}
if (ok) {
if (charCount != i) { // shift if necessary
chars[charCount] = chars[i];
}
charCount++;
}
}
super.insertString(offs, new String(chars, 0, charCount), a);
// can't call any sort of methods on the enclosing class here
// seems to have something to do with how Document objects are set up
}
}
}

View File

@ -1,813 +0,0 @@
/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2004-10 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology
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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package processing.app.tools;
import processing.app.*;
import processing.core.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.*;
/**
* GUI tool for font creation heaven/hell.
*/
public class CreateFont extends JFrame implements Tool {
Editor editor;
//Sketch sketch;
Dimension windowSize;
JList fontSelector;
JTextField sizeSelector;
JButton charsetButton;
JCheckBox smoothBox;
JComponent sample;
JButton okButton;
JTextField filenameField;
HashMap<String,Font> table;
boolean smooth = true;
Font font;
String[] list;
int selection = -1;
CharacterSelector charSelector;
public CreateFont() {
super("Create Font");
}
public String getMenuTitle() {
return "Create Font...";
}
public void init(Editor editor) {
this.editor = editor;
Container paine = getContentPane();
paine.setLayout(new BorderLayout()); //10, 10));
JPanel pain = new JPanel();
pain.setBorder(new EmptyBorder(13, 13, 13, 13));
paine.add(pain, BorderLayout.CENTER);
pain.setLayout(new BoxLayout(pain, BoxLayout.Y_AXIS));
String labelText =
"Use this tool to create bitmap fonts for your program.\n" +
"Select a font and size, and click 'OK' to generate the font.\n" +
"It will be added to the data folder of the current sketch.";
JTextArea textarea = new JTextArea(labelText);
textarea.setBorder(new EmptyBorder(10, 10, 20, 10));
textarea.setBackground(null);
textarea.setEditable(false);
textarea.setHighlighter(null);
textarea.setFont(new Font("Dialog", Font.PLAIN, 12));
pain.add(textarea);
// don't care about families starting with . or #
// also ignore dialog, dialoginput, monospaced, serif, sansserif
// getFontList is deprecated in 1.4, so this has to be used
GraphicsEnvironment ge =
GraphicsEnvironment.getLocalGraphicsEnvironment();
Font fonts[] = ge.getAllFonts();
String flist[] = new String[fonts.length];
table = new HashMap<String,Font>();
int index = 0;
for (int i = 0; i < fonts.length; i++) {
//String psname = fonts[i].getPSName();
//if (psname == null) System.err.println("ps name is null");
flist[index++] = fonts[i].getPSName();
table.put(fonts[i].getPSName(), fonts[i]);
}
list = new String[index];
System.arraycopy(flist, 0, list, 0, index);
fontSelector = new JList(list);
fontSelector.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
if (e.getValueIsAdjusting() == false) {
selection = fontSelector.getSelectedIndex();
okButton.setEnabled(true);
update();
}
}
});
fontSelector.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
fontSelector.setVisibleRowCount(12);
JScrollPane fontScroller = new JScrollPane(fontSelector);
pain.add(fontScroller);
Dimension d1 = new Dimension(13, 13);
pain.add(new Box.Filler(d1, d1, d1));
sample = new SampleComponent(this);
// Seems that in some instances, no default font is set
// http://dev.processing.org/bugs/show_bug.cgi?id=777
sample.setFont(new Font("Dialog", Font.PLAIN, 12));
pain.add(sample);
Dimension d2 = new Dimension(6, 6);
pain.add(new Box.Filler(d2, d2, d2));
JPanel panel = new JPanel();
panel.add(new JLabel("Size:"));
sizeSelector = new JTextField(" 48 ");
sizeSelector.getDocument().addDocumentListener(new DocumentListener() {
public void insertUpdate(DocumentEvent e) { update(); }
public void removeUpdate(DocumentEvent e) { update(); }
public void changedUpdate(DocumentEvent e) { }
});
panel.add(sizeSelector);
smoothBox = new JCheckBox("Smooth");
smoothBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
smooth = smoothBox.isSelected();
update();
}
});
smoothBox.setSelected(smooth);
panel.add(smoothBox);
// allBox = new JCheckBox("All Characters");
// allBox.addActionListener(new ActionListener() {
// public void actionPerformed(ActionEvent e) {
// all = allBox.isSelected();
// }
// });
// allBox.setSelected(all);
// panel.add(allBox);
charsetButton = new JButton("Characters...");
charsetButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//showCharacterList();
charSelector.setVisible(true);
}
});
panel.add(charsetButton);
pain.add(panel);
JPanel filestuff = new JPanel();
filestuff.add(new JLabel("Filename:"));
filestuff.add(filenameField = new JTextField(20));
filestuff.add(new JLabel(".vlw"));
pain.add(filestuff);
JPanel buttons = new JPanel();
JButton cancelButton = new JButton("Cancel");
cancelButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setVisible(false);
}
});
okButton = new JButton("OK");
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
build();
}
});
okButton.setEnabled(false);
buttons.add(cancelButton);
buttons.add(okButton);
pain.add(buttons);
JRootPane root = getRootPane();
root.setDefaultButton(okButton);
ActionListener disposer = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
setVisible(false);
}
};
Base.registerWindowCloseKeys(root, disposer);
Base.setIcon(this);
setResizable(false);
pack();
// do this after pack so it doesn't affect layout
sample.setFont(new Font(list[0], Font.PLAIN, 48));
fontSelector.setSelectedIndex(0);
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
windowSize = getSize();
setLocation((screen.width - windowSize.width) / 2,
(screen.height - windowSize.height) / 2);
// create this behind the scenes
charSelector = new CharacterSelector();
}
public void run() {
setVisible(true);
}
public void update() {
int fontsize = 0;
try {
fontsize = Integer.parseInt(sizeSelector.getText().trim());
//System.out.println("'" + sizeSelector.getText() + "'");
} catch (NumberFormatException e2) { }
// if a deselect occurred, selection will be -1
if ((fontsize > 0) && (fontsize < 256) && (selection != -1)) {
//font = new Font(list[selection], Font.PLAIN, fontsize);
Font instance = (Font) table.get(list[selection]);
font = instance.deriveFont(Font.PLAIN, fontsize);
//System.out.println("setting font to " + font);
sample.setFont(font);
String filenameSuggestion = list[selection].replace(' ', '_');
filenameSuggestion += "-" + fontsize;
filenameField.setText(filenameSuggestion);
}
}
public void build() {
int fontsize = 0;
try {
fontsize = Integer.parseInt(sizeSelector.getText().trim());
} catch (NumberFormatException e) { }
if (fontsize <= 0) {
JOptionPane.showMessageDialog(this, "Bad font size, try again.",
"Badness", JOptionPane.WARNING_MESSAGE);
return;
}
String filename = filenameField.getText().trim();
if (filename.length() == 0) {
JOptionPane.showMessageDialog(this, "Enter a file name for the font.",
"Lameness", JOptionPane.WARNING_MESSAGE);
return;
}
if (!filename.endsWith(".vlw")) {
filename += ".vlw";
}
// Please implement me properly. The schematic is below, but not debugged.
// http://dev.processing.org/bugs/show_bug.cgi?id=1464
// final String filename2 = filename;
// final int fontsize2 = fontsize;
// SwingUtilities.invokeLater(new Runnable() {
// public void run() {
try {
Font instance = (Font) table.get(list[selection]);
font = instance.deriveFont(Font.PLAIN, fontsize);
//PFont f = new PFont(font, smooth, all ? null : PFont.CHARSET);
PFont f = new PFont(font, smooth, charSelector.getCharacters());
// PFont f = new PFont(font, smooth, null);
// char[] charset = charSelector.getCharacters();
// ProgressMonitor progressMonitor = new ProgressMonitor(CreateFont.this,
// "Creating font", "", 0, charset.length);
// progressMonitor.setProgress(0);
// for (int i = 0; i < charset.length; i++) {
// System.out.println(charset[i]);
// f.index(charset[i]); // load this char
// progressMonitor.setProgress(i+1);
// }
// make sure the 'data' folder exists
File folder = editor.getSketch().prepareDataFolder();
f.save(new FileOutputStream(new File(folder, filename)));
} catch (IOException e) {
JOptionPane.showMessageDialog(CreateFont.this,
"An error occurred while creating font.",
"No font for you",
JOptionPane.WARNING_MESSAGE);
e.printStackTrace();
}
// }
// });
setVisible(false);
}
/**
* make the window vertically resizable
*/
public Dimension getMaximumSize() {
return new Dimension(windowSize.width, 2000);
}
public Dimension getMinimumSize() {
return windowSize;
}
/*
public void show(File targetFolder) {
this.targetFolder = targetFolder;
show();
}
*/
}
/**
* Component that draws the sample text. This is its own subclassed component
* because Mac OS X controls seem to reset the RenderingHints for smoothing
* so that they cannot be overridden properly for JLabel or JTextArea.
* @author fry
*/
class SampleComponent extends JComponent {
// see http://rinkworks.com/words/pangrams.shtml
String text =
"Forsaking monastic tradition, twelve jovial friars gave up their " +
"vocation for a questionable existence on the flying trapeze.";
int high = 80;
CreateFont parent;
public SampleComponent(CreateFont p) {
this.parent = p;
// and yet, we still need an inner class to handle the basics.
// or no, maybe i'll refactor this as a separate class!
// maybe a few getters and setters? mmm?
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
String input =
(String) JOptionPane.showInputDialog(parent,
"Enter new sample text:",
"Sample Text",
JOptionPane.PLAIN_MESSAGE,
null, // icon
null, // choices
text);
if (input != null) {
text = input;
parent.repaint();
}
}
});
}
public void paintComponent(Graphics g) {
// System.out.println("smoothing set to " + smooth);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.WHITE);
Dimension dim = getSize();
g2.fillRect(0, 0, dim.width, dim.height);
g2.setColor(Color.BLACK);
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
parent.smooth ?
RenderingHints.VALUE_TEXT_ANTIALIAS_ON :
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
// add this one as well (after 1.0.9)
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
parent.smooth ?
RenderingHints.VALUE_ANTIALIAS_ON :
RenderingHints.VALUE_ANTIALIAS_OFF);
//super.paintComponent(g2);
Font font = getFont();
int ascent = g2.getFontMetrics().getAscent();
// System.out.println(f.getName());
g2.setFont(font);
g2.drawString(text, 5, dim.height - (dim.height - ascent) / 2);
}
public Dimension getPreferredSize() {
return new Dimension(400, high);
}
public Dimension getMaximumSize() {
return new Dimension(10000, high);
}
public Dimension getMinimumSize() {
return new Dimension(100, high);
}
}
/**
* Frame for selecting which characters will be included with the font.
*/
class CharacterSelector extends JFrame {
JRadioButton defaultCharsButton;
JRadioButton allCharsButton;
JRadioButton unicodeCharsButton;
JScrollPane unicodeBlockScroller;
JList charsetList;
public CharacterSelector() {
super("Character Selector");
charsetList = new CheckBoxList();
DefaultListModel model = new DefaultListModel();
charsetList.setModel(model);
for (String item : blockNames) {
model.addElement(new JCheckBox(item));
}
unicodeBlockScroller =
new JScrollPane(charsetList,
ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
Container outer = getContentPane();
outer.setLayout(new BorderLayout());
JPanel pain = new JPanel();
pain.setBorder(new EmptyBorder(13, 13, 13, 13));
outer.add(pain, BorderLayout.CENTER);
pain.setLayout(new BoxLayout(pain, BoxLayout.Y_AXIS));
String labelText =
"Default characters will include most bitmaps for Mac OS\n" +
"and Windows Latin scripts. Including all characters may\n" +
"require large amounts of memory for all of the bitmaps.\n" +
"For greater control, you can select specific Unicode blocks.";
JTextArea textarea = new JTextArea(labelText);
textarea.setBorder(new EmptyBorder(13, 8, 13, 8));
textarea.setBackground(null);
textarea.setEditable(false);
textarea.setHighlighter(null);
textarea.setFont(new Font("Dialog", Font.PLAIN, 12));
pain.add(textarea);
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
//System.out.println("action " + unicodeCharsButton.isSelected());
//unicodeBlockScroller.setEnabled(unicodeCharsButton.isSelected());
charsetList.setEnabled(unicodeCharsButton.isSelected());
}
};
defaultCharsButton = new JRadioButton("Default Characters");
allCharsButton = new JRadioButton("All Characters");
unicodeCharsButton = new JRadioButton("Specific Unicode Blocks");
defaultCharsButton.addActionListener(listener);
allCharsButton.addActionListener(listener);
unicodeCharsButton.addActionListener(listener);
ButtonGroup group = new ButtonGroup();
group.add(defaultCharsButton);
group.add(allCharsButton);
group.add(unicodeCharsButton);
JPanel radioPanel = new JPanel();
//radioPanel.setBackground(Color.red);
radioPanel.setLayout(new BoxLayout(radioPanel, BoxLayout.Y_AXIS));
radioPanel.add(defaultCharsButton);
radioPanel.add(allCharsButton);
radioPanel.add(unicodeCharsButton);
JPanel rightStuff = new JPanel();
rightStuff.setLayout(new BoxLayout(rightStuff, BoxLayout.X_AXIS));
rightStuff.add(radioPanel);
rightStuff.add(Box.createHorizontalGlue());
pain.add(rightStuff);
pain.add(Box.createVerticalStrut(13));
// pain.add(radioPanel);
// pain.add(defaultCharsButton);
// pain.add(allCharsButton);
// pain.add(unicodeCharsButton);
defaultCharsButton.setSelected(true);
charsetList.setEnabled(false);
//frame.getContentPane().add(scroller);
pain.add(unicodeBlockScroller);
pain.add(Box.createVerticalStrut(8));
JPanel buttons = new JPanel();
JButton okButton = new JButton("OK");
okButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
setVisible(false);
}
});
okButton.setEnabled(true);
buttons.add(okButton);
pain.add(buttons);
JRootPane root = getRootPane();
root.setDefaultButton(okButton);
ActionListener disposer = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
setVisible(false);
}
};
Base.registerWindowCloseKeys(root, disposer);
Base.setIcon(this);
pack();
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
Dimension windowSize = getSize();
setLocation((screen.width - windowSize.width) / 2,
(screen.height - windowSize.height) / 2);
}
protected char[] getCharacters() {
if (defaultCharsButton.isSelected()) {
return PFont.CHARSET;
}
char[] charset = new char[65536];
if (allCharsButton.isSelected()) {
for (int i = 0; i < 0xFFFF; i++) {
charset[i] = (char) i;
}
} else {
DefaultListModel model = (DefaultListModel) charsetList.getModel();
int index = 0;
for (int i = 0; i < BLOCKS.length; i++) {
if (((JCheckBox) model.get(i)).isSelected()) {
for (int j = blockStart[i]; j <= blockStop[i]; j++) {
charset[index++] = (char) j;
}
}
}
charset = PApplet.subset(charset, 0, index);
}
//System.out.println("Creating font with " + charset.length + " characters.");
return charset;
}
// http://www.unicode.org/Public/UNIDATA/Blocks.txt
static final String[] BLOCKS = {
"0000..007F; Basic Latin",
"0080..00FF; Latin-1 Supplement",
"0100..017F; Latin Extended-A",
"0180..024F; Latin Extended-B",
"0250..02AF; IPA Extensions",
"02B0..02FF; Spacing Modifier Letters",
"0300..036F; Combining Diacritical Marks",
"0370..03FF; Greek and Coptic",
"0400..04FF; Cyrillic",
"0500..052F; Cyrillic Supplement",
"0530..058F; Armenian",
"0590..05FF; Hebrew",
"0600..06FF; Arabic",
"0700..074F; Syriac",
"0750..077F; Arabic Supplement",
"0780..07BF; Thaana",
"07C0..07FF; NKo",
"0800..083F; Samaritan",
"0900..097F; Devanagari",
"0980..09FF; Bengali",
"0A00..0A7F; Gurmukhi",
"0A80..0AFF; Gujarati",
"0B00..0B7F; Oriya",
"0B80..0BFF; Tamil",
"0C00..0C7F; Telugu",
"0C80..0CFF; Kannada",
"0D00..0D7F; Malayalam",
"0D80..0DFF; Sinhala",
"0E00..0E7F; Thai",
"0E80..0EFF; Lao",
"0F00..0FFF; Tibetan",
"1000..109F; Myanmar",
"10A0..10FF; Georgian",
"1100..11FF; Hangul Jamo",
"1200..137F; Ethiopic",
"1380..139F; Ethiopic Supplement",
"13A0..13FF; Cherokee",
"1400..167F; Unified Canadian Aboriginal Syllabics",
"1680..169F; Ogham",
"16A0..16FF; Runic",
"1700..171F; Tagalog",
"1720..173F; Hanunoo",
"1740..175F; Buhid",
"1760..177F; Tagbanwa",
"1780..17FF; Khmer",
"1800..18AF; Mongolian",
"18B0..18FF; Unified Canadian Aboriginal Syllabics Extended",
"1900..194F; Limbu",
"1950..197F; Tai Le",
"1980..19DF; New Tai Lue",
"19E0..19FF; Khmer Symbols",
"1A00..1A1F; Buginese",
"1A20..1AAF; Tai Tham",
"1B00..1B7F; Balinese",
"1B80..1BBF; Sundanese",
"1C00..1C4F; Lepcha",
"1C50..1C7F; Ol Chiki",
"1CD0..1CFF; Vedic Extensions",
"1D00..1D7F; Phonetic Extensions",
"1D80..1DBF; Phonetic Extensions Supplement",
"1DC0..1DFF; Combining Diacritical Marks Supplement",
"1E00..1EFF; Latin Extended Additional",
"1F00..1FFF; Greek Extended",
"2000..206F; General Punctuation",
"2070..209F; Superscripts and Subscripts",
"20A0..20CF; Currency Symbols",
"20D0..20FF; Combining Diacritical Marks for Symbols",
"2100..214F; Letterlike Symbols",
"2150..218F; Number Forms",
"2190..21FF; Arrows",
"2200..22FF; Mathematical Operators",
"2300..23FF; Miscellaneous Technical",
"2400..243F; Control Pictures",
"2440..245F; Optical Character Recognition",
"2460..24FF; Enclosed Alphanumerics",
"2500..257F; Box Drawing",
"2580..259F; Block Elements",
"25A0..25FF; Geometric Shapes",
"2600..26FF; Miscellaneous Symbols",
"2700..27BF; Dingbats",
"27C0..27EF; Miscellaneous Mathematical Symbols-A",
"27F0..27FF; Supplemental Arrows-A",
"2800..28FF; Braille Patterns",
"2900..297F; Supplemental Arrows-B",
"2980..29FF; Miscellaneous Mathematical Symbols-B",
"2A00..2AFF; Supplemental Mathematical Operators",
"2B00..2BFF; Miscellaneous Symbols and Arrows",
"2C00..2C5F; Glagolitic",
"2C60..2C7F; Latin Extended-C",
"2C80..2CFF; Coptic",
"2D00..2D2F; Georgian Supplement",
"2D30..2D7F; Tifinagh",
"2D80..2DDF; Ethiopic Extended",
"2DE0..2DFF; Cyrillic Extended-A",
"2E00..2E7F; Supplemental Punctuation",
"2E80..2EFF; CJK Radicals Supplement",
"2F00..2FDF; Kangxi Radicals",
"2FF0..2FFF; Ideographic Description Characters",
"3000..303F; CJK Symbols and Punctuation",
"3040..309F; Hiragana",
"30A0..30FF; Katakana",
"3100..312F; Bopomofo",
"3130..318F; Hangul Compatibility Jamo",
"3190..319F; Kanbun",
"31A0..31BF; Bopomofo Extended",
"31C0..31EF; CJK Strokes",
"31F0..31FF; Katakana Phonetic Extensions",
"3200..32FF; Enclosed CJK Letters and Months",
"3300..33FF; CJK Compatibility",
"3400..4DBF; CJK Unified Ideographs Extension A",
"4DC0..4DFF; Yijing Hexagram Symbols",
"4E00..9FFF; CJK Unified Ideographs",
"A000..A48F; Yi Syllables",
"A490..A4CF; Yi Radicals",
"A4D0..A4FF; Lisu",
"A500..A63F; Vai",
"A640..A69F; Cyrillic Extended-B",
"A6A0..A6FF; Bamum",
"A700..A71F; Modifier Tone Letters",
"A720..A7FF; Latin Extended-D",
"A800..A82F; Syloti Nagri",
"A830..A83F; Common Indic Number Forms",
"A840..A87F; Phags-pa",
"A880..A8DF; Saurashtra",
"A8E0..A8FF; Devanagari Extended",
"A900..A92F; Kayah Li",
"A930..A95F; Rejang",
"A960..A97F; Hangul Jamo Extended-A",
"A980..A9DF; Javanese",
"AA00..AA5F; Cham",
"AA60..AA7F; Myanmar Extended-A",
"AA80..AADF; Tai Viet",
"ABC0..ABFF; Meetei Mayek",
"AC00..D7AF; Hangul Syllables",
"D7B0..D7FF; Hangul Jamo Extended-B",
"D800..DB7F; High Surrogates",
"DB80..DBFF; High Private Use Surrogates",
"DC00..DFFF; Low Surrogates",
"E000..F8FF; Private Use Area",
"F900..FAFF; CJK Compatibility Ideographs",
"FB00..FB4F; Alphabetic Presentation Forms",
"FB50..FDFF; Arabic Presentation Forms-A",
"FE00..FE0F; Variation Selectors",
"FE10..FE1F; Vertical Forms",
"FE20..FE2F; Combining Half Marks",
"FE30..FE4F; CJK Compatibility Forms",
"FE50..FE6F; Small Form Variants",
"FE70..FEFF; Arabic Presentation Forms-B",
"FF00..FFEF; Halfwidth and Fullwidth Forms",
"FFF0..FFFF; Specials"
};
static String[] blockNames;
static int[] blockStart;
static int[] blockStop;
static {
int count = BLOCKS.length;
blockNames = new String[count];
blockStart = new int[count];
blockStop = new int[count];
for (int i = 0; i < count; i++) {
String line = BLOCKS[i];
blockStart[i] = PApplet.unhex(line.substring(0, 4));
blockStop[i] = PApplet.unhex(line.substring(6, 10));
blockNames[i] = line.substring(12);
}
// PApplet.println(codePointStop);
// PApplet.println(codePoints);
}
}
// Code for this CheckBoxList class found on the net, though I've lost the
// link. If you run across the original version, please let me know so that
// the original author can be credited properly. It was from a snippet
// collection, but it seems to have been picked up so many places with others
// placing their copyright on it, that I haven't been able to determine the
// original author. [fry 20100216]
class CheckBoxList extends JList {
protected static Border noFocusBorder = new EmptyBorder(1, 1, 1, 1);
public CheckBoxList() {
setCellRenderer(new CellRenderer());
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
if (isEnabled()) {
int index = locationToIndex(e.getPoint());
if (index != -1) {
JCheckBox checkbox = (JCheckBox)
getModel().getElementAt(index);
checkbox.setSelected(!checkbox.isSelected());
repaint();
}
}
}
});
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
protected class CellRenderer implements ListCellRenderer {
public Component getListCellRendererComponent(JList list, Object value,
int index, boolean isSelected,
boolean cellHasFocus) {
JCheckBox checkbox = (JCheckBox) value;
checkbox.setBackground(isSelected ? getSelectionBackground() : getBackground());
checkbox.setForeground(isSelected ? getSelectionForeground() : getForeground());
//checkbox.setEnabled(isEnabled());
checkbox.setEnabled(list.isEnabled());
checkbox.setFont(getFont());
checkbox.setFocusPainted(false);
checkbox.setBorderPainted(true);
checkbox.setBorder(isSelected ? UIManager.getBorder("List.focusCellHighlightBorder") : noFocusBorder);
return checkbox;
}
}
}