1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-06-17 22:23:10 +03:00

Initial sync with Processing 6406. Compiles and runs (on Mac OS X) but probably very buggy.

This commit is contained in:
David A. Mellis
2010-04-21 01:58:57 +00:00
parent d36fbfe1cf
commit 34579ae440
57 changed files with 22913 additions and 2218 deletions

View File

@ -3,7 +3,7 @@
/* /*
Part of the Processing project - http://processing.org Part of the Processing project - http://processing.org
Copyright (c) 2004-09 Ben Fry and Casey Reas Copyright (c) 2004-10 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology Copyright (c) 2001-04 Massachusetts Institute of Technology
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@ -42,7 +42,10 @@ import processing.core.*;
*/ */
public class Base { public class Base {
public static final int REVISION = 18; public static final int REVISION = 18;
/** This might be replaced by main() if there's a lib/version.txt file. */
static String VERSION_NAME = "0018"; static String VERSION_NAME = "0018";
/** Set true if this a proper release rather than a numbered revision. */
static public boolean RELEASE = false;
static HashMap<Integer, String> platformNames = new HashMap<Integer, String>(); static HashMap<Integer, String> platformNames = new HashMap<Integer, String>();
static { static {
@ -101,31 +104,16 @@ public class Base {
// ArrayList editors = Collections.synchronizedList(new ArrayList<Editor>()); // ArrayList editors = Collections.synchronizedList(new ArrayList<Editor>());
Editor activeEditor; Editor activeEditor;
// int nextEditorX;
// int nextEditorY;
// import com.sun.jna.Library;
// import com.sun.jna.Native;
// public interface CLibrary extends Library {
// CLibrary INSTANCE = (CLibrary)Native.loadLibrary("c", CLibrary.class);
// int setenv(String name, String value, int overwrite);
// String getenv(String name);
// int unsetenv(String name);
// int putenv(String string);
// }
static public void main(String args[]) { static public void main(String args[]) {
// /Users/fry/coconut/sketchbook/libraries/gsvideo/library
// CLibrary clib = CLibrary.INSTANCE;
// clib.setenv("DYLD_LIBRARY_PATH", "/Users/fry/coconut/sketchbook/libraries/gsvideo/library", 1);
// System.out.println("env is now " + clib.getenv("DYLD_LIBRARY_PATH"));
try { try {
File versionFile = getContentFile("lib/version.txt"); File versionFile = getContentFile("lib/version.txt");
if (versionFile.exists()) { if (versionFile.exists()) {
VERSION_NAME = PApplet.loadStrings(versionFile)[0]; String version = PApplet.loadStrings(versionFile)[0];
if (!version.equals(VERSION_NAME)) {
VERSION_NAME = version;
RELEASE = true;
}
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
@ -187,10 +175,12 @@ public class Base {
try { try {
platform.setLookAndFeel(); platform.setLookAndFeel();
} catch (Exception e) { } catch (Exception e) {
String mess = e.getMessage();
if (mess.indexOf("ch.randelshofer.quaqua.QuaquaLookAndFeel") == -1) {
System.err.println("Non-fatal error while setting the Look & Feel."); System.err.println("Non-fatal error while setting the Look & Feel.");
System.err.println("The error message follows, however Arduino should run fine."); System.err.println("The error message follows, however Arduino should run fine.");
System.err.println(e.getMessage()); System.err.println(mess);
//e.printStackTrace(); }
} }
// Create a location for untitled sketches // Create a location for untitled sketches
@ -213,7 +203,7 @@ public class Base {
static protected void initPlatform() { static protected void initPlatform() {
try { try {
Class platformClass = Class.forName("processing.app.Platform"); Class<?> platformClass = Class.forName("processing.app.Platform");
if (Base.isMacOS()) { if (Base.isMacOS()) {
platformClass = Class.forName("processing.app.macosx.Platform"); platformClass = Class.forName("processing.app.macosx.Platform");
} else if (Base.isWindows()) { } else if (Base.isWindows()) {
@ -270,7 +260,7 @@ public class Base {
} }
} }
// If not path is set, get the default sketchbook folder for this platform // If no path is set, get the default sketchbook folder for this platform
if (sketchbookPath == null) { if (sketchbookPath == null) {
File defaultFolder = getDefaultSketchbookFolder(); File defaultFolder = getDefaultSketchbookFolder();
Preferences.set("sketchbook.path", defaultFolder.getAbsolutePath()); Preferences.set("sketchbook.path", defaultFolder.getAbsolutePath());
@ -456,8 +446,8 @@ public class Base {
protected int[] nextEditorLocation() { protected int[] nextEditorLocation() {
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize(); Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
int defaultWidth = Preferences.getInteger("default.window.width"); int defaultWidth = Preferences.getInteger("editor.window.width.default");
int defaultHeight = Preferences.getInteger("default.window.height"); int defaultHeight = Preferences.getInteger("editor.window.height.default");
if (activeEditor == null) { if (activeEditor == null) {
// If no current active editor, use default placement // If no current active editor, use default placement
@ -584,7 +574,7 @@ public class Base {
* Replace the sketch in the current window with a new untitled document. * Replace the sketch in the current window with a new untitled document.
*/ */
public void handleNewReplace() { public void handleNewReplace() {
if (!activeEditor.checkModified(true)) { if (!activeEditor.checkModified()) {
return; // sketch was modified, and user canceled return; // sketch was modified, and user canceled
} }
// Close the running window, avoid window boogers with multiple sketches // Close the running window, avoid window boogers with multiple sketches
@ -616,7 +606,7 @@ public class Base {
* @param path Location of the primary pde file for the sketch. * @param path Location of the primary pde file for the sketch.
*/ */
public void handleOpenReplace(String path) { public void handleOpenReplace(String path) {
if (!activeEditor.checkModified(true)) { if (!activeEditor.checkModified()) {
return; // sketch was modified, and user canceled return; // sketch was modified, and user canceled
} }
// Close the running window, avoid window boogers with multiple sketches // Close the running window, avoid window boogers with multiple sketches
@ -758,8 +748,8 @@ public class Base {
*/ */
public boolean handleClose(Editor editor) { public boolean handleClose(Editor editor) {
// Check if modified // Check if modified
boolean immediate = editors.size() == 1; // boolean immediate = editors.size() == 1;
if (!editor.checkModified(immediate)) { if (!editor.checkModified()) {
return false; return false;
} }
@ -862,7 +852,7 @@ public class Base {
protected boolean handleQuitEach() { protected boolean handleQuitEach() {
int index = 0; int index = 0;
for (Editor editor : editors) { for (Editor editor : editors) {
if (editor.checkModified(true)) { if (editor.checkModified()) {
// Update to the new/final sketch path for this fella // Update to the new/final sketch path for this fella
storeSketchPath(editor, index); storeSketchPath(editor, index);
index++; index++;
@ -914,7 +904,8 @@ public class Base {
// Add a list of all sketches and subfolders // Add a list of all sketches and subfolders
try { try {
boolean sketches = addSketches(menu, getSketchbookFolder(), true); //boolean sketches = addSketches(menu, getSketchbookFolder(), true);
boolean sketches = addSketches(menu, getSketchbookFolder());
if (sketches) menu.addSeparator(); if (sketches) menu.addSeparator();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
@ -923,11 +914,11 @@ public class Base {
//System.out.println("rebuilding examples menu"); //System.out.println("rebuilding examples menu");
// Add each of the subfolders of examples directly to the menu // Add each of the subfolders of examples directly to the menu
try { try {
boolean found = addSketches(menu, examplesFolder, true); boolean found = addSketches(menu, examplesFolder);
if (found) menu.addSeparator(); if (found) menu.addSeparator();
found = addSketches(menu, getSketchbookLibrariesFolder(), true); found = addSketches(menu, getSketchbookLibrariesFolder());
if (found) menu.addSeparator(); if (found) menu.addSeparator();
addSketches(menu, librariesFolder, true); addSketches(menu, librariesFolder);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -939,7 +930,8 @@ public class Base {
//new Exception().printStackTrace(); //new Exception().printStackTrace();
try { try {
menu.removeAll(); menu.removeAll();
addSketches(menu, getSketchbookFolder(), false); //addSketches(menu, getSketchbookFolder(), false);
addSketches(menu, getSketchbookFolder());
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -983,11 +975,11 @@ public class Base {
//System.out.println("rebuilding examples menu"); //System.out.println("rebuilding examples menu");
try { try {
menu.removeAll(); menu.removeAll();
boolean found = addSketches(menu, examplesFolder, false); boolean found = addSketches(menu, examplesFolder);
if (found) menu.addSeparator(); if (found) menu.addSeparator();
found = addSketches(menu, getSketchbookLibrariesFolder(), false); found = addSketches(menu, getSketchbookLibrariesFolder());
if (found) menu.addSeparator(); if (found) menu.addSeparator();
addSketches(menu, librariesFolder, false); addSketches(menu, librariesFolder);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -1050,8 +1042,7 @@ public class Base {
* should replace the sketch in the current window, or false when the * should replace the sketch in the current window, or false when the
* sketch should open in a new window. * sketch should open in a new window.
*/ */
protected boolean addSketches(JMenu menu, File folder, protected boolean addSketches(JMenu menu, File folder) throws IOException {
final boolean openReplaces) throws IOException {
// skip .DS_Store files, etc (this shouldn't actually be necessary) // skip .DS_Store files, etc (this shouldn't actually be necessary)
if (!folder.isDirectory()) return false; if (!folder.isDirectory()) return false;
@ -1068,7 +1059,8 @@ public class Base {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
String path = e.getActionCommand(); String path = e.getActionCommand();
if (new File(path).exists()) { if (new File(path).exists()) {
if (openReplaces) { // if (openReplaces) {
if ((e.getModifiers() & ActionEvent.SHIFT_MASK) == 0) {
handleOpenReplace(path); handleOpenReplace(path);
} else { } else {
handleOpen(path); handleOpen(path);
@ -1121,14 +1113,15 @@ public class Base {
} else { } else {
// don't create an extra menu level for a folder named "examples" // don't create an extra menu level for a folder named "examples"
if (subfolder.getName().equals("examples")) { if (subfolder.getName().equals("examples")) {
boolean found = addSketches(menu, subfolder, openReplaces); //, false); boolean found = addSketches(menu, subfolder);
if (found) ifound = true; if (found) ifound = true;
} else { } else {
// not a sketch folder, but maybe a subfolder containing sketches // not a sketch folder, but maybe a subfolder containing sketches
JMenu submenu = new JMenu(list[i]); JMenu submenu = new JMenu(list[i]);
// needs to be separate var // needs to be separate var
// otherwise would set ifound to false // otherwise would set ifound to false
boolean found = addSketches(submenu, subfolder, openReplaces); //, false); //boolean found = addSketches(submenu, subfolder, openReplaces); //, false);
boolean found = addSketches(submenu, subfolder); //, false);
if (found) { if (found) {
menu.add(submenu); menu.add(submenu);
ifound = true; ifound = true;
@ -1319,6 +1312,11 @@ public class Base {
// } // }
static public Platform getPlatform() {
return platform;
}
static public String getPlatformName() { static public String getPlatformName() {
String osname = System.getProperty("os.name"); String osname = System.getProperty("os.name");
@ -1714,12 +1712,11 @@ public class Base {
} }
*/ */
/** /**
* Registers key events for a Ctrl-W and ESC with an ActionListener * Registers key events for a Ctrl-W and ESC with an ActionListener
* that will take care of disposing the window. * that will take care of disposing the window.
*/ */
static public void registerWindowCloseKeys(JRootPane root, //Window window, static public void registerWindowCloseKeys(JRootPane root,
ActionListener disposer) { ActionListener disposer) {
KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0); KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
root.registerKeyboardAction(disposer, stroke, root.registerKeyboardAction(disposer, stroke,
@ -1836,6 +1833,129 @@ public class Base {
// ................................................................... // ...................................................................
// incomplete
static public int showYesNoCancelQuestion(Editor editor, String title,
String primary, String secondary) {
if (!Base.isMacOS()) {
int result =
JOptionPane.showConfirmDialog(null, primary + "\n" + secondary, title,
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE);
return result;
// if (result == JOptionPane.YES_OPTION) {
//
// } else if (result == JOptionPane.NO_OPTION) {
// return true; // ok to continue
//
// } else if (result == JOptionPane.CANCEL_OPTION) {
// return false;
//
// } else {
// throw new IllegalStateException();
// }
} else {
// Pane formatting adapted from the Quaqua guide
// http://www.randelshofer.ch/quaqua/guide/joptionpane.html
JOptionPane pane =
new JOptionPane("<html> " +
"<head> <style type=\"text/css\">"+
"b { font: 13pt \"Lucida Grande\" }"+
"p { font: 11pt \"Lucida Grande\"; margin-top: 8px }"+
"</style> </head>" +
"<b>Do you want to save changes to this sketch<BR>" +
" before closing?</b>" +
"<p>If you don't save, your changes will be lost.",
JOptionPane.QUESTION_MESSAGE);
String[] options = new String[] {
"Save", "Cancel", "Don't Save"
};
pane.setOptions(options);
// highlight the safest option ala apple hig
pane.setInitialValue(options[0]);
// on macosx, setting the destructive property places this option
// away from the others at the lefthand side
pane.putClientProperty("Quaqua.OptionPane.destructiveOption",
new Integer(2));
JDialog dialog = pane.createDialog(editor, null);
dialog.setVisible(true);
Object result = pane.getValue();
if (result == options[0]) {
return JOptionPane.YES_OPTION;
} else if (result == options[1]) {
return JOptionPane.CANCEL_OPTION;
} else if (result == options[2]) {
return JOptionPane.NO_OPTION;
} else {
return JOptionPane.CLOSED_OPTION;
}
}
}
//if (result == JOptionPane.YES_OPTION) {
//
// } else if (result == JOptionPane.NO_OPTION) {
// return true; // ok to continue
//
// } else if (result == JOptionPane.CANCEL_OPTION) {
// return false;
//
// } else {
// throw new IllegalStateException();
// }
static public int showYesNoQuestion(Frame editor, String title,
String primary, String secondary) {
if (!Base.isMacOS()) {
return JOptionPane.showConfirmDialog(editor,
"<html><body>" +
"<b>" + primary + "</b>" +
"<br>" + secondary, title,
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE);
} else {
// Pane formatting adapted from the Quaqua guide
// http://www.randelshofer.ch/quaqua/guide/joptionpane.html
JOptionPane pane =
new JOptionPane("<html> " +
"<head> <style type=\"text/css\">"+
"b { font: 13pt \"Lucida Grande\" }"+
"p { font: 11pt \"Lucida Grande\"; margin-top: 8px }"+
"</style> </head>" +
"<b>" + primary + "</b>" +
"<p>" + secondary + "</p>",
JOptionPane.QUESTION_MESSAGE);
String[] options = new String[] {
"Yes", "No"
};
pane.setOptions(options);
// highlight the safest option ala apple hig
pane.setInitialValue(options[0]);
JDialog dialog = pane.createDialog(editor, null);
dialog.setVisible(true);
Object result = pane.getValue();
if (result == options[0]) {
return JOptionPane.YES_OPTION;
} else if (result == options[1]) {
return JOptionPane.NO_OPTION;
} else {
return JOptionPane.CLOSED_OPTION;
}
}
}
/** /**
* Retrieve a path to something in the Processing folder. Eventually this * Retrieve a path to something in the Processing folder. Eventually this
* may refer to the Contents subfolder of Processing.app, if we bundle things * may refer to the Contents subfolder of Processing.app, if we bundle things
@ -1959,6 +2079,36 @@ public class Base {
} }
/**
* Read from a file with a bunch of attribute/value pairs
* that are separated by = and ignore comments with #.
*/
static public HashMap<String,String> readSettings(File inputFile) {
HashMap<String,String> outgoing = new HashMap<String,String>();
if (!inputFile.exists()) return outgoing; // return empty hash
String lines[] = PApplet.loadStrings(inputFile);
for (int i = 0; i < lines.length; i++) {
int hash = lines[i].indexOf('#');
String line = (hash == -1) ?
lines[i].trim() : lines[i].substring(0, hash).trim();
if (line.length() == 0) continue;
int equals = line.indexOf('=');
if (equals == -1) {
System.err.println("ignoring illegal line in " + inputFile);
System.err.println(" " + line);
continue;
}
String attr = line.substring(0, equals).trim();
String valu = line.substring(equals + 1).trim();
outgoing.put(attr, valu);
}
return outgoing;
}
static public void copyFile(File sourceFile, static public void copyFile(File sourceFile,
File targetFile) throws IOException { File targetFile) throws IOException {
InputStream from = InputStream from =
@ -2116,7 +2266,7 @@ public class Base {
static public String[] listFiles(File folder, boolean relative) { static public String[] listFiles(File folder, boolean relative) {
String path = folder.getAbsolutePath(); String path = folder.getAbsolutePath();
Vector vector = new Vector(); Vector<String> vector = new Vector<String>();
listFiles(relative ? (path + File.separator) : "", path, vector); listFiles(relative ? (path + File.separator) : "", path, vector);
String outgoing[] = new String[vector.size()]; String outgoing[] = new String[vector.size()];
vector.copyInto(outgoing); vector.copyInto(outgoing);
@ -2125,7 +2275,7 @@ public class Base {
static protected void listFiles(String basePath, static protected void listFiles(String basePath,
String path, Vector vector) { String path, Vector<String> vector) {
File folder = new File(path); File folder = new File(path);
String list[] = folder.list(); String list[] = folder.list();
if (list == null) return; if (list == null) return;

View File

@ -43,7 +43,6 @@ import javax.swing.undo.*;
import gnu.io.*; import gnu.io.*;
/** /**
* Main editor panel for the Processing Development Environment. * Main editor panel for the Processing Development Environment.
*/ */
@ -114,7 +113,6 @@ public class Editor extends JFrame implements RunnerListener {
EditorLineStatus lineStatus; EditorLineStatus lineStatus;
boolean newEditor = true;
JEditorPane editorPane; JEditorPane editorPane;
JEditTextArea textarea; JEditTextArea textarea;
@ -122,14 +120,14 @@ public class Editor extends JFrame implements RunnerListener {
// runtime information and window placement // runtime information and window placement
Point sketchWindowLocation; Point sketchWindowLocation;
Runner runtime; //Runner runtime;
JMenuItem exportAppItem; JMenuItem exportAppItem;
JMenuItem saveMenuItem; JMenuItem saveMenuItem;
JMenuItem saveAsMenuItem; JMenuItem saveAsMenuItem;
boolean running; boolean running;
boolean presenting; //boolean presenting;
boolean uploading; boolean uploading;
// undo fellers // undo fellers
@ -142,6 +140,12 @@ public class Editor extends JFrame implements RunnerListener {
FindReplace find; FindReplace find;
Runnable runHandler;
Runnable presentHandler;
Runnable stopHandler;
Runnable exportHandler;
Runnable exportAppHandler;
public Editor(Base ibase, String path, int[] location) { public Editor(Base ibase, String path, int[] location) {
super("Arduino"); super("Arduino");
@ -149,6 +153,9 @@ public class Editor extends JFrame implements RunnerListener {
//Base.setIcon(this); //Base.setIcon(this);
// Install default actions for Run, Present, etc.
resetHandlers();
// add listener to handle window close box hit event // add listener to handle window close box hit event
addWindowListener(new WindowAdapter() { addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) { public void windowClosing(WindowEvent e) {
@ -232,22 +239,7 @@ public class Editor extends JFrame implements RunnerListener {
lineStatus = new EditorLineStatus(textarea); lineStatus = new EditorLineStatus(textarea);
consolePanel.add(lineStatus, BorderLayout.SOUTH); consolePanel.add(lineStatus, BorderLayout.SOUTH);
// if (newEditor) {
// try {
// setupEditorPane();
// upper.add(editorPane);
// } catch (Exception e1) {
// PrintWriter w = PApplet.createWriter(new File("/Users/fry/Desktop/blah.txt"));
// w.println(e1.getMessage());
// e1.printStackTrace(w);
// w.flush();
// w.close();
//// e1.printStackTrace());
//// e1.printStackTrace(System.out);
// }
// } else {
upper.add(textarea); upper.add(textarea);
// }
splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
upper, consolePanel); upper, consolePanel);
@ -276,12 +268,64 @@ public class Editor extends JFrame implements RunnerListener {
listener = new EditorListener(this, textarea); listener = new EditorListener(this, textarea);
pain.add(box); pain.add(box);
pain.setTransferHandler(new TransferHandler() { // get shift down/up events so we can show the alt version of toolbar buttons
textarea.addKeyListener(toolbar);
pain.setTransferHandler(new FileDropHandler());
// System.out.println("t1");
// Finish preparing Editor (formerly found in Base)
pack();
// System.out.println("t2");
// Set the window bounds and the divider location before setting it visible
setPlacement(location);
// If the window is resized too small this will resize it again to the
// minimums. Adapted by Chris Lonnen from comments here:
// http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4320050
// as a fix for http://dev.processing.org/bugs/show_bug.cgi?id=25
final int minW = Preferences.getInteger("editor.window.width.min");
final int minH = Preferences.getInteger("editor.window.height.min");
addComponentListener(new java.awt.event.ComponentAdapter() {
public void componentResized(ComponentEvent event) {
setSize((getWidth() < minW) ? minW : getWidth(),
(getHeight() < minH) ? minH : getHeight());
}
});
// System.out.println("t3");
// Bring back the general options for the editor
applyPreferences();
// System.out.println("t4");
// Open the document that was passed in
boolean loaded = handleOpenInternal(path);
if (!loaded) sketch = null;
// System.out.println("t5");
// All set, now show the window
//setVisible(true);
}
/**
* Handles files dragged & dropped from the desktop and into the editor
* window. Dragging files into the editor window is the same as using
* "Sketch &rarr; Add File" for each file.
*/
class FileDropHandler extends TransferHandler {
public boolean canImport(JComponent dest, DataFlavor[] flavors) { public boolean canImport(JComponent dest, DataFlavor[] flavors) {
return true; return true;
} }
@SuppressWarnings("unchecked")
public boolean importData(JComponent src, Transferable transferable) { public boolean importData(JComponent src, Transferable transferable) {
int successful = 0; int successful = 0;
@ -299,10 +343,10 @@ public class Editor extends JFrame implements RunnerListener {
} }
} }
} else if (transferable.isDataFlavorSupported(uriListFlavor)) { } else if (transferable.isDataFlavorSupported(uriListFlavor)) {
//System.out.println("uri list"); // Some platforms (Mac OS X and Linux, when this began) preferred
// this method of moving files.
String data = (String)transferable.getTransferData(uriListFlavor); String data = (String)transferable.getTransferData(uriListFlavor);
String[] pieces = PApplet.splitTokens(data, "\r\n"); String[] pieces = PApplet.splitTokens(data, "\r\n");
//PApplet.println(pieces);
for (int i = 0; i < pieces.length; i++) { for (int i = 0; i < pieces.length; i++) {
if (pieces[i].startsWith("#")) continue; if (pieces[i].startsWith("#")) continue;
@ -333,76 +377,9 @@ public class Editor extends JFrame implements RunnerListener {
} }
return true; return true;
} }
});
// System.out.println("t1");
// Finish preparing Editor (formerly found in Base)
pack();
// System.out.println("t2");
// Set the window bounds and the divider location before setting it visible
setPlacement(location);
// System.out.println("t3");
// Bring back the general options for the editor
applyPreferences();
// System.out.println("t4");
// Open the document that was passed in
boolean loaded = handleOpenInternal(path);
if (!loaded) sketch = null;
// System.out.println("t5");
// All set, now show the window
//setVisible(true);
} }
/*
// http://wiki.netbeans.org/DevFaqEditorCodeCompletionAnyJEditorPane
void setupEditorPane() throws IOException {
editorPane = new JEditorPane();
// This will find the Java editor kit and associate it with
// our editor pane. But that does not give us code completion
// just yet because we have no Java context (i.e. no class path, etc.).
// However, this does give us syntax coloring.
EditorKit kit = CloneableEditorSupport.getEditorKit("text/x-java");
editorPane.setEditorKit(kit);
// You can specify any ".java" file.
// If the file does not exist, it will be created.
// The contents of the file does not matter.
// The extension must be ".java", however.
// String newSourcePath = "/Users/fry/Desktop/tmp.java";
// File tmpFile = new File(newSourcePath);
// System.out.println(tmpFile.getParent() + " " + tmpFile.getName());
// FileObject fob = FileUtil.createData(tmpFile);
File tmpFile = File.createTempFile("temp", ".java");
FileObject fob = FileUtil.toFileObject(FileUtil.normalizeFile(tmpFile));
DataObject dob = DataObject.find(fob);
editorPane.getDocument().putProperty(Document.StreamDescriptionProperty, dob);
// This sets up a default class path for us so that
// we can find all the JDK classes via code completion.
DialogBinding.bindComponentToFile(fob, 0, 0, editorPane);
// Last but not least, we need to fill the editor pane with
// some initial dummy code - as it seems somehow required to
// kick-start code completion.
// A simple dummy package declaration will do.
editorPane.setText("package dummy;");
}
*/
protected void setPlacement(int[] location) { protected void setPlacement(int[] location) {
setBounds(location[0], location[1], location[2], location[3]); setBounds(location[0], location[1], location[2], location[3]);
if (location[4] != 0) { if (location[4] != 0) {
@ -434,10 +411,10 @@ public class Editor extends JFrame implements RunnerListener {
* This appears to only be required on OS X 10.2, and is not * This appears to only be required on OS X 10.2, and is not
* even being called on later versions of OS X or Windows. * even being called on later versions of OS X or Windows.
*/ */
public Dimension getMinimumSize() { // public Dimension getMinimumSize() {
//System.out.println("getting minimum size"); // //System.out.println("getting minimum size");
return new Dimension(500, 550); // return new Dimension(500, 550);
} // }
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
@ -737,7 +714,7 @@ public class Editor extends JFrame implements RunnerListener {
protected void addTools(JMenu menu, File sourceFolder) { protected void addTools(JMenu menu, File sourceFolder) {
HashMap toolItems = new HashMap(); HashMap<String, JMenuItem> toolItems = new HashMap<String, JMenuItem>();
File[] folders = sourceFolder.listFiles(new FileFilter() { File[] folders = sourceFolder.listFiles(new FileFilter() {
public boolean accept(File folder) { public boolean accept(File folder) {
@ -807,7 +784,7 @@ public class Editor extends JFrame implements RunnerListener {
// If no class name found, just move on. // If no class name found, just move on.
if (className == null) continue; if (className == null) continue;
Class toolClass = Class.forName(className, true, loader); Class<?> toolClass = Class.forName(className, true, loader);
final Tool tool = (Tool) toolClass.newInstance(); final Tool tool = (Tool) toolClass.newInstance();
tool.init(Editor.this); tool.init(Editor.this);
@ -817,6 +794,7 @@ public class Editor extends JFrame implements RunnerListener {
item.addActionListener(new ActionListener() { item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(tool); SwingUtilities.invokeLater(tool);
//new Thread(tool).start();
} }
}); });
//menu.add(item); //menu.add(item);
@ -826,7 +804,7 @@ public class Editor extends JFrame implements RunnerListener {
e.printStackTrace(); e.printStackTrace();
} }
} }
ArrayList<String> toolList = new ArrayList(toolItems.keySet()); ArrayList<String> toolList = new ArrayList<String>(toolItems.keySet());
if (toolList.size() == 0) return; if (toolList.size() == 0) return;
menu.addSeparator(); menu.addSeparator();
@ -843,7 +821,7 @@ public class Editor extends JFrame implements RunnerListener {
try { try {
ZipFile zipFile = new ZipFile(file); ZipFile zipFile = new ZipFile(file);
Enumeration entries = zipFile.entries(); Enumeration<?> entries = zipFile.entries();
while (entries.hasMoreElements()) { while (entries.hasMoreElements()) {
ZipEntry entry = (ZipEntry) entries.nextElement(); ZipEntry entry = (ZipEntry) entries.nextElement();
@ -869,7 +847,7 @@ public class Editor extends JFrame implements RunnerListener {
protected JMenuItem createToolMenuItem(String className) { protected JMenuItem createToolMenuItem(String className) {
try { try {
Class toolClass = Class.forName(className); Class<?> toolClass = Class.forName(className);
final Tool tool = (Tool) toolClass.newInstance(); final Tool tool = (Tool) toolClass.newInstance();
JMenuItem item = new JMenuItem(tool.getMenuTitle()); JMenuItem item = new JMenuItem(tool.getMenuTitle());
@ -903,12 +881,14 @@ public class Editor extends JFrame implements RunnerListener {
menu.add(createToolMenuItem("processing.app.tools.Archiver")); menu.add(createToolMenuItem("processing.app.tools.Archiver"));
menu.add(createToolMenuItem("processing.app.tools.FixEncoding")); menu.add(createToolMenuItem("processing.app.tools.FixEncoding"));
/* // // These are temporary entries while Android mode is being worked out.
//menu.add(createToolMenuItem("processing.app.tools.android.Build")); // // The mode will not be in the tools menu, and won't involve a cmd-key
item = createToolMenuItem("processing.app.tools.android.Build"); // if (!Base.RELEASE) {
item.setAccelerator(KeyStroke.getKeyStroke('D', modifiers)); // item = createToolMenuItem("processing.app.tools.android.AndroidTool");
menu.add(item); // item.setAccelerator(KeyStroke.getKeyStroke('D', modifiers));
*/ // menu.add(item);
// menu.add(createToolMenuItem("processing.app.tools.android.Reset"));
// }
return menu; return menu;
} }
@ -1363,6 +1343,35 @@ public class Editor extends JFrame implements RunnerListener {
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
// these will be done in a more generic way soon, more like:
// setHandler("action name", Runnable);
// but for the time being, working out the kinks of how many things to
// abstract from the editor in this fashion.
public void setHandlers(Runnable runHandler, Runnable presentHandler,
Runnable stopHandler,
Runnable exportHandler, Runnable exportAppHandler) {
this.runHandler = runHandler;
this.presentHandler = presentHandler;
this.stopHandler = stopHandler;
this.exportHandler = exportHandler;
this.exportAppHandler = exportAppHandler;
}
public void resetHandlers() {
runHandler = new DefaultRunHandler();
presentHandler = new DefaultPresentHandler();
stopHandler = new DefaultStopHandler();
exportHandler = new DefaultExportHandler();
exportAppHandler = new DefaultExportAppHandler();
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
/** /**
* Gets the current sketch object. * Gets the current sketch object.
*/ */
@ -1799,26 +1808,50 @@ public class Editor extends JFrame implements RunnerListener {
console.clear(); console.clear();
} }
//presenting = present; // Cannot use invokeLater() here, otherwise it gets
// placed on the event thread and causes a hang--bad idea all around.
new Thread(verbose ? presentHandler : runHandler).start();
}
SwingUtilities.invokeLater(new Runnable() { // DAM: in Arduino, this is compile
class DefaultRunHandler implements Runnable {
public void run() { public void run() {
try { try {
sketch.compile(verbose); sketch.prepare();
String appletClassName = sketch.build(false);
statusNotice("Done compiling."); statusNotice("Done compiling.");
} catch (RunnerException e) {
//statusError("Error compiling...");
statusError(e);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); statusError(e);
} }
toolbar.deactivate(EditorToolbar.RUN); toolbar.deactivate(EditorToolbar.RUN);
} }
});
} }
// DAM: in Arduino, this is compile (with verbose output)
class DefaultPresentHandler implements Runnable {
public void run() {
try {
sketch.prepare();
String appletClassName = sketch.build(true);
statusNotice("Done compiling.");
} catch (Exception e) {
statusError(e);
}
toolbar.deactivate(EditorToolbar.RUN);
}
}
class DefaultStopHandler implements Runnable {
public void run() {
try {
// DAM: we should try to kill the compilation or upload process here.
} catch (Exception e) {
statusError(e);
}
}
}
/** /**
* Set the location of the sketch run window. Used by Runner to update the * Set the location of the sketch run window. Used by Runner to update the
@ -1855,8 +1888,10 @@ public class Editor extends JFrame implements RunnerListener {
/** /**
* Called by Runner to notify that the sketch has stopped running. * Deactivate the Run button. This is called by Runner to notify that the
* Tools should not call this function, use handleStop() instead. * sketch has stopped running, usually in response to an error (or maybe
* the sketch completing and exiting?) Tools should not call this function.
* To initiate a "stop" action, call handleStop() instead.
*/ */
public void internalRunnerClosed() { public void internalRunnerClosed() {
running = false; running = false;
@ -1870,11 +1905,9 @@ public class Editor extends JFrame implements RunnerListener {
public void internalCloseRunner() { public void internalCloseRunner() {
running = false; running = false;
if (stopHandler != null)
try { try {
if (runtime != null) { stopHandler.run();
runtime.close(); // kills the window
runtime = null; // will this help?
}
} catch (Exception e) { } } catch (Exception e) { }
sketch.cleanup(); sketch.cleanup();
@ -1883,13 +1916,14 @@ public class Editor extends JFrame implements RunnerListener {
/** /**
* Check if the sketch is modified and ask user to save changes. * Check if the sketch is modified and ask user to save changes.
* Immediately should be set true when quitting, or when the save should
* not happen asynchronously. Come to think of it, that's always now?
* @return false if canceling the close/quit operation * @return false if canceling the close/quit operation
*/ */
protected boolean checkModified(boolean immediately) { protected boolean checkModified() {
if (!sketch.isModified()) return true; if (!sketch.isModified()) return true;
// As of Processing 1.0.10, this always happens immediately.
// http://dev.processing.org/bugs/show_bug.cgi?id=1456
String prompt = "Save changes to " + sketch.getName() + "? "; String prompt = "Save changes to " + sketch.getName() + "? ";
if (!Base.isMacOS()) { if (!Base.isMacOS()) {
@ -1899,13 +1933,14 @@ public class Editor extends JFrame implements RunnerListener {
JOptionPane.QUESTION_MESSAGE); JOptionPane.QUESTION_MESSAGE);
if (result == JOptionPane.YES_OPTION) { if (result == JOptionPane.YES_OPTION) {
return handleSave(immediately); return handleSave(true);
} else if (result == JOptionPane.NO_OPTION) { } else if (result == JOptionPane.NO_OPTION) {
return true; // ok to continue return true; // ok to continue
} else if (result == JOptionPane.CANCEL_OPTION) { } else if (result == JOptionPane.CANCEL_OPTION) {
return false; return false;
} else { } else {
throw new IllegalStateException(); throw new IllegalStateException();
} }
@ -1950,7 +1985,7 @@ public class Editor extends JFrame implements RunnerListener {
Object result = pane.getValue(); Object result = pane.getValue();
if (result == options[0]) { // save (and close/quit) if (result == options[0]) { // save (and close/quit)
return handleSave(immediately); return handleSave(true);
} else if (result == options[2]) { // don't save (still close/quit) } else if (result == options[2]) { // don't save (still close/quit)
return true; return true;
@ -2203,20 +2238,23 @@ public class Editor extends JFrame implements RunnerListener {
synchronized public void handleExport(final boolean verbose) { synchronized public void handleExport(final boolean verbose) {
//if (!handleExportCheckModified()) return; //if (!handleExportCheckModified()) return;
toolbar.activate(EditorToolbar.EXPORT); toolbar.activate(EditorToolbar.EXPORT);
console.clear(); console.clear();
statusNotice("Uploading to I/O Board..."); statusNotice("Uploading to I/O Board...");
//SwingUtilities.invokeLater(new Runnable() { new Thread(verbose ? exportAppHandler : exportHandler).start();
Thread t = new Thread(new Runnable() { }
// DAM: in Arduino, this is upload
class DefaultExportHandler implements Runnable {
public void run() { public void run() {
try { try {
serialMonitor.closeSerialPort(); serialMonitor.closeSerialPort();
serialMonitor.setVisible(false); serialMonitor.setVisible(false);
uploading = true; uploading = true;
boolean success = sketch.exportApplet(verbose); boolean success = sketch.exportApplet(false);
if (success) { if (success) {
statusNotice("Done uploading."); statusNotice("Done uploading.");
} else { } else {
@ -2232,10 +2270,37 @@ public class Editor extends JFrame implements RunnerListener {
uploading = false; uploading = false;
//toolbar.clear(); //toolbar.clear();
toolbar.deactivate(EditorToolbar.EXPORT); toolbar.deactivate(EditorToolbar.EXPORT);
}}); }
t.start();
} }
// DAM: in Arduino, this is upload (with verbose output)
class DefaultExportAppHandler implements Runnable {
public void run() {
try {
serialMonitor.closeSerialPort();
serialMonitor.setVisible(false);
uploading = true;
boolean success = sketch.exportApplet(true);
if (success) {
statusNotice("Done uploading.");
} else {
// error message will already be visible
}
} catch (RunnerException e) {
//statusError("Error during upload.");
//e.printStackTrace();
statusError(e);
} catch (Exception e) {
e.printStackTrace();
}
uploading = false;
//toolbar.clear();
toolbar.deactivate(EditorToolbar.EXPORT);
}
}
/** /**
* Checks to see if the sketch has been modified, and if so, * Checks to see if the sketch has been modified, and if so,
@ -2418,7 +2483,7 @@ public class Editor extends JFrame implements RunnerListener {
} }
statusError(mess); statusError(mess);
} }
e.printStackTrace(); // e.printStackTrace();
} }
@ -2563,4 +2628,3 @@ public class Editor extends JFrame implements RunnerListener {
} }
} }
} }

View File

@ -28,6 +28,7 @@ import java.awt.event.*;
import java.io.*; import java.io.*;
import javax.swing.*; import javax.swing.*;
import javax.swing.text.*; import javax.swing.text.*;
import java.util.*; import java.util.*;
@ -47,8 +48,6 @@ public class EditorConsole extends JScrollPane {
MutableAttributeSet stdStyle; MutableAttributeSet stdStyle;
MutableAttributeSet errStyle; MutableAttributeSet errStyle;
boolean cerror;
int maxLineCount; int maxLineCount;
static File errFile; static File errFile;
@ -221,18 +220,9 @@ public class EditorConsole extends JScrollPane {
public void write(byte b[], int offset, int length, boolean err) { public void write(byte b[], int offset, int length, boolean err) {
if (err != cerror) {
// advance the line because switching between err/out streams
// potentially, could check whether we're already on a new line
message("", cerror, true);
}
// we could do some cross platform CR/LF mangling here before outputting // we could do some cross platform CR/LF mangling here before outputting
// add text to output document // add text to output document
message(new String(b, offset, length), err, false); message(new String(b, offset, length), err, false);
// set last error state
cerror = err;
} }
@ -291,10 +281,10 @@ public class EditorConsole extends JScrollPane {
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
class EditorConsoleStream extends OutputStream { private static class EditorConsoleStream extends OutputStream {
//static EditorConsole current; //static EditorConsole current;
boolean err; // whether stderr or stdout final boolean err; // whether stderr or stdout
byte single[] = new byte[1]; final byte single[] = new byte[1];
public EditorConsoleStream(boolean err) { public EditorConsoleStream(boolean err) {
this.err = err; this.err = err;
@ -389,7 +379,7 @@ public class EditorConsole extends JScrollPane {
* swing event thread, so they need to be synchronized * swing event thread, so they need to be synchronized
*/ */
class BufferedStyledDocument extends DefaultStyledDocument { class BufferedStyledDocument extends DefaultStyledDocument {
ArrayList elements = new ArrayList(); ArrayList<ElementSpec> elements = new ArrayList<ElementSpec>();
int maxLineLength, maxLineCount; int maxLineLength, maxLineCount;
int currentLineLength = 0; int currentLineLength = 0;
boolean needLineBreak = false; boolean needLineBreak = false;

View File

@ -103,6 +103,10 @@ public class EditorListener {
char c = event.getKeyChar(); char c = event.getKeyChar();
int code = event.getKeyCode(); int code = event.getKeyCode();
// if (code == KeyEvent.VK_SHIFT) {
// editor.toolbar.setShiftPressed(true);
// }
//System.out.println((int)c + " " + code + " " + event); //System.out.println((int)c + " " + code + " " + event);
//System.out.println(); //System.out.println();
@ -457,6 +461,13 @@ public class EditorListener {
} }
// public boolean keyReleased(KeyEvent event) {
// if (code == KeyEvent.VK_SHIFT) {
// editor.toolbar.setShiftPressed(false);
// }
// }
public boolean keyTyped(KeyEvent event) { public boolean keyTyped(KeyEvent event) {
char c = event.getKeyChar(); char c = event.getKeyChar();

View File

@ -3,7 +3,7 @@
/* /*
Part of the Processing project - http://processing.org Part of the Processing project - http://processing.org
Copyright (c) 2004-08 Ben Fry and Casey Reas Copyright (c) 2004-09 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology Copyright (c) 2001-04 Massachusetts Institute of Technology
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@ -25,6 +25,7 @@ package processing.app;
import java.awt.*; import java.awt.*;
import java.awt.event.*; import java.awt.event.*;
import javax.swing.*; import javax.swing.*;
import javax.swing.event.*; import javax.swing.event.*;
@ -32,12 +33,18 @@ import javax.swing.event.*;
/** /**
* run/stop/etc buttons for the ide * run/stop/etc buttons for the ide
*/ */
public class EditorToolbar extends JComponent implements MouseInputListener { public class EditorToolbar extends JComponent implements MouseInputListener, KeyListener {
/** Rollover titles for each button. */
static final String title[] = { static final String title[] = {
"Verify", "Stop", "New", "Open", "Save", "Upload", "Serial Monitor" "Verify", "Stop", "New", "Open", "Save", "Upload", "Serial Monitor"
}; };
/** Titles for each button when the shift key is pressed. */
static final String titleShift[] = {
"Verify (w/ Verbose Output)", "Stop", "New Editor Window", "Open in Another Window", "Save", "Upload (w/ Verbose Output)", "Serial Monitor"
};
static final int BUTTON_COUNT = title.length; static final int BUTTON_COUNT = title.length;
/** Width of each toolbar button. */ /** Width of each toolbar button. */
static final int BUTTON_WIDTH = 27; static final int BUTTON_WIDTH = 27;
@ -45,6 +52,9 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
static final int BUTTON_HEIGHT = 32; static final int BUTTON_HEIGHT = 32;
/** The amount of space between groups of buttons on the toolbar. */ /** The amount of space between groups of buttons on the toolbar. */
static final int BUTTON_GAP = 5; static final int BUTTON_GAP = 5;
/** Size of the button image being chopped up. */
static final int BUTTON_IMAGE_SIZE = 33;
static final int RUN = 0; static final int RUN = 0;
static final int STOP = 1; static final int STOP = 1;
@ -61,45 +71,35 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
static final int ACTIVE = 2; static final int ACTIVE = 2;
Editor editor; Editor editor;
//boolean disableRun; // this was for library
//Label status;
Image offscreen; Image offscreen;
int width, height; int width, height;
Color bgcolor; Color bgcolor;
static Image buttons; static Image[][] buttonImages;
static Image inactive[];
static Image rollover[];
static Image active[];
int currentRollover; int currentRollover;
//int currentSelection;
JPopupMenu popup; JPopupMenu popup;
JMenu menu; JMenu menu;
int buttonCount; int buttonCount;
int state[] = new int[BUTTON_COUNT]; int[] state = new int[BUTTON_COUNT];
Image stateImage[]; Image[] stateImage;
int which[]; // mapping indices to implementation int which[]; // mapping indices to implementation
int x1[], x2[]; int x1[], x2[];
int y1, y2; int y1, y2;
String status;
Font statusFont; Font statusFont;
Color statusColor; Color statusColor;
boolean shiftPressed;
public EditorToolbar(Editor editor, JMenu menu) { public EditorToolbar(Editor editor, JMenu menu) {
this.editor = editor; this.editor = editor;
this.menu = menu; this.menu = menu;
if (buttons == null) {
buttons = Base.getThemeImage("buttons.gif", this);
}
buttonCount = 0; buttonCount = 0;
which = new int[BUTTON_COUNT]; which = new int[BUTTON_COUNT];
@ -115,9 +115,6 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
currentRollover = -1; currentRollover = -1;
bgcolor = Theme.getColor("buttons.bgcolor"); bgcolor = Theme.getColor("buttons.bgcolor");
status = "";
statusFont = Theme.getFont("buttons.status.font"); statusFont = Theme.getFont("buttons.status.font");
statusColor = Theme.getColor("buttons.status.color"); statusColor = Theme.getColor("buttons.status.color");
@ -125,30 +122,28 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
addMouseMotionListener(this); addMouseMotionListener(this);
} }
protected void loadButtons() {
public void paintComponent(Graphics screen) { Image allButtons = Base.getThemeImage("buttons.gif", this);
// this data is shared by all EditorToolbar instances buttonImages = new Image[BUTTON_COUNT][3];
if (inactive == null) {
inactive = new Image[BUTTON_COUNT];
rollover = new Image[BUTTON_COUNT];
active = new Image[BUTTON_COUNT];
int IMAGE_SIZE = 33;
for (int i = 0; i < BUTTON_COUNT; i++) { for (int i = 0; i < BUTTON_COUNT; i++) {
inactive[i] = createImage(BUTTON_WIDTH, BUTTON_HEIGHT); for (int state = 0; state < 3; state++) {
Graphics g = inactive[i].getGraphics(); Image image = createImage(BUTTON_WIDTH, BUTTON_HEIGHT);
g.drawImage(buttons, -(i*IMAGE_SIZE) - 3, -2*IMAGE_SIZE, null); Graphics g = image.getGraphics();
g.drawImage(allButtons,
rollover[i] = createImage(BUTTON_WIDTH, BUTTON_HEIGHT); -(i*BUTTON_IMAGE_SIZE) - 3,
g = rollover[i].getGraphics(); (-2 + state)*BUTTON_IMAGE_SIZE, null);
g.drawImage(buttons, -(i*IMAGE_SIZE) - 3, -1*IMAGE_SIZE, null); buttonImages[i][state] = image;
active[i] = createImage(BUTTON_WIDTH, BUTTON_HEIGHT);
g = active[i].getGraphics();
g.drawImage(buttons, -(i*IMAGE_SIZE) - 3, -0*IMAGE_SIZE, null);
} }
} }
}
@Override
public void paintComponent(Graphics screen) {
// this data is shared by all EditorToolbar instances
if (buttonImages == null) {
loadButtons();
}
// this happens once per instance of EditorToolbar // this happens once per instance of EditorToolbar
if (stateImage == null) { if (stateImage == null) {
@ -191,21 +186,34 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
/* /*
// if i ever find the guy who wrote the java2d api, i will hurt him. // if i ever find the guy who wrote the java2d api, i will hurt him.
*
* whereas I love the Java2D API. --jdf. lol.
*
Graphics2D g2 = (Graphics2D) g; Graphics2D g2 = (Graphics2D) g;
FontRenderContext frc = g2.getFontRenderContext(); FontRenderContext frc = g2.getFontRenderContext();
float statusW = (float) statusFont.getStringBounds(status, frc).getWidth(); float statusW = (float) statusFont.getStringBounds(status, frc).getWidth();
float statusX = (getSize().width - statusW) / 2; float statusX = (getSize().width - statusW) / 2;
g2.drawString(status, statusX, statusY); g2.drawString(status, statusX, statusY);
*/ */
//int statusY = (BUTTON_HEIGHT + statusFont.getAscent()) / 2; if (currentRollover != -1) {
int statusY = (BUTTON_HEIGHT + g.getFontMetrics().getAscent()) / 2; int statusY = (BUTTON_HEIGHT + g.getFontMetrics().getAscent()) / 2;
String status = shiftPressed ? titleShift[currentRollover] : title[currentRollover];
g.drawString(status, buttonCount * BUTTON_WIDTH + 3 * BUTTON_GAP, statusY); g.drawString(status, buttonCount * BUTTON_WIDTH + 3 * BUTTON_GAP, statusY);
}
screen.drawImage(offscreen, 0, 0, null); screen.drawImage(offscreen, 0, 0, null);
if (!isEnabled()) {
screen.setColor(new Color(0,0,0,100));
screen.fillRect(0, 0, getWidth(), getHeight());
}
} }
public void mouseMoved(MouseEvent e) { public void mouseMoved(MouseEvent e) {
if (!isEnabled())
return;
// mouse events before paint(); // mouse events before paint();
if (state == null) return; if (state == null) return;
@ -213,16 +221,17 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
// avoid flicker, since there will probably be an update event // avoid flicker, since there will probably be an update event
setState(OPEN, INACTIVE, false); setState(OPEN, INACTIVE, false);
} }
//System.out.println(e); handleMouse(e);
//mouseMove(e);
handleMouse(e.getX(), e.getY());
} }
public void mouseDragged(MouseEvent e) { } public void mouseDragged(MouseEvent e) { }
public void handleMouse(int x, int y) { public void handleMouse(MouseEvent e) {
int x = e.getX();
int y = e.getY();
if (currentRollover != -1) { if (currentRollover != -1) {
if ((x > x1[currentRollover]) && (y > y1) && if ((x > x1[currentRollover]) && (y > y1) &&
(x < x2[currentRollover]) && (y < y2)) { (x < x2[currentRollover]) && (y < y2)) {
@ -230,7 +239,6 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
} else { } else {
setState(currentRollover, INACTIVE, true); setState(currentRollover, INACTIVE, true);
messageClear(title[currentRollover]);
currentRollover = -1; currentRollover = -1;
} }
} }
@ -238,10 +246,8 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
if (sel == -1) return; if (sel == -1) return;
if (state[sel] != ACTIVE) { if (state[sel] != ACTIVE) {
//if (!(disableRun && ((sel == RUN) || (sel == STOP)))) {
setState(sel, ROLLOVER, true); setState(sel, ROLLOVER, true);
currentRollover = sel; currentRollover = sel;
//}
} }
} }
@ -263,32 +269,16 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
private void setState(int slot, int newState, boolean updateAfter) { private void setState(int slot, int newState, boolean updateAfter) {
//if (inactive == null) return;
state[slot] = newState; state[slot] = newState;
switch (newState) { stateImage[slot] = buttonImages[which[slot]][newState];
case INACTIVE:
stateImage[slot] = inactive[which[slot]];
break;
case ACTIVE:
stateImage[slot] = active[which[slot]];
break;
case ROLLOVER:
stateImage[slot] = rollover[which[slot]];
message(title[which[slot]]);
break;
}
if (updateAfter) { if (updateAfter) {
//System.out.println("trying to update " + slot + " " + state[slot]); repaint();
//new Exception("setting slot " + slot + " to " + state[slot]).printStackTrace();
repaint(); // changed for swing from update();
//Toolkit.getDefaultToolkit().sync();
} }
} }
public void mouseEntered(MouseEvent e) { public void mouseEntered(MouseEvent e) {
//mouseMove(e); handleMouse(e);
handleMouse(e.getX(), e.getY());
} }
@ -300,14 +290,18 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
if (state[OPEN] != INACTIVE) { if (state[OPEN] != INACTIVE) {
setState(OPEN, INACTIVE, true); setState(OPEN, INACTIVE, true);
} }
status = ""; handleMouse(e);
handleMouse(e.getX(), e.getY());
} }
int wasDown = -1; int wasDown = -1;
public void mousePressed(MouseEvent e) { public void mousePressed(MouseEvent e) {
// jdf
if (!isEnabled())
return;
final int x = e.getX(); final int x = e.getX();
final int y = e.getY(); final int y = e.getY();
@ -331,8 +325,11 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
break; break;
case NEW: case NEW:
//editor.base.handleNew(e.isShiftDown()); if (shiftPressed) {
editor.base.handleNew();
} else {
editor.base.handleNewReplace(); editor.base.handleNewReplace();
}
break; break;
case SAVE: case SAVE:
@ -353,84 +350,26 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
public void mouseClicked(MouseEvent e) { } public void mouseClicked(MouseEvent e) { }
public void mouseReleased(MouseEvent e) { public void mouseReleased(MouseEvent e) { }
/*
switch (currentSelection) {
case OPEN:
setState(OPEN, INACTIVE, true);
break;
}
currentSelection = -1;
*/
}
//public void disableRun(boolean what) {
//disableRun = what;
//}
/*
public void run() {
if (inactive == null) return;
clear();
setState(RUN, ACTIVE, true);
}
*/
// public void running(boolean yesno) {
// setState(RUN, yesno ? ACTIVE : INACTIVE, true);
// }
/** /**
* Set a particular button to be active. * Set a particular button to be active.
*/ */
public void activate(int what) { public void activate(int what) {
//System.out.println("activating " + what); if (buttonImages != null) {
if (inactive == null) return;
setState(what, ACTIVE, true); setState(what, ACTIVE, true);
} }
}
//public void clearRun() {
//if (inactive == null) return;
//setState(RUN, INACTIVE, true);
//}
/** /**
* Set a particular button to be active. * Set a particular button to be active.
*/ */
public void deactivate(int what) { public void deactivate(int what) {
if (inactive == null) return; // don't draw if not ready if (buttonImages != null) {
setState(what, INACTIVE, true); setState(what, INACTIVE, true);
} }
/**
* Clear all the state of all buttons.
*/
// public void clear() { // (int button) {
// if (inactive == null) return;
//
// System.out.println("clearing state of buttons");
// // skip the run button, do the others
// for (int i = 1; i < buttonCount; i++) {
// setState(i, INACTIVE, false);
// }
// repaint(); // changed for swing from update();
// }
public void message(String msg) {
//status.setText(msg + " "); // don't mind the hack
status = msg;
}
public void messageClear(String msg) {
//if (status.getText().equals(msg + " ")) status.setText(Editor.EMPTY);
if (status.equals(msg)) status = "";
} }
@ -447,4 +386,23 @@ public class EditorToolbar extends JComponent implements MouseInputListener {
public Dimension getMaximumSize() { public Dimension getMaximumSize() {
return new Dimension(3000, BUTTON_HEIGHT); return new Dimension(3000, BUTTON_HEIGHT);
} }
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SHIFT) {
shiftPressed = true;
repaint();
}
}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_SHIFT) {
shiftPressed = false;
repaint();
}
}
public void keyTyped(KeyEvent e) { }
} }

View File

@ -26,6 +26,9 @@ import java.io.File;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.sun.jna.Library;
import com.sun.jna.Native;
/** /**
* Used by Base for platform-specific tweaking, for instance finding the * Used by Base for platform-specific tweaking, for instance finding the
@ -129,6 +132,36 @@ public class Platform {
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary)Native.loadLibrary("c", CLibrary.class);
int setenv(String name, String value, int overwrite);
String getenv(String name);
int unsetenv(String name);
int putenv(String string);
}
public void setenv(String variable, String value) {
CLibrary clib = CLibrary.INSTANCE;
clib.setenv(variable, value, 1);
}
public String getenv(String variable) {
CLibrary clib = CLibrary.INSTANCE;
return clib.getenv(variable);
}
public int unsetenv(String variable) {
CLibrary clib = CLibrary.INSTANCE;
return clib.unsetenv(variable);
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
protected void showLauncherWarning() { protected void showLauncherWarning() {
Base.showWarning("No launcher available", Base.showWarning("No launcher available",
"Unspecified platform, no launcher available.\n" + "Unspecified platform, no launcher available.\n" +

View File

@ -626,6 +626,11 @@ public class Preferences {
} }
static public void unset(String attribute) {
table.remove(attribute);
}
static public boolean getBoolean(String attribute) { static public boolean getBoolean(String attribute) {
String value = get(attribute); //, null); String value = get(attribute); //, null);
return (new Boolean(value)).booleanValue(); return (new Boolean(value)).booleanValue();

View File

@ -3,7 +3,7 @@
/* /*
Part of the Processing project - http://processing.org Part of the Processing project - http://processing.org
Copyright (c) 2004-09 Ben Fry and Casey Reas Copyright (c) 2004-10 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology Copyright (c) 2001-04 Massachusetts Institute of Technology
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@ -95,6 +95,9 @@ public class Sketch {
* DLLs or JNILIBs. * DLLs or JNILIBs.
*/ */
private String libraryPath; private String libraryPath;
/**
* List of library folders.
*/
private ArrayList<File> importedLibraries; private ArrayList<File> importedLibraries;
/** /**
@ -1165,11 +1168,14 @@ public class Sketch {
* X. afterwards, some of these steps need a cleanup function * X. afterwards, some of these steps need a cleanup function
* </PRE> * </PRE>
*/ */
protected String compile(boolean verbose) //protected String compile() throws RunnerException {
throws RunnerException {
String name;
/**
* When running from the editor, take care of preparations before running
* the build.
*/
public void prepare() {
// make sure the user didn't hide the sketch folder // make sure the user didn't hide the sketch folder
ensureExistence(); ensureExistence();
@ -1199,11 +1205,8 @@ public class Sketch {
// better connected to the dataFolder stuff below. // better connected to the dataFolder stuff below.
cleanup(); cleanup();
// handle preprocessing the main file's code // // handle preprocessing the main file's code
name = build(tempBuildFolder.getAbsolutePath(), verbose); // return build(tempBuildFolder.getAbsolutePath());
size(tempBuildFolder.getAbsolutePath(), name);
return name;
} }
@ -1255,14 +1258,6 @@ public class Sketch {
// 1. concatenate all .pde files to the 'main' pde // 1. concatenate all .pde files to the 'main' pde
// store line number for starting point of each code bit // store line number for starting point of each code bit
// Unfortunately, the header has to be written on a single line, because
// there's no way to determine how long it will be until the code has
// already been preprocessed. The header will vary in length based on
// the programming mode (STATIC, ACTIVE, or JAVA), which is determined
// by the preprocessor. So the preprocOffset for the primary class remains
// zero, even though it'd be nice to have a legitimate offset, and be able
// to remove the 'pretty' boolean for preproc.write().
StringBuffer bigCode = new StringBuffer(); StringBuffer bigCode = new StringBuffer();
int bigCount = 0; int bigCount = 0;
for (SketchCode sc : code) { for (SketchCode sc : code) {
@ -1271,29 +1266,9 @@ public class Sketch {
bigCode.append(sc.getProgram()); bigCode.append(sc.getProgram());
bigCode.append('\n'); bigCode.append('\n');
bigCount += sc.getLineCount(); bigCount += sc.getLineCount();
// if (sc != code[0]) {
// sc.setPreprocName(null); // don't compile me
// }
} }
} }
/*
String program = code[0].getProgram();
StringBuffer bigCode = new StringBuffer(program);
int bigCount = code[0].getLineCount();
bigCode.append('\n');
for (int i = 1; i < codeCount; i++) {
if (code[i].isExtension("pde")) {
code[i].setPreprocOffset(bigCount);
bigCode.append(code[i].getProgram());
bigCode.append('\n');
bigCount += code[i].getLineCount();
code[i].setPreprocName(null); // don't compile me
}
}
*/
// Note that the headerOffset isn't applied until compile and run, because // Note that the headerOffset isn't applied until compile and run, because
// it only applies to the code after it's been written to the .java file. // it only applies to the code after it's been written to the .java file.
int headerOffset = 0; int headerOffset = 0;
@ -1391,6 +1366,134 @@ public class Sketch {
} }
public ArrayList<File> getImportedLibraries() {
return importedLibraries;
}
/**
* Map an error from a set of processed .java files back to its location
* in the actual sketch.
* @param message The error message.
* @param filename The .java file where the exception was found.
* @param line Line number of the .java file for the exception (1-indexed)
* @return A RunnerException to be sent to the editor, or null if it wasn't
* possible to place the exception to the sketch code.
*/
// public RunnerException placeExceptionAlt(String message,
// String filename, int line) {
// String appletJavaFile = appletClassName + ".java";
// SketchCode errorCode = null;
// if (filename.equals(appletJavaFile)) {
// for (SketchCode code : getCode()) {
// if (code.isExtension("pde")) {
// if (line >= code.getPreprocOffset()) {
// errorCode = code;
// }
// }
// }
// } else {
// for (SketchCode code : getCode()) {
// if (code.isExtension("java")) {
// if (filename.equals(code.getFileName())) {
// errorCode = code;
// }
// }
// }
// }
// int codeIndex = getCodeIndex(errorCode);
//
// if (codeIndex != -1) {
// //System.out.println("got line num " + lineNumber);
// // in case this was a tab that got embedded into the main .java
// line -= getCode(codeIndex).getPreprocOffset();
//
// // lineNumber is 1-indexed, but editor wants zero-indexed
// line--;
//
// // getMessage() will be what's shown in the editor
// RunnerException exception =
// new RunnerException(message, codeIndex, line, -1);
// exception.hideStackTrace();
// return exception;
// }
// return null;
// }
/**
* Map an error from a set of processed .java files back to its location
* in the actual sketch.
* @param message The error message.
* @param filename The .java file where the exception was found.
* @param line Line number of the .java file for the exception (0-indexed!)
* @return A RunnerException to be sent to the editor, or null if it wasn't
* possible to place the exception to the sketch code.
*/
public RunnerException placeException(String message,
String dotJavaFilename,
int dotJavaLine) {
int codeIndex = 0; //-1;
int codeLine = -1;
// System.out.println("placing " + dotJavaFilename + " " + dotJavaLine);
// System.out.println("code count is " + getCodeCount());
// first check to see if it's a .java file
for (int i = 0; i < getCodeCount(); i++) {
SketchCode code = getCode(i);
if (code.isExtension("java")) {
if (dotJavaFilename.equals(code.getFileName())) {
codeIndex = i;
codeLine = dotJavaLine;
return new RunnerException(message, codeIndex, codeLine);
}
}
}
// If not the preprocessed file at this point, then need to get out
if (!dotJavaFilename.equals(name + ".java")) {
return null;
}
// if it's not a .java file, codeIndex will still be 0
// this section searches through the list of .pde files
codeIndex = 0;
for (int i = 0; i < getCodeCount(); i++) {
SketchCode code = getCode(i);
if (code.isExtension("pde")) {
// System.out.println("preproc offset is " + code.getPreprocOffset());
// System.out.println("looking for line " + dotJavaLine);
if (code.getPreprocOffset() <= dotJavaLine) {
codeIndex = i;
// System.out.println("i'm thinkin file " + i);
codeLine = dotJavaLine - code.getPreprocOffset();
}
}
}
// could not find a proper line number, so deal with this differently.
// but if it was in fact the .java file we're looking for, though,
// send the error message through.
// this is necessary because 'import' statements will be at a line
// that has a lower number than the preproc offset, for instance.
// if (codeLine == -1 && !dotJavaFilename.equals(name + ".java")) {
// return null;
// }
return new RunnerException(message, codeIndex, codeLine);
}
/**
* Run the build inside the temporary build folder.
* @return null if compilation failed, main class name if not
* @throws RunnerException
*/
public String build(boolean verbose) throws RunnerException {
return build(tempBuildFolder.getAbsolutePath(), verbose);
}
/** /**
* Preprocess and compile all the code for this sketch. * Preprocess and compile all the code for this sketch.
* *
@ -1410,6 +1513,7 @@ public class Sketch {
// that will bubble up to whomever called build(). // that will bubble up to whomever called build().
Compiler compiler = new Compiler(); Compiler compiler = new Compiler();
if (compiler.compile(this, buildPath, primaryClassName, verbose)) { if (compiler.compile(this, buildPath, primaryClassName, verbose)) {
size(buildPath, primaryClassName);
return primaryClassName; return primaryClassName;
} }
return null; return null;
@ -1538,7 +1642,8 @@ public class Sketch {
break; break;
} else { } else {
index++; // continue blanking this area
p[index++] = ' ';
} }
} }
if (!endOfRainbow) { if (!endOfRainbow) {
@ -1588,35 +1693,6 @@ public class Sketch {
} }
/**
* Read from a file with a bunch of attribute/value pairs
* that are separated by = and ignore comments with #.
*/
protected HashMap<String,String> readSettings(File inputFile) {
HashMap<String,String> outgoing = new HashMap<String,String>();
if (!inputFile.exists()) return outgoing; // return empty hash
String lines[] = PApplet.loadStrings(inputFile);
for (int i = 0; i < lines.length; i++) {
int hash = lines[i].indexOf('#');
String line = (hash == -1) ?
lines[i].trim() : lines[i].substring(0, hash).trim();
if (line.length() == 0) continue;
int equals = line.indexOf('=');
if (equals == -1) {
System.err.println("ignoring illegal line in " + inputFile);
System.err.println(" " + line);
continue;
}
String attr = line.substring(0, equals).trim();
String valu = line.substring(equals + 1).trim();
outgoing.put(attr, valu);
}
return outgoing;
}
/** /**
* Slurps up .class files from a colon (or semicolon on windows) * Slurps up .class files from a colon (or semicolon on windows)
* separated list of paths and adds them to a ZipOutputStream. * separated list of paths and adds them to a ZipOutputStream.
@ -1923,11 +1999,6 @@ public class Sketch {
} }
public ArrayList<File> getImportedLibraries() {
return importedLibraries;
}
public String getClassPath() { public String getClassPath() {
return classPath; return classPath;
} }

View File

@ -0,0 +1,95 @@
/*
* @(#)StreamRedirectThread.java 1.4 03/01/23
*
* Copyright 2003 Sun Microsystems, Inc. All rights reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*/
/*
* Copyright (c) 1997-2001 by Sun Microsystems, Inc. All Rights Reserved.
*
* Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
* modify and redistribute this software in source and binary code form,
* provided that i) this copyright notice and license appear on all copies of
* the software; and ii) Licensee does not utilize the software in a manner
* which is disparaging to Sun.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
* NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
* LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
* LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
* INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
* CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
* OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* This software is not designed or intended for use in on-line control of
* aircraft, air traffic, aircraft navigation or aircraft communications; or in
* the design, construction, operation or maintenance of any nuclear
* facility. Licensee represents and warrants that it will not use or
* redistribute the Software for such purposes.
*/
package processing.app;
import java.io.*;
/**
* StreamRedirectThread is a thread which copies it's input to
* it's output and terminates when it completes.
*
* @version @(#) StreamRedirectThread.java 1.4 03/01/23 23:33:38
* @author Robert Field
*/
public class StreamRedirectThread extends Thread {
private final Reader in;
private final Writer out;
private static final int BUFFER_SIZE = 2048;
/**
* Set up for copy.
* @param name Name of the thread
* @param in Stream to copy from
* @param out Stream to copy to
*/
public StreamRedirectThread(String name, InputStream in, OutputStream out) {
super(name);
this.in = new InputStreamReader(in);
this.out = new OutputStreamWriter(out);
setPriority(Thread.MAX_PRIORITY-1);
}
public StreamRedirectThread(String name, Reader in, Writer out) {
super(name);
this.in = in;
this.out = out;
setPriority(Thread.MAX_PRIORITY-1);
}
/**
* Copy.
*/
public void run() {
try {
char[] cbuf = new char[BUFFER_SIZE];
int count;
//System.out.println("opening streamredirectthread");
while ((count = in.read(cbuf, 0, BUFFER_SIZE)) >= 0) {
out.write(cbuf, 0, count);
// had to add the flush() here.. maybe shouldn't be using writer? [fry]
out.flush();
}
//System.out.println("exiting streamredirectthread");
out.flush();
} catch(IOException exc) {
System.err.println("Child I/O Transfer - " + exc);
}
}
}

View File

@ -8,8 +8,12 @@ import java.util.zip.*;
//import javax.swing.SwingUtilities; //import javax.swing.SwingUtilities;
/** /**
* An example of a very simple, multi-threaded HTTP server. * This code is placed here in anticipation of running the reference from an
* Taken from <a href="http://java.sun.com/developer/technicalArticles/Networking/Webserver/">this</a> article on java.sun.com. * internal web server that reads the docs from a zip file, instead of using
* thousands of .html files on the disk, which is really inefficient.
* <p/>
* This is a very simple, multi-threaded HTTP server, originally based on
* <a href="http://j.mp/6BQwpI">this</a> article on java.sun.com.
*/ */
public class WebServer implements HttpConstants { public class WebServer implements HttpConstants {

View File

@ -65,7 +65,8 @@ public class EventThread extends Thread {
// Maps ThreadReference to ThreadTrace instances // Maps ThreadReference to ThreadTrace instances
private Map traceMap = new HashMap(); private Map traceMap = new HashMap();
EventThread(Runner parent, VirtualMachine vm, String[] excludes, PrintWriter writer) {
public EventThread(Runner parent, VirtualMachine vm, String[] excludes, PrintWriter writer) {
super("event-handler"); super("event-handler");
this.parent = parent; this.parent = parent;
this.vm = vm; this.vm = vm;
@ -103,7 +104,7 @@ public class EventThread extends Thread {
* @param excludes Class patterns for which we don't want events * @param excludes Class patterns for which we don't want events
* @param watchFields Do we want to watch assignments to fields * @param watchFields Do we want to watch assignments to fields
*/ */
void setEventRequests(boolean watchFields) { public void setEventRequests(boolean watchFields) {
EventRequestManager mgr = vm.eventRequestManager(); EventRequestManager mgr = vm.eventRequestManager();
// VMDeathRequest deathReq = mgr.createVMDeathRequest(); // VMDeathRequest deathReq = mgr.createVMDeathRequest();

View File

@ -29,7 +29,7 @@ import java.io.*;
/** /**
* Slurps up messages from compiler. * Slurps up messages from compiler.
*/ */
class MessageSiphon implements Runnable { public class MessageSiphon implements Runnable {
BufferedReader streamReader; BufferedReader streamReader;
Thread thread; Thread thread;
MessageConsumer consumer; MessageConsumer consumer;
@ -84,4 +84,9 @@ class MessageSiphon implements Runnable {
thread = null; thread = null;
} }
} }
public Thread getThread() {
return thread;
}
} }

View File

@ -24,6 +24,7 @@
package processing.app.debug; package processing.app.debug;
import processing.app.*; import processing.app.*;
import processing.app.preproc.PdePreprocessor;
import processing.core.*; import processing.core.*;
import java.awt.Point; import java.awt.Point;
@ -49,60 +50,54 @@ public class Runner implements MessageConsumer {
private boolean presenting; private boolean presenting;
// Object that listens for error messages or exceptions. // Object that listens for error messages or exceptions.
private RunnerListener listener; protected RunnerListener listener;
// Running remote VM // Running remote VM
private VirtualMachine vm; protected VirtualMachine vm;
// Thread transferring remote error stream to our error stream // Thread transferring remote error stream to our error stream
private Thread errThread = null; protected Thread errThread = null;
// Thread transferring remote output stream to our output stream // Thread transferring remote output stream to our output stream
private Thread outThread = null; protected Thread outThread = null;
// Mode for tracing the Trace program (default= 0 off) // Mode for tracing the Trace program (default= 0 off)
private int debugTraceMode = 0; protected int debugTraceMode = 0;
// Do we want to watch assignments to fields // Do we want to watch assignments to fields
private boolean watchFields = false; protected boolean watchFields = false;
// Class patterns for which we don't want events // Class patterns for which we don't want events
private String[] excludes = { protected String[] excludes = {
"java.*", "javax.*", "sun.*", "com.sun.*", "java.*", "javax.*", "sun.*", "com.sun.*",
"apple.*", "apple.*",
"processing.*" "processing.*"
}; };
private RunnerException exception; protected RunnerException exception;
//private PrintStream leechErr; //private PrintStream leechErr;
private Editor editor; protected Editor editor;
private Sketch sketch; protected Sketch sketch;
private String appletClassName; private String appletClassName;
// private boolean newMessage;
// private int messageLineCount;
// private boolean foundMessageSource;
//
// private SystemOutSiphon processInput;
// private OutputStream processOutput;
// private MessageSiphon processError;
public Runner(RunnerListener listener, Sketch sketch) {
public Runner(Sketch sketch, String appletClassName,
boolean presenting, RunnerListener listener) {
this.sketch = sketch;
this.appletClassName = appletClassName;
this.presenting = presenting;
this.listener = listener; this.listener = listener;
this.sketch = sketch;
if (listener instanceof Editor) { if (listener instanceof Editor) {
this.editor = (Editor) listener; this.editor = (Editor) listener;
// } else {
// System.out.println("actually it's a " + listener.getClass().getName());
} }
} }
public void launch() { public void launch(String appletClassName, boolean presenting) {
this.appletClassName = appletClassName;
this.presenting = presenting;
// TODO entire class is a total mess as of release 0136. // TODO entire class is a total mess as of release 0136.
// This will be cleaned up significantly over the next couple months. // This will be cleaned up significantly over the next couple months.
@ -132,7 +127,7 @@ public class Runner implements MessageConsumer {
protected String[] getMachineParams() { protected String[] getMachineParams() {
ArrayList params = new ArrayList(); ArrayList<String> params = new ArrayList<String>();
//params.add("-Xint"); // interpreted mode //params.add("-Xint"); // interpreted mode
//params.add("-Xprof"); // profiler //params.add("-Xprof"); // profiler
@ -203,6 +198,13 @@ public class Runner implements MessageConsumer {
protected String[] getSketchParams() { protected String[] getSketchParams() {
ArrayList<String> params = new ArrayList<String>(); ArrayList<String> params = new ArrayList<String>();
// It's dangerous to add your own main() to your code,
// but if you've done it, we'll respect your right to hang yourself.
// http://dev.processing.org/bugs/show_bug.cgi?id=1446
if (PdePreprocessor.foundMain) {
params.add(appletClassName);
} else {
params.add("processing.core.PApplet"); params.add("processing.core.PApplet");
// If there was a saved location (this guy has been run more than once) // If there was a saved location (this guy has been run more than once)
@ -242,6 +244,7 @@ public class Runner implements MessageConsumer {
} }
params.add(appletClassName); params.add(appletClassName);
}
// String outgoing[] = new String[params.size()]; // String outgoing[] = new String[params.size()];
// params.toArray(outgoing); // params.toArray(outgoing);
@ -250,121 +253,11 @@ public class Runner implements MessageConsumer {
} }
/*
protected VirtualMachine launchVirtualMachine_sun(String[] vmParams, String[] classParams) {
//vm = launchTarget(sb.toString());
LaunchingConnector connector =
findLaunchingConnector("com.sun.jdi.CommandLineLaunch");
//Map arguments = connectorArguments(connector, mainArgs);
PApplet.println(connector); // gets the defaults
Map arguments = connector.defaultArguments();
//System.out.println(arguments);
// for (Iterator itr = arguments.keySet().iterator(); itr.hasNext(); ) {
// Connector.Argument argument =
// (Connector.Argument) arguments.get(itr.next());
// System.out.println(argument);
// }
//connector.transport().
Connector.Argument mainArg =
(Connector.Argument)arguments.get("main");
if (mainArg == null) {
throw new Error("Bad launching connector");
}
String mainArgs = "";
//mainArgs = addArgument(mainArgs, className);
if (classParams != null) {
for (int i = 0; i < classParams.length; i++) {
mainArgs = addArgument(mainArgs, classParams[i], ' ');
}
}
mainArg.setValue(mainArgs);
//System.out.println("main args are: ");
//System.out.println(mainArgs);
// if (watchFields) {
// // We need a VM that supports watchpoints
// Connector.Argument optionArg =
// (Connector.Argument)arguments.get("options");
// if (optionArg == null) {
// throw new Error("Bad launching connector");
// }
// optionArg.setValue("-classic");
// }
String optionArgs = "";
for (int i = 0; i < vmParams.length; i++) {
optionArgs = addArgument(optionArgs, vmParams[i], ' ');
}
// prevent any incorrect transport address b.s. from being added
// -Xrunjdwp:transport=dt_socket,address=cincinnati118.ipcorporate.com:55422,suspend=y
//optionArgs = addArgument(optionArgs, "-agentlib:jdwp=transport=dt_socket,address=localhost:12345,suspend=y", ' ');
//optionArgs += " -Xrunjdwp:transport=dt_socket,address=localhost:55422,suspend=y";
//optionArgs = optionArgs + " -agentlib:jdwp=transport=dt_socket";
//optionArgs = addArgument(optionArgs, "-Xrunjdwp:transport=dt_socket,address=localhost:55422,suspend=y", ' ');
//optionArgs = addArgument(optionArgs, "address=127.0.0.1:54321", ' ');
//optionArgs = addArgument(optionArgs, "localAddress", ' ');
Connector.Argument optionArg =
(Connector.Argument)arguments.get("options");
optionArg.setValue(optionArgs);
// Connector.Argument addressArg =
// (Connector.Argument)arguments.get("address");
//arguments.put("raw.address", new Connector.Argument("blah"));
//PApplet.println("it's gonna be " + addressArg);
//arguments.put("address", "localhost");
// Connector.Argument addressArg =
// (Connector.Argument)arguments.get("address");
// addressArg.setValue("localhost");
// System.out.println("option args are: ");
// System.out.println(arguments.get("options"));
System.out.println("args are " + arguments);
// com.sun.tools.jdi.SunCommandLineLauncher
// http://java.sun.com/j2se/1.5.0/docs/guide/jpda/conninv.html#sunlaunch
try {
return connector.launch(arguments);
} catch (IOException exc) {
throw new Error("Unable to launch target VM: " + exc);
} catch (IllegalConnectorArgumentsException exc) {
throw new Error("Internal error: " + exc);
} catch (VMStartException exc) {
exc.printStackTrace();
System.err.println();
System.err.println("Could not run the sketch.");
System.err.println("Make sure that you haven't set the maximum available memory too high.");
System.err.println("For more information, read revisions.txt and Help -> Troubleshooting.");
//System.err.println("Target VM failed to initialize:");
//System.err.println("msg is " + exc.getMessage());
//exc.printStackTrace();
//throw new Error("Target VM failed to initialize: " +
//exc.getMessage());
//throw new Error(exc.getMessage());
//throw new RunnerException(exc.getMessage());
//editor.error(exc);
editor.error("Could not run the sketch.");
return null;
}
}
*/
protected VirtualMachine launchVirtualMachine(String[] vmParams, protected VirtualMachine launchVirtualMachine(String[] vmParams,
String[] classParams) { String[] classParams) {
//vm = launchTarget(sb.toString()); //vm = launchTarget(sb.toString());
LaunchingConnector connector = LaunchingConnector connector = (LaunchingConnector)
findLaunchingConnector("com.sun.jdi.RawCommandLineLaunch"); findConnector("com.sun.jdi.RawCommandLineLaunch");
//PApplet.println(connector); // gets the defaults //PApplet.println(connector); // gets the defaults
//Map arguments = connectorArguments(connector, mainArgs); //Map arguments = connectorArguments(connector, mainArgs);
@ -447,9 +340,10 @@ public class Runner implements MessageConsumer {
} }
System.err.println("For more information, read revisions.txt and Help \u2192 Troubleshooting."); System.err.println("For more information, read revisions.txt and Help \u2192 Troubleshooting.");
} }
if (editor != null) { // changing this to separate editor and listener [091124]
//if (editor != null) {
listener.statusError("Could not run the sketch."); listener.statusError("Could not run the sketch.");
} //}
return null; return null;
} }
} }
@ -493,7 +387,7 @@ public class Runner implements MessageConsumer {
* start threads to forward remote error and output streams, * start threads to forward remote error and output streams,
* resume the remote VM, wait for the final event, and shutdown. * resume the remote VM, wait for the final event, and shutdown.
*/ */
void generateTrace(PrintWriter writer) { protected void generateTrace(PrintWriter writer) {
vm.setDebugTraceMode(debugTraceMode); vm.setDebugTraceMode(debugTraceMode);
EventThread eventThread = null; EventThread eventThread = null;
@ -515,7 +409,7 @@ public class Runner implements MessageConsumer {
// process.getErrorStream(), // process.getErrorStream(),
// System.err); // System.err);
MessageSiphon ms = new MessageSiphon(process.getErrorStream(), this); MessageSiphon ms = new MessageSiphon(process.getErrorStream(), this);
errThread = ms.thread; errThread = ms.getThread();
outThread = new StreamRedirectThread("output reader", outThread = new StreamRedirectThread("output reader",
process.getInputStream(), process.getInputStream(),
@ -545,7 +439,6 @@ public class Runner implements MessageConsumer {
if (editor != null) { if (editor != null) {
editor.internalRunnerClosed(); editor.internalRunnerClosed();
} }
} catch (InterruptedException exc) { } catch (InterruptedException exc) {
// we don't interrupt // we don't interrupt
} }
@ -554,20 +447,10 @@ public class Runner implements MessageConsumer {
} }
/** protected Connector findConnector(String connectorName) {
* Find a com.sun.jdi.CommandLineLaunch connector
*/
LaunchingConnector findLaunchingConnector(String connectorName) {
//VirtualMachineManager mgr = Bootstrap.virtualMachineManager();
// Get the default connector.
// Not useful here since they all need different args.
// System.out.println(Bootstrap.virtualMachineManager().defaultConnector());
// return Bootstrap.virtualMachineManager().defaultConnector();
List connectors = Bootstrap.virtualMachineManager().allConnectors(); List connectors = Bootstrap.virtualMachineManager().allConnectors();
// code to list available connectors // debug: code to list available connectors
// Iterator iter2 = connectors.iterator(); // Iterator iter2 = connectors.iterator();
// while (iter2.hasNext()) { // while (iter2.hasNext()) {
// Connector connector = (Connector)iter2.next(); // Connector connector = (Connector)iter2.next();
@ -578,10 +461,10 @@ public class Runner implements MessageConsumer {
while (iter.hasNext()) { while (iter.hasNext()) {
Connector connector = (Connector)iter.next(); Connector connector = (Connector)iter.next();
if (connector.name().equals(connectorName)) { if (connector.name().equals(connectorName)) {
return (LaunchingConnector)connector; return connector;
} }
} }
throw new Error("No launching connector"); throw new Error("No connector");
} }
@ -611,7 +494,17 @@ public class Runner implements MessageConsumer {
// System.out.println(or.referenceType().fields()); // System.out.println(or.referenceType().fields());
// if (name.startsWith("java.lang.")) { // if (name.startsWith("java.lang.")) {
// name = name.substring(10); // name = name.substring(10);
if (exceptionName.equals("java.lang.OutOfMemoryError")) { if (!handleCommonErrors(exceptionName, message, listener)) {
reportException(message, event.thread());
}
if (editor != null) {
editor.internalRunnerClosed();
}
}
public static boolean handleCommonErrors(final String exceptionClass, final String message, final RunnerListener listener)
{
if (exceptionClass.equals("java.lang.OutOfMemoryError")) {
listener.statusError("OutOfMemoryError: You may need to increase the memory setting in Preferences."); listener.statusError("OutOfMemoryError: You may need to increase the memory setting in Preferences.");
System.err.println("An OutOfMemoryError means that your code is either using up too much memory"); System.err.println("An OutOfMemoryError means that your code is either using up too much memory");
System.err.println("because of a bug (e.g. creating an array that's too large, or unintentionally"); System.err.println("because of a bug (e.g. creating an array that's too large, or unintentionally");
@ -619,96 +512,83 @@ public class Runner implements MessageConsumer {
System.err.println("If your sketch uses a lot of memory (for instance if it loads a lot of data files)"); System.err.println("If your sketch uses a lot of memory (for instance if it loads a lot of data files)");
System.err.println("you can increase the memory available to your sketch using the Preferences window."); System.err.println("you can increase the memory available to your sketch using the Preferences window.");
} else if (exceptionName.equals("java.lang.StackOverflowError")) { } else if (exceptionClass.equals("java.lang.StackOverflowError")) {
listener.statusError("StackOverflowError: This sketch is attempting too much recursion."); listener.statusError("StackOverflowError: This sketch is attempting too much recursion.");
System.err.println("A StackOverflowError means that you have a bug that's causing a function"); System.err.println("A StackOverflowError means that you have a bug that's causing a function");
System.err.println("to be called recursively (it's calling itself and going in circles),"); System.err.println("to be called recursively (it's calling itself and going in circles),");
System.err.println("or you're intentionally calling a recursive function too much,"); System.err.println("or you're intentionally calling a recursive function too much,");
System.err.println("and your code should be rewritten in a more efficient manner."); System.err.println("and your code should be rewritten in a more efficient manner.");
} else if (exceptionName.equals("java.lang.UnsupportedClassVersionError")) { } else if (exceptionClass.equals("java.lang.UnsupportedClassVersionError")) {
listener.statusError("UnsupportedClassVersionError: A library is using code compiled with an unsupported version of Java."); listener.statusError("UnsupportedClassVersionError: A library is using code compiled with an unsupported version of Java.");
System.err.println("This version of Processing only supports libraries and JAR files compiled for Java 1.5."); System.err.println("This version of Processing only supports libraries and JAR files compiled for Java 1.5.");
System.err.println("A library used by this sketch was compiled for Java 1.6 or later, "); System.err.println("A library used by this sketch was compiled for Java 1.6 or later, ");
System.err.println("and needs to be recompiled to be compatible with Java 1.5."); System.err.println("and needs to be recompiled to be compatible with Java 1.5.");
} else if (exceptionClass.equals("java.lang.NoSuchMethodError") || exceptionClass.equals("java.lang.NoSuchFieldError")) {
} else if (exceptionName.equals("java.lang.NoSuchMethodError") || exceptionName.equals("java.lang.NoSuchFieldError")) { listener.statusError(exceptionClass.substring(10) + ": You're probably using a library that's incompatible with this version of Processing.");
listener.statusError(exceptionName.substring(10) + ": You're probably using a library that's incompatible with this version of Processing."); } else if (message!=null &&
message.equals("ClassNotFoundException: quicktime.std.StdQTException")) {
} else if (message.equals("ClassNotFoundException: quicktime.std.StdQTException")) { listener
listener.statusError("Could not find QuickTime, please reinstall QuickTime 7 or later."); .statusError("Could not find QuickTime, please reinstall QuickTime 7 or later.");
} else { } else {
reportException(message, event.thread()); return false;
} }
editor.internalRunnerClosed(); return true;
} }
// TODO: This may be called more than one time per error in the VM,
// This may be called more than one time per error in the VM,
// presumably because exceptions might be wrapped inside others, // presumably because exceptions might be wrapped inside others,
// and this will fire for both. // and this will fire for both.
protected void reportException(String message, ThreadReference thread) { protected void reportException(String message, ThreadReference thread) {
try { listener.statusError(findException(message, thread));
int codeIndex = -1; }
int lineNumber = -1;
/**
* Move through a list of stack frames, searching for references to code
* found in the current sketch. Return with a RunnerException that contains
* the location of the error, or if nothing is found, just return with a
* RunnerException that wraps the error message itself.
*/
RunnerException findException(String message, ThreadReference thread) {
try {
// use to dump the stack for debugging
// for (StackFrame frame : thread.frames()) {
// System.out.println("frame: " + frame);
// }
// Any of the thread.blah() methods can throw an AbsentInformationEx
// if that bit of data is missing. If so, just write out the error
// message to the console.
List<StackFrame> frames = thread.frames(); List<StackFrame> frames = thread.frames();
for (StackFrame frame : frames) { for (StackFrame frame : frames) {
// System.out.println("frame: " + frame); try {
Location location = frame.location(); Location location = frame.location();
String filename = null; String filename = null;
filename = location.sourceName(); filename = location.sourceName();
lineNumber = location.lineNumber(); int lineNumber = location.lineNumber() - 1;
RunnerException rex =
String appletJavaFile = appletClassName + ".java"; sketch.placeException(message, filename, lineNumber);
SketchCode errorCode = null; if (rex != null) {
if (filename.equals(appletJavaFile)) { return rex;
for (SketchCode code : sketch.getCode()) {
if (code.isExtension("pde")) {
if (lineNumber >= code.getPreprocOffset()) {
errorCode = code;
}
}
}
} else {
for (SketchCode code : sketch.getCode()) {
if (code.isExtension("java")) {
if (filename.equals(code.getFileName())) {
errorCode = code;
}
}
}
}
codeIndex = sketch.getCodeIndex(errorCode);
if (codeIndex != -1) {
//System.out.println("got line num " + lineNumber);
// in case this was a tab that got embedded into the main .java
lineNumber -= sketch.getCode(codeIndex).getPreprocOffset();
// lineNumber is 1-indexed, but editor wants zero-indexed
lineNumber--;
// getMessage() will be what's shown in the editor
exception = new RunnerException(message, codeIndex, lineNumber, -1);
exception.hideStackTrace();
listener.statusError(exception);
return;
}
} }
} catch (AbsentInformationException e) { } catch (AbsentInformationException e) {
// Any of the thread.blah() methods can throw an AbsentInformationEx
// if that bit of data is missing. If so, just write out the error
// message to the console.
//e.printStackTrace(); // not useful //e.printStackTrace(); // not useful
exception = new RunnerException(message); exception = new RunnerException(message);
exception.hideStackTrace(); exception.hideStackTrace();
listener.statusError(exception); listener.statusError(exception);
}
}
} catch (IncompatibleThreadStateException e) { } catch (IncompatibleThreadStateException e) {
// This shouldn't happen, but if it does, print the exception in case
// it's something that needs to be debugged separately.
e.printStackTrace(); e.printStackTrace();
} }
// Give up, nothing found inside the pile of stack frames
RunnerException rex = new RunnerException(message);
// exception is being created /here/, so stack trace is not useful
rex.hideStackTrace();
return rex;
} }
@ -727,25 +607,6 @@ public class Runner implements MessageConsumer {
} }
vm = null; vm = null;
} }
//if (window != null) window.hide();
// if (window != null) {
// //System.err.println("disposing window");
// window.dispose();
// window = null;
// }
/*
if (process != null) {
try {
process.destroy();
} catch (Exception e) {
//System.err.println("(ignored) error while destroying");
//e.printStackTrace();
}
process = null;
}
*/
} }
@ -762,7 +623,10 @@ public class Runner implements MessageConsumer {
// that signals that the applet has been quit. // that signals that the applet has been quit.
if (s.indexOf(PApplet.EXTERNAL_STOP) == 0) { if (s.indexOf(PApplet.EXTERNAL_STOP) == 0) {
//System.out.println("external: quit"); //System.out.println("external: quit");
editor.internalCloseRunner(); if (editor != null) {
//editor.internalCloseRunner(); // [091124]
editor.handleStop();
}
return; return;
} }
@ -773,281 +637,23 @@ public class Runner implements MessageConsumer {
int space = nums.indexOf(' '); int space = nums.indexOf(' ');
int left = Integer.parseInt(nums.substring(0, space)); int left = Integer.parseInt(nums.substring(0, space));
int top = Integer.parseInt(nums.substring(space + 1)); int top = Integer.parseInt(nums.substring(space + 1));
// this is only fired when connected to an editor
editor.setSketchLocation(new Point(left, top)); editor.setSketchLocation(new Point(left, top));
//System.out.println("external: move to " + left + " " + top); //System.out.println("external: move to " + left + " " + top);
return; return;
} }
// Removed while doing cleaning for 0145,
// it seems that this is never actually printed out.
/*
// this is PApplet sending a message saying "i'm about to spew
// a stack trace because an error occurred during PApplet.run()"
if (s.indexOf(PApplet.LEECH_WAKEUP) == 0) {
// newMessage being set to 'true' means that the next time
// message() is called, expect the first line of the actual
// error message & stack trace to be sent from the applet.
newMessage = true;
return; // this line ignored
}
*/
// these are used for debugging, in case there are concerns // these are used for debugging, in case there are concerns
// that some errors aren't coming through properly // that some errors aren't coming through properly
/* // if (s.length() > 2) {
if (s.length() > 2) { // System.err.println(newMessage);
System.err.println(newMessage); // System.err.println("message " + s.length() + ":" + s);
System.err.println("message " + s.length() + ":" + s); // }
}
*/
// always shove out the mesage, since it might not fall under // always shove out the mesage, since it might not fall under
// the same setup as we're expecting // the same setup as we're expecting
System.err.print(s); System.err.print(s);
//System.err.println("[" + s.length() + "] " + s); //System.err.println("[" + s.length() + "] " + s);
System.err.flush(); System.err.flush();
// // exit here because otherwise the exception name
// // may be titled with a blank string
// if (s.trim().length() == 0) return;
//
// // annoying, because it seems as though the terminators
// // aren't being sent properly
// //System.err.println(s);
//
// //if (newMessage && s.length() > 2) {
// if (newMessage) {
// exception = new RunnerException(s); // type of java ex
// exception.hideStackTrace();
// //System.out.println("setting ex type to " + s);
// newMessage = false;
// foundMessageSource = false;
// messageLineCount = 0;
//
// } else {
// messageLineCount++;
//
// /*
//java.lang.NullPointerException
// at javatest.<init>(javatest.java:5)
// at Temporary_2425_1153.draw(Temporary_2425_1153.java:11)
// at PApplet.nextFrame(PApplet.java:481)
// at PApplet.run(PApplet.java:428)
// at java.lang.Thread.run(Unknown Source)
// */
//
// if (!foundMessageSource) {
// // " at javatest.<init>(javatest.java:5)"
// // -> "javatest.<init>(javatest.java:5)"
// int atIndex = s.indexOf("at ");
// if (atIndex == -1) {
// //System.err.println(s); // stop double-printing exceptions
// return;
// }
// s = s.substring(atIndex + 3);
//
// // added for 0124 to improve error handling
// // not highlighting lines if it's in the p5 code
// if (s.startsWith("processing.")) return;
// // no highlight if it's java.lang.whatever
// if (s.startsWith("java.")) return;
//
// // "javatest.<init>(javatest.java:5)"
// // -> "javatest.<init>" and "(javatest.java:5)"
// int startParen = s.indexOf('(');
// // at javatest.<init>(javatest.java:5)
// //String pkgClassFxn = null;
// //String fileLine = null;
// int codeIndex = -1;
// int lineNumber = -1;
//
// if (startParen == -1) {
// //pkgClassFxn = s;
//
// } else {
// //pkgClassFxn = s.substring(0, startParen);
//
// // "(javatest.java:5)"
// String fileAndLine = s.substring(startParen + 1);
// int stopParen = fileAndLine.indexOf(')');
// //fileAndLine = fileAndLine.substring(0, fileAndLine.length() - 1);
// fileAndLine = fileAndLine.substring(0, stopParen);
// //System.out.println("file 'n line " + fileAndLine);
//
// //if (!fileAndLine.equals("Unknown Source")) {
// // "javatest.java:5"
// int colonIndex = fileAndLine.indexOf(':');
// if (colonIndex != -1) {
// String filename = fileAndLine.substring(0, colonIndex);
// // "javatest.java" and "5"
// //System.out.println("filename = " + filename);
// //System.out.println("pre0 = " + sketch.code[0].preprocName);
// //for (int i = 0; i < sketch.codeCount; i++) {
// //System.out.println(i + " " + sketch.code[i].lineOffset + " " +
// // sketch.code[i].preprocName);
// //}
// lineNumber =
// Integer.parseInt(fileAndLine.substring(colonIndex + 1)) - 1;
//
// for (int i = 0; i < sketch.getCodeCount(); i++) {
// SketchCode code = sketch.getCode(i);
// //System.out.println(code.preprocName + " " + lineNumber + " " +
// // code.preprocOffset);
// if (((code.preprocName == null) &&
// (lineNumber >= code.preprocOffset)) ||
// ((code.preprocName != null) &&
// code.preprocName.equals(filename))) {
// codeIndex = i;
// //System.out.println("got codeindex " + codeIndex);
// //break;
// //} else if (
// }
// }
//
// if (codeIndex != -1) {
// //System.out.println("got line num " + lineNumber);
// // in case this was a tab that got embedded into the main .java
// lineNumber -= sketch.getCode(codeIndex).preprocOffset;
//
// // this may have a paren on the end, if so need to strip
// // down to just the digits
// /*
// int lastNumberIndex = colonIndex + 1;
// while ((lastNumberIndex < fileAndLine.length()) &&
// Character.isDigit(fileAndLine.charAt(lastNumberIndex))) {
// lastNumberIndex++;
// }
// */
//
// // lineNumber is 1-indexed, but editor wants zero-indexed
// // getMessage() will be what's shown in the editor
// exception =
// new RunnerException(exception.getMessage(),
// codeIndex, lineNumber, -1);
// exception.hideStackTrace();
// foundMessageSource = true;
// }
// }
// }
// editor.error(exception);
//
// /*
// int index = s.indexOf(className + ".java");
// if (index != -1) {
// int len = (className + ".java").length();
// String lineNumberStr = s.substring(index + len + 1);
// index = lineNumberStr.indexOf(')');
// lineNumberStr = lineNumberStr.substring(0, index);
// try {
// exception.line = Integer.parseInt(lineNumberStr) - 1; //2;
// } catch (NumberFormatException e) { }
// //e.printStackTrace(); // a recursive error waiting to happen?
// // if nfe occurs, who cares, still send the error on up
// editor.error(exception);
// */
//
// /*
// // WARNING THESE ARE DISABLED!!
// } else if ((index = s.indexOf(className + ".class")) != -1) {
// // code to check for:
// // at Temporary_484_3845.loop(Compiled Code)
// // would also probably get:
// // at Temporary_484_3845.loop
// // which (i believe) is used by the mac and/or jview
// String functionStr = s.substring(index +
// (className + ".class").length() + 1);
// index = functionStr.indexOf('(');
// if (index != -1) {
// functionStr = functionStr.substring(0, index);
// }
// exception = new RunnerException(//"inside \"" + functionStr + "()\": " +
// exception.getMessage() +
// " inside " + functionStr + "() " +
// "[add Compiler.disable() to setup()]");
// editor.error(exception);
// // this will fall through in tihs example:
// // at Temporary_4636_9696.pootie(Compiled Code)
// // at Temporary_4636_9696.loop(Temporary_4636_9696.java:24)
// // because pootie() (re)sets the exception title
// // and throws it, but then the line number gets set
// // because of the line that comes after
// */
//
// } else if (messageLineCount > 10) { // 5 -> 10 for 0088
// // this means the class name may not be mentioned
// // in the stack trace.. this is just a general purpose
// // error, but needs to make it through anyway.
// // so if five lines have gone past, might as well signal
// messageLineCount = -100;
// exception = new RunnerException(exception.getMessage());
// exception.hideStackTrace();
// editor.error(exception);
//
// } else {
// //System.err.print(s);
// }
// //System.out.println("got it " + s);
// }
}
//////////////////////////////////////////////////////////////
/**
* Siphons from an InputStream of System.out (from a Process)
* and sends it to the real System.out.
*/
class SystemOutSiphon implements Runnable {
InputStream input;
Thread thread;
public SystemOutSiphon(InputStream input) {
this.input = input;
thread = new Thread(this);
// unless this is set to min, it seems to hork the app
// since it's in charge of stuffing the editor console with strings
// maybe it's time to get rid of/fix that friggin console
// ...disabled for 0075, with 0074's fix for code folder hanging
// this only seems to make the console unresponsive
//thread.setPriority(Thread.MIN_PRIORITY);
thread.start();
}
public void run() {
byte boofer[] = new byte[256];
while (Thread.currentThread() == thread) {
try {
// can't use a buffered reader here because incremental
// print statements are interesting too.. causes some
// disparity with how System.err gets spewed, oh well.
int count = input.read(boofer, 0, boofer.length);
if (count == -1) {
thread = null;
} else {
System.out.print(new String(boofer, 0, count));
//System.out.flush();
}
} catch (IOException e) {
// this is prolly because the app was quit & the stream broken
//e.printStackTrace(System.out);
//e.printStackTrace();
thread = null;
} catch (Exception e) {
//System.out.println("SystemOutSiphon: i just died in your arms tonight");
// on mac os x, this will spew a "Bad File Descriptor" ex
// each time an external app is shut down.
//e.printStackTrace();
thread = null;
//System.out.println("");
}
//System.out.println("SystemOutSiphon: out");
//thread = null;
}
}
} }
} }

View File

@ -37,7 +37,15 @@ public class RunnerException extends Exception /*RuntimeException*/ {
public RunnerException(String message) { public RunnerException(String message) {
this(message, -1, -1, -1, true); this(message, true);
}
public RunnerException(String message, boolean showStackTrace) {
this(message, -1, -1, -1, showStackTrace);
}
public RunnerException(String message, int file, int line) {
this(message, file, line, -1, true);
} }

View File

@ -28,4 +28,6 @@ public interface RunnerListener {
public void statusError(String message); public void statusError(String message);
public void statusError(Exception exception); public void statusError(Exception exception);
public void statusNotice(String message);
} }

View File

@ -67,10 +67,18 @@ public class Platform extends processing.app.Platform {
return true; return true;
} }
// Attempt to use xdg-open
try {
Process p = Runtime.getRuntime().exec(new String[] { "xdg-open" });
p.waitFor();
Preferences.set("launcher", "xdg-open");
return true;
} catch (Exception e) { }
// Attempt to use gnome-open // Attempt to use gnome-open
try { try {
Process p = Runtime.getRuntime().exec(new String[] { "gnome-open" }); Process p = Runtime.getRuntime().exec(new String[] { "gnome-open" });
/*int result =*/ p.waitFor(); p.waitFor();
// Not installed will throw an IOException (JDK 1.4.2, Ubuntu 7.04) // Not installed will throw an IOException (JDK 1.4.2, Ubuntu 7.04)
Preferences.set("launcher", "gnome-open"); Preferences.set("launcher", "gnome-open");
return true; return true;
@ -79,7 +87,7 @@ public class Platform extends processing.app.Platform {
// Attempt with kde-open // Attempt with kde-open
try { try {
Process p = Runtime.getRuntime().exec(new String[] { "kde-open" }); Process p = Runtime.getRuntime().exec(new String[] { "kde-open" });
/*int result =*/ p.waitFor(); p.waitFor();
Preferences.set("launcher", "kde-open"); Preferences.set("launcher", "kde-open");
return true; return true;
} catch (Exception e) { } } catch (Exception e) { }
@ -100,7 +108,8 @@ public class Platform extends processing.app.Platform {
e.printStackTrace(); e.printStackTrace();
} }
} else { } else {
System.out.println("not available"); System.out.println("No launcher set, cannot open " +
file.getAbsolutePath());
} }
} }
} }

View File

@ -25,12 +25,15 @@ package processing.app.macosx;
import java.awt.Insets; import java.awt.Insets;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.lang.reflect.Method;
import java.net.URI;
import javax.swing.UIManager; import javax.swing.UIManager;
import com.apple.eio.FileManager; import com.apple.eio.FileManager;
import processing.app.Base; import processing.app.Base;
import processing.core.PApplet;
/** /**
@ -103,35 +106,44 @@ public class Platform extends processing.app.Platform {
public void openURL(String url) throws Exception { public void openURL(String url) throws Exception {
if (!url.startsWith("http://")) { if (PApplet.javaVersion < 1.6f) {
if (url.startsWith("http://")) {
// formerly com.apple.eio.FileManager.openURL(url);
// but due to deprecation, instead loading dynamically
try {
Class<?> eieio = Class.forName("com.apple.eio.FileManager");
Method openMethod =
eieio.getMethod("openURL", new Class[] { String.class });
openMethod.invoke(null, new Object[] { url });
} catch (Exception e) {
e.printStackTrace();
}
} else {
// Assume this is a file instead, and just open it. // Assume this is a file instead, and just open it.
// Extension of http://dev.processing.org/bugs/show_bug.cgi?id=1010 // Extension of http://dev.processing.org/bugs/show_bug.cgi?id=1010
processing.core.PApplet.open(url); processing.core.PApplet.open(url);
}
/*
// prepend file:// on this guy since it's a file
url = "file://" + url;
// replace spaces with %20 for the file url
// otherwise the mac doesn't like to open it
// can't just use URLEncoder, since that makes slashes into
// %2F characters, which is no good. some might say "useless"
if (url.indexOf(' ') != -1) {
StringBuffer sb = new StringBuffer();
char c[] = url.toCharArray();
for (int i = 0; i < c.length; i++) {
if (c[i] == ' ') {
sb.append("%20");
} else { } else {
sb.append(c[i]); try {
Class<?> desktopClass = Class.forName("java.awt.Desktop");
Method getMethod = desktopClass.getMethod("getDesktop");
Object desktop = getMethod.invoke(null, new Object[] { });
// for Java 1.6, replacing with java.awt.Desktop.browse()
// and java.awt.Desktop.open()
if (url.startsWith("http://")) { // browse to a location
Method browseMethod =
desktopClass.getMethod("browse", new Class[] { URI.class });
browseMethod.invoke(desktop, new Object[] { new URI(url) });
} else { // open a file
Method openMethod =
desktopClass.getMethod("open", new Class[] { File.class });
openMethod.invoke(desktop, new Object[] { new File(url) });
}
} catch (Exception e) {
e.printStackTrace();
} }
} }
url = sb.toString();
}
*/
}
// for Java 1.6, replace with java.awt.Desktop.browse() and java.awt.Desktop.open()
com.apple.eio.FileManager.openURL(url);
} }

View File

@ -50,7 +50,8 @@ public class ThinkDifferent implements ApplicationListener {
static protected void init(Base base) { static protected void init(Base base) {
if (application == null) { if (application == null) {
application = new com.apple.eawt.Application(); //application = new com.apple.eawt.Application();
application = com.apple.eawt.Application.getApplication();
} }
if (adapter == null) { if (adapter == null) {
adapter = new ThinkDifferent(base); adapter = new ThinkDifferent(base);

View File

@ -51,15 +51,9 @@ public class PdePreprocessor {
List prototypes; List prototypes;
String[] defaultImports;
// these ones have the .* at the end, since a class name might be at the end // these ones have the .* at the end, since a class name might be at the end
// instead of .* which would make trouble other classes using this can lop // instead of .* which would make trouble other classes using this can lop
// off the . and anything after it to produce a package name consistently. // off the . and anything after it to produce a package name consistently.
//public String extraImports[];
ArrayList<String> programImports; ArrayList<String> programImports;
// imports just from the code folder, treated differently // imports just from the code folder, treated differently
@ -71,24 +65,24 @@ public class PdePreprocessor {
PrintStream stream; PrintStream stream;
String program; String program;
String buildPath; String buildPath;
// starts as sketch name, ends as main class name
String name; String name;
/** /**
* Setup a new preprocessor. * Setup a new preprocessor.
*/ */
public PdePreprocessor() { } public PdePreprocessor() {
public int writePrefix(String program, String buildPath,
String name, String codeFolderPackages[])
throws FileNotFoundException {
this.buildPath = buildPath;
this.name = name;
int tabSize = Preferences.getInteger("editor.tabs.size"); int tabSize = Preferences.getInteger("editor.tabs.size");
char[] indentChars = new char[tabSize]; char[] indentChars = new char[tabSize];
Arrays.fill(indentChars, ' '); Arrays.fill(indentChars, ' ');
indent = new String(indentChars); indent = new String(indentChars);
}
public int writePrefix(String program, String buildPath,
String sketchName, String codeFolderPackages[]) throws FileNotFoundException {
this.buildPath = buildPath;
this.name = sketchName;
// if the program ends with no CR or LF an OutOfMemoryError will happen. // if the program ends with no CR or LF an OutOfMemoryError will happen.
// not gonna track down the bug now, so here's a hack for it: // not gonna track down the bug now, so here's a hack for it:
@ -99,51 +93,12 @@ public class PdePreprocessor {
// an OutOfMemoryError or NullPointerException will happen. // an OutOfMemoryError or NullPointerException will happen.
// again, not gonna bother tracking this down, but here's a hack. // again, not gonna bother tracking this down, but here's a hack.
// http://dev.processing.org/bugs/show_bug.cgi?id=16 // http://dev.processing.org/bugs/show_bug.cgi?id=16
Sketch.scrubComments(program); String scrubbed = Sketch.scrubComments(program);
// this returns the scrubbed version, but more important for this // If there are errors, an exception is thrown and this fxn exits.
// function, it'll check to see if there are errors with the comments.
if (Preferences.getBoolean("preproc.substitute_unicode")) { if (Preferences.getBoolean("preproc.substitute_unicode")) {
// check for non-ascii chars (these will be/must be in unicode format) program = substituteUnicode(program);
char p[] = program.toCharArray();
int unicodeCount = 0;
for (int i = 0; i < p.length; i++) {
if (p[i] > 127) unicodeCount++;
} }
// if non-ascii chars are in there, convert to unicode escapes
if (unicodeCount != 0) {
// add unicodeCount * 5.. replacing each unicode char
// with six digit uXXXX sequence (xxxx is in hex)
// (except for nbsp chars which will be a replaced with a space)
int index = 0;
char p2[] = new char[p.length + unicodeCount*5];
for (int i = 0; i < p.length; i++) {
if (p[i] < 128) {
p2[index++] = p[i];
} else if (p[i] == 160) { // unicode for non-breaking space
p2[index++] = ' ';
} else {
int c = p[i];
p2[index++] = '\\';
p2[index++] = 'u';
char str[] = Integer.toHexString(c).toCharArray();
// add leading zeros, so that the length is 4
//for (int i = 0; i < 4 - str.length; i++) p2[index++] = '0';
for (int m = 0; m < 4 - str.length; m++) p2[index++] = '0';
System.arraycopy(str, 0, p2, index, str.length);
index += str.length;
}
}
program = new String(p2, 0, index);
}
}
// These may change in-between (if the prefs panel adds this option)
// so grab them here on construction.
String prefsLine = Preferences.get("preproc.imports");
defaultImports = PApplet.splitTokens(prefsLine, ", ");
//String importRegexp = "(?:^|\\s|;)(import\\s+)(\\S+)(\\s*;)"; //String importRegexp = "(?:^|\\s|;)(import\\s+)(\\S+)(\\s*;)";
String importRegexp = "^\\s*#include\\s+[<\"](\\S+)[\">]"; String importRegexp = "^\\s*#include\\s+[<\"](\\S+)[\">]";
@ -184,8 +139,47 @@ public class PdePreprocessor {
return headerCount + prototypeCount; return headerCount + prototypeCount;
} }
static String substituteUnicode(String program) {
// check for non-ascii chars (these will be/must be in unicode format)
char p[] = program.toCharArray();
int unicodeCount = 0;
for (int i = 0; i < p.length; i++) {
if (p[i] > 127) unicodeCount++;
}
// if non-ascii chars are in there, convert to unicode escapes
if (unicodeCount != 0) {
// add unicodeCount * 5.. replacing each unicode char
// with six digit uXXXX sequence (xxxx is in hex)
// (except for nbsp chars which will be a replaced with a space)
int index = 0;
char p2[] = new char[p.length + unicodeCount*5];
for (int i = 0; i < p.length; i++) {
if (p[i] < 128) {
p2[index++] = p[i];
} else if (p[i] == 160) { // unicode for non-breaking space
p2[index++] = ' ';
} else {
int c = p[i];
p2[index++] = '\\';
p2[index++] = 'u';
char str[] = Integer.toHexString(c).toCharArray();
// add leading zeros, so that the length is 4
//for (int i = 0; i < 4 - str.length; i++) p2[index++] = '0';
for (int m = 0; m < 4 - str.length; m++) p2[index++] = '0';
System.arraycopy(str, 0, p2, index, str.length);
index += str.length;
}
}
program = new String(p2, 0, index);
}
return program;
}
/** /**
* preprocesses a pde file and write out a java file * preprocesses a pde file and writes out a java file
* @return the classname of the exported Java * @return the classname of the exported Java
*/ */
//public String write(String program, String buildPath, String name, //public String write(String program, String buildPath, String name,

View File

@ -24,7 +24,7 @@ import java.util.*;
* to the implementations of this class to do so. * to the implementations of this class to do so.
* *
* @author Slava Pestov * @author Slava Pestov
* @version $Id: InputHandler.java 4168 2008-08-09 17:24:37Z fry $ * @version $Id: InputHandler.java 6126 2010-02-16 23:43:53Z fry $
*/ */
public abstract class InputHandler extends KeyAdapter public abstract class InputHandler extends KeyAdapter
{ {
@ -70,6 +70,9 @@ public abstract class InputHandler extends KeyAdapter
public static final ActionListener SELECT_PREV_WORD = new prev_word(true); public static final ActionListener SELECT_PREV_WORD = new prev_word(true);
public static final ActionListener REPEAT = new repeat(); public static final ActionListener REPEAT = new repeat();
public static final ActionListener TOGGLE_RECT = new toggle_rect(); public static final ActionListener TOGGLE_RECT = new toggle_rect();
public static final ActionListener CLIPBOARD_CUT = new clipboard_cut(); // [fry]
public static final ActionListener CLIPBOARD_COPY = new clipboard_copy();
public static final ActionListener CLIPBOARD_PASTE = new clipboard_paste();
// Default action // Default action
public static final ActionListener INSERT_CHAR = new insert_char(); public static final ActionListener INSERT_CHAR = new insert_char();
@ -113,6 +116,9 @@ public abstract class InputHandler extends KeyAdapter
actions.put("repeat",REPEAT); actions.put("repeat",REPEAT);
actions.put("toggle-rect",TOGGLE_RECT); actions.put("toggle-rect",TOGGLE_RECT);
actions.put("insert-char",INSERT_CHAR); actions.put("insert-char",INSERT_CHAR);
actions.put("clipboard-cut",CLIPBOARD_CUT);
actions.put("clipboard-copy",CLIPBOARD_COPY);
actions.put("clipboard-paste",CLIPBOARD_PASTE);
} }
/** /**
@ -1077,6 +1083,34 @@ public abstract class InputHandler extends KeyAdapter
} }
} }
public static class clipboard_cut implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
getTextArea(evt).cut();
}
}
public static class clipboard_copy implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
getTextArea(evt).copy();
}
}
public static class clipboard_paste implements ActionListener
{
public void actionPerformed(ActionEvent evt)
{
getTextArea(evt).paste();
}
}
public static class insert_char implements ActionListener, public static class insert_char implements ActionListener,
InputHandler.NonRepeatable InputHandler.NonRepeatable
{ {

View File

@ -22,6 +22,9 @@ import java.awt.event.*;
import java.awt.*; import java.awt.*;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.Vector; import java.util.Vector;
import java.awt.im.InputMethodRequests;
import processing.app.syntax.im.InputMethodSupport;
/** /**
* jEdit's text area component. It is more suited for editing program * jEdit's text area component. It is more suited for editing program
@ -51,7 +54,7 @@ import java.util.Vector;
* + "}");</pre> * + "}");</pre>
* *
* @author Slava Pestov * @author Slava Pestov
* @version $Id: JEditTextArea.java 5625 2009-06-07 21:08:59Z fry $ * @version $Id: JEditTextArea.java 6123 2010-02-16 21:43:44Z fry $
*/ */
public class JEditTextArea extends JComponent public class JEditTextArea extends JComponent
{ {
@ -127,6 +130,16 @@ public class JEditTextArea extends JComponent
}); });
} }
/**
* Inline Input Method Support for Japanese.
*/
private InputMethodSupport inputMethodSupport = null;
public InputMethodRequests getInputMethodRequests() {
if (inputMethodSupport == null) {
inputMethodSupport = new InputMethodSupport(this);
}
return inputMethodSupport;
}
/** /**
* Get current position of the vertical scroll bar. [fry] * Get current position of the vertical scroll bar. [fry]

View File

@ -34,18 +34,22 @@ public class PdeTextAreaDefaults extends TextAreaDefaults {
inputHandler = new DefaultInputHandler(); inputHandler = new DefaultInputHandler();
//inputHandler.addDefaultKeyBindings(); // 0122 //inputHandler.addDefaultKeyBindings(); // 0122
// use option on mac for things that are ctrl on windows/linux // use option on mac for text edit controls that are ctrl on windows/linux
String mod = Base.isMacOS() ? "A" : "C"; String mod = Base.isMacOS() ? "A" : "C";
// right now, ctrl-up/down is select up/down, but mod should be // right now, ctrl-up/down is select up/down, but mod should be
// used instead, because the mac expects it to be option(alt) // used instead, because the mac expects it to be option(alt)
inputHandler.addKeyBinding("BACK_SPACE", InputHandler.BACKSPACE); inputHandler.addKeyBinding("BACK_SPACE", InputHandler.BACKSPACE);
inputHandler.addKeyBinding("DELETE", InputHandler.DELETE); // for 0122, shift-backspace is delete, for 0176, it's now a preference,
// to prevent holy warriors from attacking me for it.
//inputHandler.addKeyBinding("S+BACK_SPACE", InputHandler.BACKSPACE); if (Preferences.getBoolean("editor.keys.shift_backspace_is_delete")) {
// for 0122, shift-backspace is delete
inputHandler.addKeyBinding("S+BACK_SPACE", InputHandler.DELETE); inputHandler.addKeyBinding("S+BACK_SPACE", InputHandler.DELETE);
} else {
inputHandler.addKeyBinding("S+BACK_SPACE", InputHandler.BACKSPACE);
}
inputHandler.addKeyBinding("DELETE", InputHandler.DELETE);
inputHandler.addKeyBinding("S+DELETE", InputHandler.DELETE); inputHandler.addKeyBinding("S+DELETE", InputHandler.DELETE);
// the following two were changing for 0122 for better mac/pc compatability // the following two were changing for 0122 for better mac/pc compatability
@ -57,12 +61,23 @@ public class PdeTextAreaDefaults extends TextAreaDefaults {
//inputHandler.addKeyBinding("TAB", InputHandler.INSERT_TAB); //inputHandler.addKeyBinding("TAB", InputHandler.INSERT_TAB);
inputHandler.addKeyBinding("INSERT", InputHandler.OVERWRITE); inputHandler.addKeyBinding("INSERT", InputHandler.OVERWRITE);
// http://dev.processing.org/bugs/show_bug.cgi?id=162
// added for 0176, though the bindings do not appear relevant for osx
if (Preferences.getBoolean("editor.keys.alternative_cut_copy_paste")) {
inputHandler.addKeyBinding("C+INSERT", InputHandler.CLIPBOARD_COPY);
inputHandler.addKeyBinding("S+INSERT", InputHandler.CLIPBOARD_PASTE);
inputHandler.addKeyBinding("S+DELETE", InputHandler.CLIPBOARD_CUT);
}
// disabling for 0122, not sure what this does // disabling for 0122, not sure what this does
//inputHandler.addKeyBinding("C+\\", InputHandler.TOGGLE_RECT); //inputHandler.addKeyBinding("C+\\", InputHandler.TOGGLE_RECT);
// for 0122, these have been changed for better compatability // for 0122, these have been changed for better compatibility
// HOME and END now mean the beginning/end of the document // HOME and END now mean the beginning/end of the document
if (Base.isMacOS()) { // for 0176 changed this to a preference so that the Mac OS X people
// can get the "normal" behavior as well if they prefer.
if (Preferences.getBoolean("editor.keys.home_and_end_travel_far")) {
inputHandler.addKeyBinding("HOME", InputHandler.DOCUMENT_HOME); inputHandler.addKeyBinding("HOME", InputHandler.DOCUMENT_HOME);
inputHandler.addKeyBinding("END", InputHandler.DOCUMENT_END); inputHandler.addKeyBinding("END", InputHandler.DOCUMENT_END);
inputHandler.addKeyBinding("S+HOME", InputHandler.SELECT_DOC_HOME); inputHandler.addKeyBinding("S+HOME", InputHandler.SELECT_DOC_HOME);

View File

@ -12,6 +12,7 @@
package processing.app.syntax; package processing.app.syntax;
import processing.app.*; import processing.app.*;
import processing.app.syntax.im.CompositionTextPainter;
import javax.swing.ToolTipManager; import javax.swing.ToolTipManager;
import javax.swing.text.*; import javax.swing.text.*;
@ -33,6 +34,9 @@ implements TabExpander, Printable
/** Current setting for editor.antialias preference */ /** Current setting for editor.antialias preference */
boolean antialias; boolean antialias;
/** A specific painter composed by the InputMethod.*/
protected CompositionTextPainter compositionTextPainter;
/** /**
* Creates a new repaint manager. This should be not be called * Creates a new repaint manager. This should be not be called
* directly. * directly.
@ -73,6 +77,16 @@ implements TabExpander, Printable
eolMarkers = defaults.eolMarkers; eolMarkers = defaults.eolMarkers;
} }
/**
* Get CompositionTextPainter. if CompositionTextPainter is not created, create it.
*/
public CompositionTextPainter getCompositionTextpainter(){
if(compositionTextPainter == null){
compositionTextPainter = new CompositionTextPainter(textArea);
}
return compositionTextPainter;
}
/** /**
* Returns if this component can be traversed by pressing the * Returns if this component can be traversed by pressing the
* Tab key. This returns false. * Tab key. This returns false.
@ -602,7 +616,12 @@ implements TabExpander, Printable
y += fm.getHeight(); y += fm.getHeight();
x = Utilities.drawTabbedText(currentLine,x,y,gfx,this,0); x = Utilities.drawTabbedText(currentLine,x,y,gfx,this,0);
/*
* Draw characters via input method.
*/
if (compositionTextPainter != null && compositionTextPainter.hasComposedTextLayout()) {
compositionTextPainter.draw(gfx, lineHighlightColor);
}
if (eolMarkers) { if (eolMarkers) {
gfx.setColor(eolMarkerColor); gfx.setColor(eolMarkerColor);
gfx.drawString(".",x,y); gfx.drawString(".",x,y);
@ -625,7 +644,12 @@ implements TabExpander, Printable
x = SyntaxUtilities.paintSyntaxLine(currentLine, x = SyntaxUtilities.paintSyntaxLine(currentLine,
currentLineTokens, currentLineTokens,
styles, this, gfx, x, y); styles, this, gfx, x, y);
/*
* Draw characters via input method.
*/
if (compositionTextPainter != null && compositionTextPainter.hasComposedTextLayout()) {
compositionTextPainter.draw(gfx, lineHighlightColor);
}
if (eolMarkers) { if (eolMarkers) {
gfx.setColor(eolMarkerColor); gfx.setColor(eolMarkerColor);
gfx.drawString(".",x,y); gfx.drawString(".",x,y);

View File

@ -0,0 +1,187 @@
package processing.app.syntax.im;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.font.FontRenderContext;
import java.awt.font.TextAttribute;
import java.awt.font.TextLayout;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
import javax.swing.text.BadLocationException;
import processing.app.syntax.JEditTextArea;
import processing.app.syntax.TextAreaPainter;
/**
* This class Manage texts from input method
* by begin-process-end steps.
*
* First, if a user start inputing via input method,
* beginCompositionText is called from InputMethodSupport.
* Second, the user continues from input method, processCompositionText is called
* and reflect user inputs to text area.
* Finally the user try to commit text, endCompositionText is called.
*
* @author Takashi Maekawa (takachin@generative.info)
*/
public class CompositionTextManager {
private JEditTextArea textArea;
private String prevComposeString;
private int prevCommittedCount;
private boolean isInputProcess;
private int initialCaretPosition;
public static final int COMPOSING_UNDERBAR_HEIGHT = 5;
/**
* Create text manager class with a textarea.
* @param textArea texarea component for PDE.
*/
public CompositionTextManager(JEditTextArea textArea) {
this.textArea = textArea;
prevComposeString = "";
isInputProcess = false;
prevCommittedCount = 0;
}
/**
* Get this text manager is whether in input process or not.
*/
public boolean getIsInputProcess() {
return isInputProcess;
}
/**
* Called when a user begins input from input method.
* This method initializes text manager.
*
* @param text Text from InputMethodEvent.
* @param commited_count Numbers of committed characters in text.
*/
public void beginCompositionText(AttributedCharacterIterator text, int committed_count) {
isInputProcess = true;
prevComposeString = "";
initialCaretPosition = textArea.getCaretPosition();
processCompositionText(text, committed_count);
}
/**
* Called when a user processing input characters and
* select candidates from input method.
*
* @param text Text from InputMethodEvent.
* @param commited_count Numbers of committed characters in text.
*/
public void processCompositionText(AttributedCharacterIterator text, int committed_count) {
int layoutCaretPosition = initialCaretPosition + committed_count;
CompositionTextPainter compositionPainter = textArea.getPainter().getCompositionTextpainter();
compositionPainter.setComposedTextLayout(getTextLayout(text, committed_count), layoutCaretPosition);
int textLength = text.getEndIndex() - text.getBeginIndex() - committed_count;
StringBuffer unCommitedStringBuf = new StringBuffer(textLength);
char c;
for (c = text.setIndex(committed_count); c != AttributedCharacterIterator.DONE
&& textLength > 0; c = text.next(), --textLength) {
unCommitedStringBuf.append(c);
}
String unCommittedString = unCommitedStringBuf.toString();
try {
if(canRemovePreviousInput(committed_count)){
textArea.getDocument().remove(layoutCaretPosition, prevComposeString.length());
}
textArea.getDocument().insertString(layoutCaretPosition, unCommittedString, null);
if(committed_count > 0){
initialCaretPosition = initialCaretPosition + committed_count;
}
prevComposeString = unCommittedString;
prevCommittedCount = committed_count;
} catch (BadLocationException e) {
e.printStackTrace();
}
}
private boolean canRemovePreviousInput(int committed_count){
return (prevCommittedCount == committed_count || prevCommittedCount > committed_count);
}
/**
* Called when a user fixed text from input method or delete all
* composition text. This method resets CompositionTextPainter.
*
* @param text Text from InputMethodEvent.
* @param commited_count Numbers of committed characters in text.
*/
public void endCompositionText(AttributedCharacterIterator text, int committed_count) {
isInputProcess = false;
/*
* If there are no committed characters, remove it all from textarea.
* This case will happen if a user delete all composing characters by backspace or delete key.
* If it does, these previous characters are needed to be deleted.
*/
if(committed_count == 0){
removeNotCommittedText(text);
}
CompositionTextPainter compositionPainter = textArea.getPainter().getCompositionTextpainter();
compositionPainter.invalidateComposedTextLayout(initialCaretPosition + committed_count);
prevComposeString = "";
isInputProcess = false;
}
private void removeNotCommittedText(AttributedCharacterIterator text){
if (prevComposeString.length() == 0) {
return;
}
try {
textArea.getDocument().remove(initialCaretPosition, prevComposeString.length());
} catch (BadLocationException e) {
e.printStackTrace();
}
}
private TextLayout getTextLayout(AttributedCharacterIterator text, int committed_count) {
AttributedString composed = new AttributedString(text, committed_count, text.getEndIndex());
Font font = textArea.getPainter().getFont();
FontRenderContext context = ((Graphics2D) (textArea.getPainter().getGraphics())).getFontRenderContext();
composed.addAttribute(TextAttribute.FONT, font);
TextLayout layout = new TextLayout(composed.getIterator(), context);
return layout;
}
private Point getCaretLocation() {
Point loc = new Point();
TextAreaPainter painter = textArea.getPainter();
FontMetrics fm = painter.getFontMetrics();
int offsetY = fm.getHeight() - COMPOSING_UNDERBAR_HEIGHT;
int lineIndex = textArea.getCaretLine();
loc.y = lineIndex * fm.getHeight() + offsetY;
int offsetX = textArea.getCaretPosition()
- textArea.getLineStartOffset(lineIndex);
loc.x = textArea.offsetToX(lineIndex, offsetX);
return loc;
}
public Rectangle getTextLocation() {
Point caret = getCaretLocation();
return getCaretRectangle(caret.x, caret.y);
}
private Rectangle getCaretRectangle(int x, int y) {
TextAreaPainter painter = textArea.getPainter();
Point origin = painter.getLocationOnScreen();
int height = painter.getFontMetrics().getHeight();
return new Rectangle(origin.x + x, origin.y + y, 0, height);
}
public AttributedCharacterIterator getCommittedText(int beginIndex, int endIndex) {
int length = endIndex - beginIndex;
String textAreaString = textArea.getText(beginIndex, length);
return new AttributedString(textAreaString).getIterator();
}
public int getInsertPositionOffset() {
return textArea.getCaretPosition() * -1;
}
}

View File

@ -0,0 +1,124 @@
package processing.app.syntax.im;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.font.TextLayout;
import processing.app.syntax.JEditTextArea;
import processing.app.syntax.TextAreaPainter;
/**
* Paint texts from input method. Text via input method are transmitted by
* AttributedCaharacterIterator. This class helps the PDE's TextAreaPainter
* to handle AttributedCaharacterIterator.
*
* For practical purposes, paint to textarea is done by TextLayout class.
* Because TextLayout class is easy to draw composing texts. (For example,
* draw underline composing texts, focus when select from candidates text.)
*
* @author Takashi Maekawa (takachin@generative.info)
*/
public class CompositionTextPainter {
private TextLayout composedTextLayout;
private int composedBeginCaretPosition = 0;
private JEditTextArea textArea;
/**
* Constructor for painter.
* @param textarea textarea used by PDE.
*/
public CompositionTextPainter(JEditTextArea textArea) {
this.textArea = textArea;
composedTextLayout = null;
}
/**
* Check the painter has TextLayout.
* If a user input via InputMethod, this result will return true.
* @param textarea textarea used by PDE.
*/
public boolean hasComposedTextLayout() {
return (composedTextLayout != null);
}
/**
* Set TextLayout to the painter.
* TextLayout will be created and set by CompositionTextManager.
*
* @see CompositionTextManager
* @param textarea textarea used by PDE.
*/
public void setComposedTextLayout(TextLayout composedTextLayout, int composedStartCaretPosition) {
this.composedTextLayout = composedTextLayout;
this.composedBeginCaretPosition = composedStartCaretPosition;
}
/**
* Invalidate this TextLayout to set null.
* If a user end input via InputMethod, this method will called from CompositionTextManager.endCompositionText
*/
public void invalidateComposedTextLayout(int composedEndCaretPosition) {
this.composedTextLayout = null;
this.composedBeginCaretPosition = composedEndCaretPosition;
//this.composedBeginCaretPosition = textArea.getCaretPosition();
}
/**
* Draw text via input method with composed text information.
* This method can draw texts with some underlines to illustrate converting characters.
*
* This method is workaround for TextAreaPainter.
* Because, TextAreaPainter can't treat AttributedCharacterIterator directly.
* AttributedCharacterIterator has very important information when composing text.
* It has a map where are converted characters and committed characters.
* Ideally, changing TextAreaPainter method can treat AttributedCharacterIterator is better. But it's very tough!!
* So I choose to write some code as a workaround.
*
* This draw method is proceeded with the following steps.
* 1. Original TextAreaPainter draws characters.
* 2. This refillComposedArea method erase previous paint characters by textarea's background color.
* The refill area is only square that width and height defined by characters with input method.
* 3. CompositionTextPainter.draw method paints composed text. It was actually drawn by TextLayout.
*
* @param gfx set TextAreaPainter's Graphics object.
* @param fillBackGroundColor set textarea's background.
*/
public void draw(Graphics gfx, Color fillBackGroundColor) {
assert(composedTextLayout != null);
Point composedLoc = getCaretLocation();
refillComposedArea(fillBackGroundColor, composedLoc.x, composedLoc.y);
composedTextLayout.draw((Graphics2D) gfx, composedLoc.x, composedLoc.y);
}
/**
* Fill color to erase characters drawn by original TextAreaPainter.
*
* @param fillColor fill color to erase characters drawn by original TextAreaPainter method.
* @param x x-coordinate where to fill.
* @param y y-coordinate where to fill.
*/
private void refillComposedArea(Color fillColor, int x, int y) {
Graphics gfx = textArea.getPainter().getGraphics();
gfx.setColor(fillColor);
FontMetrics fm = textArea.getPainter().getFontMetrics();
int newY = y - (fm.getHeight() - CompositionTextManager.COMPOSING_UNDERBAR_HEIGHT);
int paintHeight = fm.getHeight();
int paintWidth = (int) composedTextLayout.getBounds().getWidth();
gfx.fillRect(x, newY, paintWidth, paintHeight);
}
private Point getCaretLocation() {
Point loc = new Point();
TextAreaPainter painter = textArea.getPainter();
FontMetrics fm = painter.getFontMetrics();
int offsetY = fm.getHeight() - CompositionTextManager.COMPOSING_UNDERBAR_HEIGHT;
int lineIndex = textArea.getCaretLine();
loc.y = lineIndex * fm.getHeight() + offsetY;
int offsetX = composedBeginCaretPosition - textArea.getLineStartOffset(lineIndex);
loc.x = textArea.offsetToX(lineIndex, offsetX);
return loc;
}
}

View File

@ -0,0 +1,105 @@
package processing.app.syntax.im;
import java.awt.Rectangle;
import java.awt.event.InputMethodEvent;
import java.awt.event.InputMethodListener;
import java.awt.font.TextHitInfo;
import java.awt.im.InputMethodRequests;
import java.text.AttributedCharacterIterator;
import processing.app.syntax.JEditTextArea;
/**
* Support in-line Japanese input for PDE. (Maybe Chinese, Korean and more)
* This class is implemented by Java Input Method Framework and handles
* If you would like to know more about Java Input Method Framework,
* Please see http://java.sun.com/j2se/1.5.0/docs/guide/imf/
*
* This class is implemented to fix Bug #854.
* http://dev.processing.org/bugs/show_bug.cgi?id=854
*
* @author Takashi Maekawa (takachin@generative.info)
*/
public class InputMethodSupport implements InputMethodRequests,
InputMethodListener {
private int committed_count = 0;
private CompositionTextManager textManager;
public InputMethodSupport(JEditTextArea textArea) {
textManager = new CompositionTextManager(textArea);
textArea.enableInputMethods(true);
textArea.addInputMethodListener(this);
}
public Rectangle getTextLocation(TextHitInfo offset) {
return textManager.getTextLocation();
}
public TextHitInfo getLocationOffset(int x, int y) {
return null;
}
public int getInsertPositionOffset() {
return textManager.getInsertPositionOffset();
}
public AttributedCharacterIterator getCommittedText(int beginIndex,
int endIndex, AttributedCharacterIterator.Attribute[] attributes) {
return textManager.getCommittedText(beginIndex, endIndex);
}
public int getCommittedTextLength() {
return committed_count;
}
public AttributedCharacterIterator cancelLatestCommittedText(
AttributedCharacterIterator.Attribute[] attributes) {
return null;
}
public AttributedCharacterIterator getSelectedText(
AttributedCharacterIterator.Attribute[] attributes) {
return null;
}
/**
* Handles events from InputMethod.
* This method judges whether beginning of input or
* progress of input or end and call related method.
*
* @param event event from Input Method.
*/
public void inputMethodTextChanged(InputMethodEvent event) {
AttributedCharacterIterator text = event.getText();
committed_count = event.getCommittedCharacterCount();
if(isBeginInputProcess(text, textManager)){
textManager.beginCompositionText(text, committed_count);
caretPositionChanged(event);
return;
}
if (isInputProcess(text)){
textManager.processCompositionText(text, committed_count);
caretPositionChanged(event);
return;
}
textManager.endCompositionText(text, committed_count);
caretPositionChanged(event);
}
private boolean isBeginInputProcess(AttributedCharacterIterator text, CompositionTextManager textManager){
if(text == null)
return false;
return (isInputProcess(text) && !textManager.getIsInputProcess());
}
private boolean isInputProcess(AttributedCharacterIterator text){
if(text == null)
return false;
return (text.getEndIndex() - (text.getBeginIndex() + committed_count) > 0);
}
public void caretPositionChanged(InputMethodEvent event) {
event.consume();
}
}

View File

@ -120,6 +120,7 @@ public class ColorSelector implements Tool, DocumentListener {
frame.setVisible(false); frame.setVisible(false);
} }
}); });
Base.setIcon(frame); Base.setIcon(frame);
hueField.getDocument().addDocumentListener(this); hueField.getDocument().addDocumentListener(this);
@ -444,19 +445,25 @@ public class ColorSelector implements Tool, DocumentListener {
} }
public Dimension getPreferredSize() { public Dimension getPreferredSize() {
//System.out.println("getting pref " + WIDE + " " + HIGH);
return new Dimension(WIDE, HIGH); return new Dimension(WIDE, HIGH);
} }
public Dimension getMinimumSize() { public Dimension getMinimumSize() {
//System.out.println("getting min " + WIDE + " " + HIGH);
return new Dimension(WIDE, HIGH); return new Dimension(WIDE, HIGH);
} }
public Dimension getMaximumSize() { public Dimension getMaximumSize() {
//System.out.println("getting max " + WIDE + " " + HIGH);
return new Dimension(WIDE, HIGH); 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;
}
}
} }
@ -506,19 +513,25 @@ public class ColorSelector implements Tool, DocumentListener {
} }
public Dimension getPreferredSize() { public Dimension getPreferredSize() {
//System.out.println("s getting pref " + WIDE + " " + HIGH);
return new Dimension(WIDE, HIGH); return new Dimension(WIDE, HIGH);
} }
public Dimension getMinimumSize() { public Dimension getMinimumSize() {
//System.out.println("s getting min " + WIDE + " " + HIGH);
return new Dimension(WIDE, HIGH); return new Dimension(WIDE, HIGH);
} }
public Dimension getMaximumSize() { public Dimension getMaximumSize() {
//System.out.println("s getting max " + WIDE + " " + HIGH);
return new Dimension(WIDE, HIGH); 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;
}
}
} }
@ -540,7 +553,7 @@ public class ColorSelector implements Tool, DocumentListener {
public Dimension getPreferredSize() { public Dimension getPreferredSize() {
if (!allowHex) { if (!allowHex) {
return new Dimension(35, super.getPreferredSize().height); return new Dimension(45, super.getPreferredSize().height);
} }
return super.getPreferredSize(); return super.getPreferredSize();
} }

View File

@ -3,7 +3,7 @@
/* /*
Part of the Processing project - http://processing.org Part of the Processing project - http://processing.org
Copyright (c) 2004-06 Ben Fry and Casey Reas Copyright (c) 2004-10 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology Copyright (c) 2001-04 Massachusetts Institute of Technology
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
@ -37,7 +37,7 @@ import javax.swing.event.*;
/** /**
* gui interface to font creation heaven/hell. * GUI tool for font creation heaven/hell.
*/ */
public class CreateFont extends JFrame implements Tool { public class CreateFont extends JFrame implements Tool {
Editor editor; Editor editor;
@ -46,30 +46,22 @@ public class CreateFont extends JFrame implements Tool {
Dimension windowSize; Dimension windowSize;
JList fontSelector; JList fontSelector;
//JComboBox styleSelector;
JTextField sizeSelector; JTextField sizeSelector;
JCheckBox allBox; JButton charsetButton;
JCheckBox smoothBox; JCheckBox smoothBox;
JTextArea sample; JComponent sample;
JButton okButton; JButton okButton;
JTextField filenameField; JTextField filenameField;
Hashtable table; HashMap<String,Font> table;
boolean smooth = true; boolean smooth = true;
boolean all = false;
Font font; Font font;
String[] list; String[] list;
int selection = -1; int selection = -1;
CharacterSelector charSelector;
//static {
//System.out.println("yep yep yep");
//}
//static final String styles[] = {
//"Plain", "Bold", "Italic", "Bold Italic"
//};
public CreateFont() { public CreateFont() {
@ -117,7 +109,7 @@ public class CreateFont extends JFrame implements Tool {
Font fonts[] = ge.getAllFonts(); Font fonts[] = ge.getAllFonts();
String flist[] = new String[fonts.length]; String flist[] = new String[fonts.length];
table = new Hashtable(); table = new HashMap<String,Font>();
int index = 0; int index = 0;
for (int i = 0; i < fonts.length; i++) { for (int i = 0; i < fonts.length; i++) {
@ -150,20 +142,8 @@ public class CreateFont extends JFrame implements Tool {
Dimension d1 = new Dimension(13, 13); Dimension d1 = new Dimension(13, 13);
pain.add(new Box.Filler(d1, d1, d1)); pain.add(new Box.Filler(d1, d1, d1));
// see http://rinkworks.com/words/pangrams.shtml sample = new SampleComponent(this);
sample = new JTextArea("The quick brown fox blah blah.") {
// Forsaking monastic tradition, twelve jovial friars gave up their
// vocation for a questionable existence on the flying trapeze.
public void paintComponent(Graphics g) {
//System.out.println("disabling aa");
Graphics2D g2 = (Graphics2D) g;
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
smooth ?
RenderingHints.VALUE_TEXT_ANTIALIAS_ON :
RenderingHints.VALUE_TEXT_ANTIALIAS_OFF);
super.paintComponent(g2);
}
};
// Seems that in some instances, no default font is set // Seems that in some instances, no default font is set
// http://dev.processing.org/bugs/show_bug.cgi?id=777 // http://dev.processing.org/bugs/show_bug.cgi?id=777
sample.setFont(new Font("Dialog", Font.PLAIN, 12)); sample.setFont(new Font("Dialog", Font.PLAIN, 12));
@ -193,14 +173,22 @@ public class CreateFont extends JFrame implements Tool {
smoothBox.setSelected(smooth); smoothBox.setSelected(smooth);
panel.add(smoothBox); panel.add(smoothBox);
allBox = new JCheckBox("All Characters"); // allBox = new JCheckBox("All Characters");
allBox.addActionListener(new ActionListener() { // 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) { public void actionPerformed(ActionEvent e) {
all = allBox.isSelected(); //showCharacterList();
charSelector.setVisible(true);
} }
}); });
allBox.setSelected(all); panel.add(charsetButton);
panel.add(allBox);
pain.add(panel); pain.add(panel);
@ -239,6 +227,7 @@ public class CreateFont extends JFrame implements Tool {
Base.registerWindowCloseKeys(root, disposer); Base.registerWindowCloseKeys(root, disposer);
Base.setIcon(this); Base.setIcon(this);
setResizable(false);
pack(); pack();
// do this after pack so it doesn't affect layout // do this after pack so it doesn't affect layout
@ -251,6 +240,9 @@ public class CreateFont extends JFrame implements Tool {
setLocation((screen.width - windowSize.width) / 2, setLocation((screen.width - windowSize.width) / 2,
(screen.height - windowSize.height) / 2); (screen.height - windowSize.height) / 2);
// create this behind the scenes
charSelector = new CharacterSelector();
} }
@ -259,26 +251,6 @@ public class CreateFont extends JFrame implements Tool {
} }
/**
* 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();
}
*/
public void update() { public void update() {
int fontsize = 0; int fontsize = 0;
try { try {
@ -313,7 +285,7 @@ public class CreateFont extends JFrame implements Tool {
return; return;
} }
String filename = filenameField.getText(); String filename = filenameField.getText().trim();
if (filename.length() == 0) { if (filename.length() == 0) {
JOptionPane.showMessageDialog(this, "Enter a file name for the font.", JOptionPane.showMessageDialog(this, "Enter a file name for the font.",
"Lameness", JOptionPane.WARNING_MESSAGE); "Lameness", JOptionPane.WARNING_MESSAGE);
@ -323,23 +295,519 @@ public class CreateFont extends JFrame implements Tool {
filename += ".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 { try {
Font instance = (Font) table.get(list[selection]); Font instance = (Font) table.get(list[selection]);
font = instance.deriveFont(Font.PLAIN, fontsize); font = instance.deriveFont(Font.PLAIN, fontsize);
PFont f = new PFont(font, smooth, all ? null : PFont.DEFAULT_CHARSET); //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 // make sure the 'data' folder exists
File folder = editor.getSketch().prepareDataFolder(); File folder = editor.getSketch().prepareDataFolder();
f.save(new FileOutputStream(new File(folder, filename))); f.save(new FileOutputStream(new File(folder, filename)));
} catch (IOException e) { } catch (IOException e) {
JOptionPane.showMessageDialog(this, JOptionPane.showMessageDialog(CreateFont.this,
"An error occurred while creating font.", "An error occurred while creating font.",
"No font for you", "No font for you",
JOptionPane.WARNING_MESSAGE); JOptionPane.WARNING_MESSAGE);
e.printStackTrace(); e.printStackTrace();
} }
// }
// });
setVisible(false); 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;
}
}
} }

View File

@ -3,7 +3,7 @@
/* /*
Part of the Processing project - http://processing.org Part of the Processing project - http://processing.org
Copyright (c) 2008 Ben Fry and Casey Reas Copyright (c) 2008-2009 Ben Fry and Casey Reas
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
@ -25,6 +25,9 @@ package processing.app.windows;
import java.io.File; import java.io.File;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import com.sun.jna.Library;
import com.sun.jna.Native;
import processing.app.Base; import processing.app.Base;
import processing.app.Preferences; import processing.app.Preferences;
import processing.app.windows.Registry.REGISTRY_ROOT_KEY; import processing.app.windows.Registry.REGISTRY_ROOT_KEY;
@ -265,4 +268,38 @@ public class Platform extends processing.app.Platform {
// not tested // not tested
//Runtime.getRuntime().exec("start explorer \"" + folder + "\""); //Runtime.getRuntime().exec("start explorer \"" + folder + "\"");
} }
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
// Code partially thanks to Richard Quirk from:
// http://quirkygba.blogspot.com/2009/11/setting-environment-variables-in-java.html
static WinLibC clib = (WinLibC) Native.loadLibrary("msvcrt", WinLibC.class);
public interface WinLibC extends Library {
//WinLibC INSTANCE = (WinLibC) Native.loadLibrary("msvcrt", WinLibC.class);
//libc = Native.loadLibrary("msvcrt", WinLibC.class);
public int _putenv(String name);
}
public void setenv(String variable, String value) {
//WinLibC clib = WinLibC.INSTANCE;
clib._putenv(variable + "=" + value);
}
public String getenv(String variable) {
return System.getenv(variable);
}
public int unsetenv(String variable) {
//WinLibC clib = WinLibC.INSTANCE;
//clib._putenv(variable + "=");
//return 0;
return clib._putenv(variable + "=");
}
} }

View File

@ -113,6 +113,7 @@ javac \
src/processing/app/macosx/*.java \ src/processing/app/macosx/*.java \
src/processing/app/preproc/*.java \ src/processing/app/preproc/*.java \
src/processing/app/syntax/*.java \ src/processing/app/syntax/*.java \
src/processing/app/syntax/im/*.java \
src/processing/app/tools/*.java src/processing/app/tools/*.java
cd ../build/macosx/work/classes cd ../build/macosx/work/classes

View File

@ -72,8 +72,15 @@ platform.auto_file_type_associations = true
# default size for the main window # default size for the main window
default.window.width = 500 editor.window.width.default = 500
default.window.height = 600 editor.window.height.default = 600
editor.window.width.min = 400
editor.window.height.min = 500
# tested as approx 440 on OS X
editor.window.height.min.macosx = 450
# tested to be 515 on Windows XP, this leaves some room
editor.window.height.min.windows = 530
# font size for editor # font size for editor
editor.font=Monospaced,plain,12 editor.font=Monospaced,plain,12
@ -92,6 +99,21 @@ editor.caret.blink=true
# area that's not in use by the text (replaced with tildes) # area that's not in use by the text (replaced with tildes)
editor.invalid=false editor.invalid=false
# enable ctrl-ins, shift-ins, shift-delete for cut/copy/paste
# on windows and linux, but disable on the mac
editor.keys.alternative_cut_copy_paste = true
editor.keys.alternative_cut_copy_paste.macosx = false
# true if shift-backspace sends the delete character,
# false if shift-backspace just means backspace
editor.keys.shift_backspace_is_delete = true
# home and end keys should only travel to the start/end of the current line
editor.keys.home_and_end_travel_far = false
# the OS X HI Guidelines say that home/end are relative to the document
# if you don't like it, this is the preference to change
editor.keys.home_and_end_travel_far.macosx = true
console = true console = true
console.output.file = stdout.txt console.output.file = stdout.txt
console.error.file = stderr.txt console.error.file = stderr.txt
@ -197,14 +219,14 @@ preproc.substitute_unicode = true
# viewed in (at least) Mozilla or IE. useful when debugging the preprocessor. # viewed in (at least) Mozilla or IE. useful when debugging the preprocessor.
preproc.output_parse_tree = false preproc.output_parse_tree = false
# imports to use by default (changed for 0149, some imports removed) # Changed after 1.0.9 to a new name, and also includes the specific entries
preproc.imports = java.applet,java.awt,java.awt.image,java.awt.event,java.io,java.net,java.text,java.util,java.util.zip,java.util.regex preproc.imports.list = java.applet.*,java.awt.Dimension,java.awt.Frame,java.awt.event.MouseEvent,java.awt.event.KeyEvent,java.awt.event.FocusEvent,java.awt.Image,java.io.*,java.net.*,java.text.*,java.util.*,java.util.zip.*,java.util.regex.*
# set the browser to be used on linux # set the browser to be used on linux
browser.linux = mozilla browser.linux = mozilla
# set to the program to be used for launching apps on linux # set to the program to be used for launching apps on linux
#launcher.linux = gnome-open #launcher.linux = xdg-open
# FULL SCREEN (PRESENT MODE) # FULL SCREEN (PRESENT MODE)
run.present.bgcolor = #666666 run.present.bgcolor = #666666

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<projectDescription> <projectDescription>
<name>core</name> <name>processing-core</name>
<comment></comment> <comment></comment>
<projects> <projects>
</projects> </projects>

View File

@ -1,22 +1,27 @@
#Thu Aug 28 17:36:28 EDT 2008 #Thu Mar 04 09:10:18 EST 2010
eclipse.preferences.version=1 eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.5 org.eclipse.jdt.core.compiler.compliance=1.5
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.5 org.eclipse.jdt.core.compiler.source=1.5
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=18
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=18
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=18 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=20
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16 org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_assignment=0 org.eclipse.jdt.core.formatter.alignment_for_assignment=0
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=18 org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16 org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=82 org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16 org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=36
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=18 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=18
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=18 org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=18
@ -28,14 +33,14 @@ org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declar
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16 org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
org.eclipse.jdt.core.formatter.blank_lines_after_package=1 org.eclipse.jdt.core.formatter.blank_lines_after_package=1
org.eclipse.jdt.core.formatter.blank_lines_before_field=1 org.eclipse.jdt.core.formatter.blank_lines_before_field=0
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
org.eclipse.jdt.core.formatter.blank_lines_before_method=1 org.eclipse.jdt.core.formatter.blank_lines_before_method=1
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
org.eclipse.jdt.core.formatter.blank_lines_before_package=0 org.eclipse.jdt.core.formatter.blank_lines_before_package=0
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=0
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
@ -50,11 +55,11 @@ org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
org.eclipse.jdt.core.formatter.comment.format_block_comments=true org.eclipse.jdt.core.formatter.comment.format_block_comments=false
org.eclipse.jdt.core.formatter.comment.format_header=false org.eclipse.jdt.core.formatter.comment.format_header=false
org.eclipse.jdt.core.formatter.comment.format_html=true org.eclipse.jdt.core.formatter.comment.format_html=true
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=false
org.eclipse.jdt.core.formatter.comment.format_line_comments=true org.eclipse.jdt.core.formatter.comment.format_line_comments=false
org.eclipse.jdt.core.formatter.comment.format_source_code=true org.eclipse.jdt.core.formatter.comment.format_source_code=true
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
@ -77,6 +82,9 @@ org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
org.eclipse.jdt.core.formatter.indentation.size=2 org.eclipse.jdt.core.formatter.indentation.size=2
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
@ -245,6 +253,8 @@ org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false

View File

@ -1,5 +1,5 @@
#Thu Jan 10 10:50:38 PST 2008 #Fri Feb 19 16:20:47 EST 2010
eclipse.preferences.version=1 eclipse.preferences.version=1
formatter_profile=_two spaces no tabs formatter_profile=_processing
formatter_settings_version=11 formatter_settings_version=11
org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8"?><templates/> org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8"?><templates/>

26
core/build.xml Normal file
View File

@ -0,0 +1,26 @@
<?xml version="1.0"?>
<project name="Processing Core" default="build">
<target name="clean" description="Clean out the build directories">
<delete dir="bin" />
<delete file="core.jar" />
</target>
<target name="compile" description="Compile">
<taskdef name="methods"
classname="PAppletMethods"
classpath="methods/methods.jar" />
<methods dir="${basedir}/src/processing/core" />
<mkdir dir="bin" />
<javac target="1.5"
encoding="UTF-8"
includeAntRuntime="false"
srcdir="src" destdir="bin"/>
</target>
<target name="build" depends="compile" description="Build core library">
<jar basedir="bin" destfile="core.jar" />
</target>
</project>

View File

@ -1,3 +1,58 @@
0178 core (private)
X filter(DILATE/ERODE)
X dilate(boolean) has bug in clamping of top kernel coordinate
X http://dev.processing.org/bugs/show_bug.cgi?id=1477
X deprecated 'screen', adding screenW and screenH
X write implementation for get/set methods inside PImage (w/o pixels[])
0177 core (private)
X no changes
0176 core (private)
X opengl sketches run at 30fps in present mode on OS X
o still having problems w/ full screen non-FSEM
X http://dev.processing.org/bugs/show_bug.cgi?id=1425
X PFont not working well with lots of characters
X only create bitmap chars on the fly when needed (in createFont)
X Implement better caching mechanism when creating large fonts
X http://dev.processing.org/bugs/show_bug.cgi?id=1111
X fix problem with "create font" still showing anti-aliased text
X don't make fonts power of 2
X PGraphics3D: beginDraw does not release old textures
X http://dev.processing.org/bugs/show_bug.cgi?id=1423
X fix from taifun_browser
X removing camera() and perspective() from setSize() trashes resize
X probably regression b/c camera/perspective can't be called then
X http://dev.processing.org/bugs/show_bug.cgi?id=1391
0175 core (private)
X changed createInputRaw() to only bother checking URLs if : present
0174 core (private)
X svg paths that use 'e' (exponent) not handled properly
X http://dev.processing.org/bugs/show_bug.cgi?id=1408
0173 core (private)
X Re-enabled hack for temporary clipping.
X Clipping still needs to be implemented properly, however. Please help!
X http://dev.processing.org/bugs/show_bug.cgi?id=1393
0172 core (private)
X no changes to the core (or were there?)
0171 core (1.0.9)
X Blurred PImages in OPENGL sketches
X removed NPOT texture support (for further testing)
X http://dev.processing.org/bugs/show_bug.cgi?id=1352
0170 core (1.0.8) 0170 core (1.0.8)
X added some min/max functions that work with doubles X added some min/max functions that work with doubles
X not sure if those are staying in or not X not sure if those are staying in or not

7
core/methods/.classpath Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="/usr/share/ant/lib/ant.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

17
core/methods/.project Normal file
View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>preproc</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

28
core/methods/build.xml Normal file
View File

@ -0,0 +1,28 @@
<project name="methods" default="task-lib">
<target name="compile">
<mkdir dir="bin" />
<!-- <javac target="1.5" srcdir="src" destdir="bin" classpath="../ant/ant.jar" debug="true"/>-->
<!-- <javac target="1.5" srcdir="src" destdir="bin" classpath="/usr/share/ant/ant.jar" debug="true"/>-->
<javac target="1.5"
srcdir="src" destdir="bin"
debug="true"
includeantruntime="true" />
</target>
<target name="task-lib" depends="compile">
<jar basedir="bin" destfile="methods.jar" />
</target>
<target name="demo">
<taskdef name="methods"
classname="PAppletMethods"
classpath="methods.jar" />
<preproc dir="demo"/>
</target>
<target name="clean">
<delete dir="bin" />
<delete file="methods.jar" />
</target>
</project>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

BIN
core/methods/methods.jar Normal file

Binary file not shown.

View File

@ -0,0 +1,272 @@
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
/**
* Ant Task for copying the PImage and PGraphics methods into PApplet.
*/
public class PAppletMethods extends Task {
private File baseDir;
public PAppletMethods() {
}
public void setDir(String dir) {
baseDir = new File(dir);
}
public void execute() throws BuildException {
// Do a bunch of checks...
if (baseDir == null) {
throw new BuildException("dir parameter must be set!");
}
//System.out.println("using basedir " + baseDir);
File graphicsFile = new File(baseDir, "PGraphics.java");
File appletFile = new File(baseDir, "PApplet.java");
File imageFile = new File(baseDir, "PImage.java");
if (!graphicsFile.exists() || !graphicsFile.canRead()) {
throw new BuildException("PGraphics file not readable: " +
graphicsFile.getAbsolutePath());
}
if (!appletFile.exists() ||
!appletFile.canRead() ||
!appletFile.canWrite()) {
throw new BuildException("PApplet file not read/writeable: " +
appletFile.getAbsolutePath());
}
if (!imageFile.exists() || !imageFile.canRead()) {
throw new BuildException("PImage file not readable: " +
imageFile.getAbsolutePath());
}
// Looking good, let's do this!
//ByteArrayOutputStream outBytes = new ByteArrayOutputStream();
//PrintStream out = new PrintStream(outBytes, "UTF-8");
StringBuffer out = new StringBuffer();
StringBuffer content = new StringBuffer();
try{
BufferedReader applet = createReader(appletFile);
String line;
while ((line = applet.readLine()) != null) {
out.append(line);
out.append('\n'); // to avoid Windows CRs
content.append(line);
content.append('\n'); // for efficiency
if (line.indexOf("public functions for processing.core") >= 0) {
break;
}
}
// read the rest of the file and append it to the
while ((line = applet.readLine()) != null) {
content.append(line);
content.append('\n');
}
applet.close();
process(out, graphicsFile);
process(out, imageFile);
out.append('}');
out.append('\n');
//} catch (IOException e) {
//e.printStackTrace();
} catch (Exception e) {
//ex.printStackTrace();
throw new BuildException(e);
}
//out.flush();
String outString = out.toString();
if (content.toString().equals(outString)) {
System.out.println("No changes to PApplet API.");
} else {
System.out.println("Updating PApplet with API changes " +
"from PImage or PGraphics.");
try {
PrintStream temp = new PrintStream(appletFile, "UTF-8");
temp.print(outString);
temp.flush();
temp.close();
} catch (IOException e) {
//e.printStackTrace();
throw new BuildException(e);
}
}
}
private void process(StringBuffer out, File input) throws IOException {
BufferedReader in = createReader(input);
int comments = 0;
String line = null;
StringBuffer commentBuffer = new StringBuffer();
while ((line = in.readLine()) != null) {
String decl = "";
// Keep track of comments
//if (line.matches(Pattern.quote("/*"))) {
if (line.indexOf("/*") != -1) {
comments++;
}
//if (line.matches(Pattern.quote("*/"))) {
if (line.indexOf("*/") != -1) {
commentBuffer.append(line);
commentBuffer.append('\n');
//System.out.println("comment is: " + commentBuffer.toString());
comments--;
// otherwise gotSomething will be false, and nuke the comment
continue;
}
// Ignore everything inside comments
if (comments > 0) {
commentBuffer.append(line);
commentBuffer.append('\n');
continue;
}
boolean gotSomething = false;
boolean gotStatic = false;
Matcher result;
if ((result = Pattern.compile("^\\s*public ([\\w\\[\\]]+) [a-zA-z_]+\\(.*$").matcher(line)).matches()) {
gotSomething = true;
} else if ((result = Pattern.compile("^\\s*abstract public ([\\w\\[\\]]+) [a-zA-z_]+\\(.*$").matcher(line)).matches()) {
gotSomething = true;
} else if ((result = Pattern.compile("^\\s*public final ([\\w\\[\\]]+) [a-zA-z_]+\\(.*$").matcher(line)).matches()) {
gotSomething = true;
} else if ((result = Pattern.compile("^\\s*static public ([\\w\\[\\]]+) [a-zA-z_]+\\(.*$").matcher(line)).matches()) {
gotSomething = true;
gotStatic = true;
}
// if function is marked "// ignore" then, uh, ignore it.
if (gotSomething && line.indexOf("// ignore") >= 0) {
gotSomething = false;
}
String returns = "";
if (gotSomething) {
if (result.group(1).equals("void")) {
returns = "";
} else {
returns = "return ";
}
// remove the abstract modifier
line = line.replaceFirst(Pattern.quote("abstract"), " ");
// replace semicolons with a start def
line = line.replaceAll(Pattern.quote(";"), " {\n");
//out.println("\n\n" + line);
out.append('\n');
out.append('\n');
// end has its own newline
//out.print(commentBuffer.toString()); // TODO disabled for now XXXX
out.append(commentBuffer.toString()); // duplicates all comments
commentBuffer.setLength(0);
out.append(line);
out.append('\n');
decl += line;
while(line.indexOf(')') == -1) {
line = in.readLine();
decl += line;
line = line.replaceAll("\\;\\s*$", " {\n");
out.append(line);
out.append('\n');
}
result = Pattern.compile(".*?\\s(\\S+)\\(.*?").matcher(decl);
// try to match. don't remove this or things will stop working!
result.matches();
String declName = result.group(1);
String gline = "";
String rline = "";
if (gotStatic) {
gline = " " + returns + "PGraphics." + declName + "(";
} else {
rline = " if (recorder != null) recorder." + declName + "(";
gline = " " + returns + "g." + declName + "(";
}
decl = decl.replaceAll("\\s+", " "); // smush onto a single line
decl = decl.replaceFirst("^.*\\(", "");
decl = decl.replaceFirst("\\).*$", "");
int prev = 0;
String parts[] = decl.split("\\, ");
for (String part : parts) {
if (!part.trim().equals("")) {
String blargh[] = part.split(" ");
String theArg = blargh[1].replaceAll("[\\[\\]]", "");
if (prev != 0) {
gline += ", ";
rline += ", ";
}
gline += theArg;
rline += theArg;
prev = 1;
}
}
gline += ");";
rline += ");";
if (!gotStatic && returns.equals("")) {
out.append(rline);
out.append('\n');
}
out.append(gline);
out.append('\n');
out.append(" }");
out.append('\n');
} else {
commentBuffer.setLength(0);
}
}
in.close();
}
static BufferedReader createReader(File file) throws IOException {
FileInputStream fis = new FileInputStream(file);
return new BufferedReader(new InputStreamReader(fis, "UTF-8"));
}
}

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,8 @@ import java.awt.event.KeyEvent;
* An attempt is made to keep the constants as short/non-verbose * An attempt is made to keep the constants as short/non-verbose
* as possible. For instance, the constant is TIFF instead of * as possible. For instance, the constant is TIFF instead of
* FILE_TYPE_TIFF. We'll do this as long as we can get away with it. * FILE_TYPE_TIFF. We'll do this as long as we can get away with it.
*
* @usage Web &amp; Application
*/ */
public interface PConstants { public interface PConstants {
@ -159,10 +161,51 @@ public interface PConstants {
// useful goodness // useful goodness
/**
* PI is a mathematical constant with the value 3.14159265358979323846.
* It is the ratio of the circumference of a circle to its diameter.
* It is useful in combination with the trigonometric functions <b>sin()</b> and <b>cos()</b>.
*
* @webref constants
* @see processing.core.PConstants#HALF_PI
* @see processing.core.PConstants#TWO_PI
* @see processing.core.PConstants#QUARTER_PI
*
*/
static final float PI = (float) Math.PI; static final float PI = (float) Math.PI;
/**
* HALF_PI is a mathematical constant with the value 1.57079632679489661923.
* It is half the ratio of the circumference of a circle to its diameter.
* It is useful in combination with the trigonometric functions <b>sin()</b> and <b>cos()</b>.
*
* @webref constants
* @see processing.core.PConstants#PI
* @see processing.core.PConstants#TWO_PI
* @see processing.core.PConstants#QUARTER_PI
*/
static final float HALF_PI = PI / 2.0f; static final float HALF_PI = PI / 2.0f;
static final float THIRD_PI = PI / 3.0f; static final float THIRD_PI = PI / 3.0f;
/**
* QUARTER_PI is a mathematical constant with the value 0.7853982.
* It is one quarter the ratio of the circumference of a circle to its diameter.
* It is useful in combination with the trigonometric functions <b>sin()</b> and <b>cos()</b>.
*
* @webref constants
* @see processing.core.PConstants#PI
* @see processing.core.PConstants#TWO_PI
* @see processing.core.PConstants#HALF_PI
*/
static final float QUARTER_PI = PI / 4.0f; static final float QUARTER_PI = PI / 4.0f;
/**
* TWO_PI is a mathematical constant with the value 6.28318530717958647693.
* It is twice the ratio of the circumference of a circle to its diameter.
* It is useful in combination with the trigonometric functions <b>sin()</b> and <b>cos()</b>.
*
* @webref constants
* @see processing.core.PConstants#PI
* @see processing.core.PConstants#HALF_PI
* @see processing.core.PConstants#QUARTER_PI
*/
static final float TWO_PI = PI * 2.0f; static final float TWO_PI = PI * 2.0f;
static final float DEG_TO_RAD = PI/180.0f; static final float DEG_TO_RAD = PI/180.0f;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -53,8 +53,12 @@ public class PGraphics3D extends PGraphics {
public PMatrix3D modelviewInv; public PMatrix3D modelviewInv;
/** /**
* The camera matrix, the modelview will be set to this on beginDraw. * Marks when changes to the size have occurred, so that the camera
* will be reset in beginDraw().
*/ */
protected boolean sizeChanged;
/** The camera matrix, the modelview will be set to this on beginDraw. */
public PMatrix3D camera; public PMatrix3D camera;
/** Inverse camera matrix */ /** Inverse camera matrix */
@ -306,6 +310,9 @@ public class PGraphics3D extends PGraphics {
* the pixel buffer for the new size. * the pixel buffer for the new size.
* *
* Note that this will nuke any cameraMode() settings. * Note that this will nuke any cameraMode() settings.
*
* No drawing can happen in this function, and no talking to the graphics
* context. That is, no glXxxx() calls, or other things that change state.
*/ */
public void setSize(int iwidth, int iheight) { // ignore public void setSize(int iwidth, int iheight) { // ignore
width = iwidth; width = iwidth;
@ -357,13 +364,8 @@ public class PGraphics3D extends PGraphics {
camera = new PMatrix3D(); camera = new PMatrix3D();
cameraInv = new PMatrix3D(); cameraInv = new PMatrix3D();
// set up the default camera // set this flag so that beginDraw() will do an update to the camera.
// camera(); sizeChanged = true;
// defaults to perspective, if the user has setup up their
// own projection, they'll need to fix it after resize anyway.
// this helps the people who haven't set up their own projection.
// perspective();
} }
@ -409,6 +411,19 @@ public class PGraphics3D extends PGraphics {
// beginDraw/endDraw). // beginDraw/endDraw).
if (!settingsInited) defaultSettings(); if (!settingsInited) defaultSettings();
if (sizeChanged) {
// set up the default camera
camera();
// defaults to perspective, if the user has setup up their
// own projection, they'll need to fix it after resize anyway.
// this helps the people who haven't set up their own projection.
perspective();
// clear the flag
sizeChanged = false;
}
resetMatrix(); // reset model matrix resetMatrix(); // reset model matrix
// reset vertices // reset vertices
@ -437,6 +452,7 @@ public class PGraphics3D extends PGraphics {
shapeFirst = 0; shapeFirst = 0;
// reset textures // reset textures
Arrays.fill(textures, null);
textureIndex = 0; textureIndex = 0;
normal(0, 0, 1); normal(0, 0, 1);
@ -1350,7 +1366,10 @@ public class PGraphics3D extends PGraphics {
boolean bClipped = false; boolean bClipped = false;
int clippedCount = 0; int clippedCount = 0;
// cameraNear = -8; // This is a hack for temporary clipping. Clipping still needs to
// be implemented properly, however. Please help!
// http://dev.processing.org/bugs/show_bug.cgi?id=1393
cameraNear = -8;
if (vertices[a][VZ] > cameraNear) { if (vertices[a][VZ] > cameraNear) {
aClipped = true; aClipped = true;
clippedCount++; clippedCount++;

View File

@ -967,6 +967,9 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
public float textAscent() { public float textAscent() {
if (textFont == null) {
defaultFontOrDeath("textAscent");
}
Font font = textFont.getFont(); Font font = textFont.getFont();
if (font == null) { if (font == null) {
return super.textAscent(); return super.textAscent();
@ -977,6 +980,9 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
public float textDescent() { public float textDescent() {
if (textFont == null) {
defaultFontOrDeath("textAscent");
}
Font font = textFont.getFont(); Font font = textFont.getFont();
if (font == null) { if (font == null) {
return super.textDescent(); return super.textDescent();
@ -1010,6 +1016,10 @@ public class PGraphicsJava2D extends PGraphics /*PGraphics2D*/ {
* will get recorded properly. * will get recorded properly.
*/ */
public void textSize(float size) { public void textSize(float size) {
if (textFont == null) {
defaultFontOrDeath("textAscent", size);
}
// if a native version available, derive this font // if a native version available, derive this font
// if (textFontNative != null) { // if (textFontNative != null) {
// textFontNative = textFontNative.deriveFont(size); // textFontNative = textFontNative.deriveFont(size);

View File

@ -31,13 +31,31 @@ import java.util.HashMap;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
/** /**
* Datatype for storing images. Processing can display <b>.gif</b>, <b>.jpg</b>, <b>.tga</b>, and <b>.png</b> images. Images may be displayed in 2D and 3D space.
* Before an image is used, it must be loaded with the <b>loadImage()</b> function.
* The <b>PImage</b> object contains fields for the <b>width</b> and <b>height</b> of the image,
* as well as an array called <b>pixels[]</b> which contains the values for every pixel in the image.
* A group of methods, described below, allow easy access to the image's pixels and alpha channel and simplify the process of compositing.
* <br><br>Before using the <b>pixels[]</b> array, be sure to use the <b>loadPixels()</b> method on the image to make sure that the pixel data is properly loaded.
* <br><br>To create a new image, use the <b>createImage()</b> function (do not use <b>new PImage()</b>).
* =advanced
*
* Storage class for pixel data. This is the base class for most image and * Storage class for pixel data. This is the base class for most image and
* pixel information, such as PGraphics and the video library classes. * pixel information, such as PGraphics and the video library classes.
* <P> * <P>
* Code for copying, resizing, scaling, and blending contributed * Code for copying, resizing, scaling, and blending contributed
* by <A HREF="http://www.toxi.co.uk">toxi</A>. * by <A HREF="http://www.toxi.co.uk">toxi</A>.
* <P> * <P>
*
* @webref image
* @usage Web &amp; Application
* @instanceName img any variable of type PImage
* @see processing.core.PApplet#loadImage(String)
* @see processing.core.PGraphics#imageMode(int)
* @see processing.core.PApplet#createImage(int, int)
*/ */
public class PImage implements PConstants, Cloneable { public class PImage implements PConstants, Cloneable {
@ -48,8 +66,32 @@ public class PImage implements PConstants, Cloneable {
*/ */
public int format; public int format;
/**
* Array containing the values for all the pixels in the image. These values are of the color datatype.
* This array is the size of the image, meaning if the image is 100x100 pixels, there will be 10000 values
* and if the window is 200x300 pixels, there will be 60000 values.
* The <b>index</b> value defines the position of a value within the array.
* For example, the statement <b>color b = img.pixels[230]</b> will set the variable <b>b</b> equal to the value at that location in the array.
* Before accessing this array, the data must loaded with the <b>loadPixels()</b> method.
* After the array data has been modified, the <b>updatePixels()</b> method must be run to update the changes.
* Without <b>loadPixels()</b>, running the code may (or will in future releases) result in a NullPointerException.
* @webref
* @brief Array containing the color of every pixel in the image
*/
public int[] pixels; public int[] pixels;
public int width, height;
/**
* The width of the image in units of pixels.
* @webref
* @brief Image width
*/
public int width;
/**
* The height of the image in units of pixels.
* @webref
* @brief Image height
*/
public int height;
/** /**
* Path to parent object that will be used with save(). * Path to parent object that will be used with save().
@ -125,7 +167,12 @@ public class PImage implements PConstants, Cloneable {
// toxi: agreed and same reasons why i left it out ;) // toxi: agreed and same reasons why i left it out ;)
} }
/**
*
* @param width image width
* @param height image height
* @param format Either RGB, ARGB, ALPHA (grayscale alpha channel)
*/
public PImage(int width, int height, int format) { public PImage(int width, int height, int format) {
init(width, height, format); init(width, height, format);
} }
@ -171,6 +218,8 @@ public class PImage implements PConstants, Cloneable {
* Construct a new PImage from a java.awt.Image. This constructor assumes * Construct a new PImage from a java.awt.Image. This constructor assumes
* that you've done the work of making sure a MediaTracker has been used * that you've done the work of making sure a MediaTracker has been used
* to fully download the data and that the img is valid. * to fully download the data and that the img is valid.
*
* @param img assumes a MediaTracker has been used to fully download the data and the img is valid
*/ */
public PImage(java.awt.Image img) { public PImage(java.awt.Image img) {
if (img instanceof BufferedImage) { if (img instanceof BufferedImage) {
@ -275,31 +324,39 @@ public class PImage implements PConstants, Cloneable {
/** /**
* Loads the pixel data for the image into its <b>pixels[]</b> array. This function must always be called before reading from or writing to <b>pixels[]</b>.
* <br><br>Certain renderers may or may not seem to require <b>loadPixels()</b> or <b>updatePixels()</b>. However, the rule is that any time you want to manipulate the <b>pixels[]</b> array, you must first call <b>loadPixels()</b>, and after changes have been made, call <b>updatePixels()</b>. Even if the renderer may not seem to use this function in the current Processing release, this will always be subject to change.
* =advanced
* Call this when you want to mess with the pixels[] array. * Call this when you want to mess with the pixels[] array.
* <p/> * <p/>
* For subclasses where the pixels[] buffer isn't set by default, * For subclasses where the pixels[] buffer isn't set by default,
* this should copy all data into the pixels[] array * this should copy all data into the pixels[] array
*
* @webref
* @brief Loads the pixel data for the image into its pixels[] array
*/ */
public void loadPixels() { // ignore public void loadPixels() { // ignore
} }
/**
* Call this when finished messing with the pixels[] array.
* <p/>
* Mark all pixels as needing update.
*/
public void updatePixels() { // ignore public void updatePixels() { // ignore
updatePixelsImpl(0, 0, width, height); updatePixelsImpl(0, 0, width, height);
} }
/** /**
* Updates the image with the data in its <b>pixels[]</b> array. Use in conjunction with <b>loadPixels()</b>. If you're only reading pixels from the array, there's no need to call <b>updatePixels()</b>.
* <br><br>Certain renderers may or may not seem to require <b>loadPixels()</b> or <b>updatePixels()</b>. However, the rule is that any time you want to manipulate the <b>pixels[]</b> array, you must first call <b>loadPixels()</b>, and after changes have been made, call <b>updatePixels()</b>. Even if the renderer may not seem to use this function in the current Processing release, this will always be subject to change.
* <br><br>Currently, none of the renderers use the additional parameters to <b>updatePixels()</b>, however this may be implemented in the future.
* =advanced
* Mark the pixels in this region as needing an update. * Mark the pixels in this region as needing an update.
* <P>
* This is not currently used by any of the renderers, however the api * This is not currently used by any of the renderers, however the api
* is structured this way in the hope of being able to use this to * is structured this way in the hope of being able to use this to
* speed things up in the future. * speed things up in the future.
* @webref
* @brief Updates the image with the data in its pixels[] array
* @param x
* @param y
* @param w
* @param h
*/ */
public void updatePixels(int x, int y, int w, int h) { // ignore public void updatePixels(int x, int y, int w, int h) { // ignore
// if (imageMode == CORNER) { // x2, y2 are w/h // if (imageMode == CORNER) { // x2, y2 are w/h
@ -369,8 +426,14 @@ public class PImage implements PConstants, Cloneable {
/** /**
* Resize this image to a new width and height. * Resize the image to a new width and height. To make the image scale proportionally, use 0 as the value for the <b>wide</b> or <b>high</b> parameter.
* Use 0 for wide or high to make that dimension scale proportionally. *
* @webref
* @brief Changes the size of an image to a new width and height
* @param wide the resized image width
* @param high the resized image height
*
* @see processing.core.PImage#get(int, int, int, int)
*/ */
public void resize(int wide, int high) { // ignore public void resize(int wide, int high) { // ignore
// Make sure that the pixels[] array is valid // Make sure that the pixels[] array is valid
@ -442,8 +505,20 @@ public class PImage implements PConstants, Cloneable {
/** /**
* Grab a subsection of a PImage, and copy it into a fresh PImage. * Reads the color of any pixel or grabs a group of pixels. If no parameters are specified, the entire image is returned. Get the value of one pixel by specifying an x,y coordinate. Get a section of the display window by specifing an additional <b>width</b> and <b>height</b> parameter. If the pixel requested is outside of the image window, black is returned. The numbers returned are scaled according to the current color ranges, but only RGB values are returned by this function. Even though you may have drawn a shape with <b>colorMode(HSB)</b>, the numbers returned will be in RGB.
* As of release 0149, no longer honors imageMode() for the coordinates. * <br><br>Getting the color of a single pixel with <b>get(x, y)</b> is easy, but not as fast as grabbing the data directly from <b>pixels[]</b>. The equivalent statement to "get(x, y)" using <b>pixels[]</b> is "pixels[y*width+x]". Processing requires calling <b>loadPixels()</b> to load the display window data into the <b>pixels[]</b> array before getting the values.
* <br><br>As of release 0149, this function ignores <b>imageMode()</b>.
*
* @webref
* @brief Reads the color of any pixel or grabs a rectangle of pixels
* @param x x-coordinate of the pixel
* @param y y-coordinate of the pixel
* @param w width of pixel rectangle to get
* @param h height of pixel rectangle to get
*
* @see processing.core.PImage#set(int, int, int)
* @see processing.core.PImage#pixels
* @see processing.core.PImage#copy(PImage, int, int, int, int, int, int, int, int)
*/ */
public PImage get(int x, int y, int w, int h) { public PImage get(int x, int y, int w, int h) {
/* /*
@ -512,7 +587,17 @@ public class PImage implements PConstants, Cloneable {
/** /**
* Set a single pixel to the specified color. * Changes the color of any pixel or writes an image directly into the display window. The <b>x</b> and <b>y</b> parameters specify the pixel to change and the <b>color</b> parameter specifies the color value. The color parameter is affected by the current color mode (the default is RGB values from 0 to 255). When setting an image, the x and y parameters define the coordinates for the upper-left corner of the image.
* <br><br>Setting the color of a single pixel with <b>set(x, y)</b> is easy, but not as fast as putting the data directly into <b>pixels[]</b>. The equivalent statement to "set(x, y, #000000)" using <b>pixels[]</b> is "pixels[y*width+x] = #000000". You must call <b>loadPixels()</b> to load the display window data into the <b>pixels[]</b> array before setting the values and calling <b>updatePixels()</b> to update the window with any changes.
* <br><br>As of release 1.0, this function ignores <b>imageMode()</b>.
* <br><br>Due to what appears to be a bug in Apple's Java implementation, the point() and set() methods are extremely slow in some circumstances when used with the default renderer. Using P2D or P3D will fix the problem. Grouping many calls to point() or set() together can also help. (<a href="http://dev.processing.org/bugs/show_bug.cgi?id=1094">Bug 1094</a>)
* =advanced
* <br><br>As of release 0149, this function ignores <b>imageMode()</b>.
*
* @webref image:pixels
* @param x x-coordinate of the pixel
* @param y y-coordinate of the pixel
* @param c any value of the color datatype
*/ */
public void set(int x, int y, int c) { public void set(int x, int y, int c) {
if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) return; if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) return;
@ -594,18 +679,20 @@ public class PImage implements PConstants, Cloneable {
* used as the alpha color. For a fully grayscale image, this * used as the alpha color. For a fully grayscale image, this
* is correct, but for a color image it's not 100% accurate. * is correct, but for a color image it's not 100% accurate.
* For a more accurate conversion, first use filter(GRAY) * For a more accurate conversion, first use filter(GRAY)
* which will make the image into a "correct" grayscake by * which will make the image into a "correct" grayscale by
* performing a proper luminance-based conversion. * performing a proper luminance-based conversion.
*
* @param maskArray any array of Integer numbers used as the alpha channel, needs to be same length as the image's pixel array
*/ */
public void mask(int alpha[]) { public void mask(int maskArray[]) {
loadPixels(); loadPixels();
// don't execute if mask image is different size // don't execute if mask image is different size
if (alpha.length != pixels.length) { if (maskArray.length != pixels.length) {
throw new RuntimeException("The PImage used with mask() must be " + throw new RuntimeException("The PImage used with mask() must be " +
"the same size as the applet."); "the same size as the applet.");
} }
for (int i = 0; i < pixels.length; i++) { for (int i = 0; i < pixels.length; i++) {
pixels[i] = ((alpha[i] & 0xff) << 24) | (pixels[i] & 0xffffff); pixels[i] = ((maskArray[i] & 0xff) << 24) | (pixels[i] & 0xffffff);
} }
format = ARGB; format = ARGB;
updatePixels(); updatePixels();
@ -613,10 +700,19 @@ public class PImage implements PConstants, Cloneable {
/** /**
* Set alpha channel for an image using another image as the source. * Masks part of an image from displaying by loading another image and using it as an alpha channel.
* This mask image should only contain grayscale data, but only the blue color channel is used.
* The mask image needs to be the same size as the image to which it is applied.
* In addition to using a mask image, an integer array containing the alpha channel data can be specified directly.
* This method is useful for creating dynamically generated alpha masks.
* This array must be of the same length as the target image's pixels array and should contain only grayscale data of values between 0-255.
* @webref
* @brief Masks part of the image from displaying
* @param maskImg any PImage object used as the alpha channel for "img", needs to be same size as "img"
*/ */
public void mask(PImage alpha) { public void mask(PImage maskImg) {
mask(alpha.pixels); maskImg.loadPixels();
mask(maskImg.pixels);
} }
@ -624,26 +720,6 @@ public class PImage implements PConstants, Cloneable {
////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////
// IMAGE FILTERS // IMAGE FILTERS
/**
* Method to apply a variety of basic filters to this image.
* <P>
* <UL>
* <LI>filter(BLUR) provides a basic blur.
* <LI>filter(GRAY) converts the image to grayscale based on luminance.
* <LI>filter(INVERT) will invert the color components in the image.
* <LI>filter(OPAQUE) set all the high bits in the image to opaque
* <LI>filter(THRESHOLD) converts the image to black and white.
* <LI>filter(DILATE) grow white/light areas
* <LI>filter(ERODE) shrink white/light areas
* </UL>
* Luminance conversion code contributed by
* <A HREF="http://www.toxi.co.uk">toxi</A>
* <P/>
* Gaussian blur code contributed by
* <A HREF="http://incubator.quasimondo.com">Mario Klingemann</A>
*/
public void filter(int kind) { public void filter(int kind) {
loadPixels(); loadPixels();
@ -716,20 +792,29 @@ public class PImage implements PConstants, Cloneable {
/** /**
* Filters an image as defined by one of the following modes:<br><br>THRESHOLD - converts the image to black and white pixels depending if they are above or below the threshold defined by the level parameter. The level must be between 0.0 (black) and 1.0(white). If no level is specified, 0.5 is used.<br><br>GRAY - converts any colors in the image to grayscale equivalents<br><br>INVERT - sets each pixel to its inverse value<br><br>POSTERIZE - limits each channel of the image to the number of colors specified as the level parameter<br><br>BLUR - executes a Guassian blur with the level parameter specifying the extent of the blurring. If no level parameter is used, the blur is equivalent to Guassian blur of radius 1.<br><br>OPAQUE - sets the alpha channel to entirely opaque.<br><br>ERODE - reduces the light areas with the amount defined by the level parameter.<br><br>DILATE - increases the light areas with the amount defined by the level parameter
* =advanced
* Method to apply a variety of basic filters to this image. * Method to apply a variety of basic filters to this image.
* These filters all take a parameter.
* <P> * <P>
* <UL> * <UL>
* <LI>filter(BLUR, int radius) performs a gaussian blur of the * <LI>filter(BLUR) provides a basic blur.
* specified radius. * <LI>filter(GRAY) converts the image to grayscale based on luminance.
* <LI>filter(POSTERIZE, int levels) will posterize the image to * <LI>filter(INVERT) will invert the color components in the image.
* between 2 and 255 levels. * <LI>filter(OPAQUE) set all the high bits in the image to opaque
* <LI>filter(THRESHOLD, float center) allows you to set the * <LI>filter(THRESHOLD) converts the image to black and white.
* center point for the threshold. It takes a value from 0 to 1.0. * <LI>filter(DILATE) grow white/light areas
* <LI>filter(ERODE) shrink white/light areas
* </UL> * </UL>
* Luminance conversion code contributed by
* <A HREF="http://www.toxi.co.uk">toxi</A>
* <P/>
* Gaussian blur code contributed by * Gaussian blur code contributed by
* <A HREF="http://incubator.quasimondo.com">Mario Klingemann</A> * <A HREF="http://incubator.quasimondo.com">Mario Klingemann</A>
* and later updated by toxi for better speed. *
* @webref
* @brief Converts the image to grayscale or black and white
* @param kind Either THRESHOLD, GRAY, INVERT, POSTERIZE, BLUR, OPAQUE, ERODE, or DILATE
* @param param in the range from 0 to 1
*/ */
public void filter(int kind, float param) { public void filter(int kind, float param) {
loadPixels(); loadPixels();
@ -1093,7 +1178,7 @@ public class PImage implements PConstants, Cloneable {
if (idxRight>=maxRowIdx) if (idxRight>=maxRowIdx)
idxRight=currIdx; idxRight=currIdx;
if (idxUp<0) if (idxUp<0)
idxUp=0; idxUp=currIdx;
if (idxDown>=maxIdx) if (idxDown>=maxIdx)
idxDown=currIdx; idxDown=currIdx;
@ -1150,7 +1235,7 @@ public class PImage implements PConstants, Cloneable {
if (idxRight>=maxRowIdx) if (idxRight>=maxRowIdx)
idxRight=currIdx; idxRight=currIdx;
if (idxUp<0) if (idxUp<0)
idxUp=0; idxUp=currIdx;
if (idxDown>=maxIdx) if (idxDown>=maxIdx)
idxDown=currIdx; idxDown=currIdx;
@ -1212,7 +1297,23 @@ public class PImage implements PConstants, Cloneable {
/** /**
* Copies area of one image into another PImage object. * Copies a region of pixels from one image into another. If the source and destination regions aren't the same size, it will automatically resize source pixels to fit the specified target region. No alpha information is used in the process, however if the source image has an alpha channel set, it will be copied as well.
* <br><br>As of release 0149, this function ignores <b>imageMode()</b>.
*
* @webref
* @brief Copies the entire image
* @param sx X coordinate of the source's upper left corner
* @param sy Y coordinate of the source's upper left corner
* @param sw source image width
* @param sh source image height
* @param dx X coordinate of the destination's upper left corner
* @param dy Y coordinate of the destination's upper left corner
* @param dw destination image width
* @param dh destination image height
* @param src an image variable referring to the source image.
*
* @see processing.core.PGraphics#alpha(int)
* @see processing.core.PImage#blend(PImage, int, int, int, int, int, int, int, int, int)
*/ */
public void copy(PImage src, public void copy(PImage src,
int sx, int sy, int sw, int sh, int sx, int sy, int sw, int sh,
@ -1321,6 +1422,7 @@ public class PImage implements PConstants, Cloneable {
/** /**
* Blends one area of this image to another area. * Blends one area of this image to another area.
*
* @see processing.core.PImage#blendColor(int,int,int) * @see processing.core.PImage#blendColor(int,int,int)
*/ */
public void blend(int sx, int sy, int sw, int sh, public void blend(int sx, int sy, int sw, int sh,
@ -1330,7 +1432,39 @@ public class PImage implements PConstants, Cloneable {
/** /**
* Copies area of one image into another PImage object. * Blends a region of pixels into the image specified by the <b>img</b> parameter. These copies utilize full alpha channel support and a choice of the following modes to blend the colors of source pixels (A) with the ones of pixels in the destination image (B):<br><br>
* BLEND - linear interpolation of colours: C = A*factor + B<br><br>
* ADD - additive blending with white clip: C = min(A*factor + B, 255)<br><br>
* SUBTRACT - subtractive blending with black clip: C = max(B - A*factor, 0)<br><br>
* DARKEST - only the darkest colour succeeds: C = min(A*factor, B)<br><br>
* LIGHTEST - only the lightest colour succeeds: C = max(A*factor, B)<br><br>
* DIFFERENCE - subtract colors from underlying image.<br><br>
* EXCLUSION - similar to DIFFERENCE, but less extreme.<br><br>
* MULTIPLY - Multiply the colors, result will always be darker.<br><br>
* SCREEN - Opposite multiply, uses inverse values of the colors.<br><br>
* OVERLAY - A mix of MULTIPLY and SCREEN. Multiplies dark values, and screens light values.<br><br>
* HARD_LIGHT - SCREEN when greater than 50% gray, MULTIPLY when lower.<br><br>
* SOFT_LIGHT - Mix of DARKEST and LIGHTEST. Works like OVERLAY, but not as harsh.<br><br>
* DODGE - Lightens light tones and increases contrast, ignores darks. Called "Color Dodge" in Illustrator and Photoshop.<br><br>
* BURN - Darker areas are applied, increasing contrast, ignores lights. Called "Color Burn" in Illustrator and Photoshop.<br><br>
* All modes use the alpha information (highest byte) of source image pixels as the blending factor. If the source and destination regions are different sizes, the image will be automatically resized to match the destination size. If the <b>srcImg</b> parameter is not used, the display window is used as the source image.<br><br>
* As of release 0149, this function ignores <b>imageMode()</b>.
*
* @webref
* @brief Copies a pixel or rectangle of pixels using different blending modes
* @param src an image variable referring to the source image
* @param sx X coordinate of the source's upper left corner
* @param sy Y coordinate of the source's upper left corner
* @param sw source image width
* @param sh source image height
* @param dx X coordinate of the destinations's upper left corner
* @param dy Y coordinate of the destinations's upper left corner
* @param dw destination image width
* @param dh destination image height
* @param mode Either BLEND, ADD, SUBTRACT, LIGHTEST, DARKEST, DIFFERENCE, EXCLUSION, MULTIPLY, SCREEN, OVERLAY, HARD_LIGHT, SOFT_LIGHT, DODGE, BURN
*
* @see processing.core.PGraphics#alpha(int)
* @see processing.core.PGraphics#copy(PImage, int, int, int, int, int, int, int, int)
* @see processing.core.PImage#blendColor(int,int,int) * @see processing.core.PImage#blendColor(int,int,int)
*/ */
public void blend(PImage src, public void blend(PImage src,
@ -2628,6 +2762,16 @@ public class PImage implements PConstants, Cloneable {
protected String[] saveImageFormats; protected String[] saveImageFormats;
/** /**
* Saves the image into a file. Images are saved in TIFF, TARGA, JPEG, and PNG format depending on the extension within the <b>filename</b> parameter.
* For example, "image.tif" will have a TIFF image and "image.png" will save a PNG image.
* If no extension is included in the filename, the image will save in TIFF format and <b>.tif</b> will be added to the name.
* These files are saved to the sketch's folder, which may be opened by selecting "Show sketch folder" from the "Sketch" menu.
* It is not possible to use <b>save()</b> while running the program in a web browser.<br><br>
* To save an image created within the code, rather than through loading, it's necessary to make the image with the <b>createImage()</b>
* function so it is aware of the location of the program and can therefore save the file to the right place.
* See the <b>createImage()</b> reference for more information.
*
* =advanced
* Save this image to disk. * Save this image to disk.
* <p> * <p>
* As of revision 0100, this function requires an absolute path, * As of revision 0100, this function requires an absolute path,
@ -2651,15 +2795,19 @@ public class PImage implements PConstants, Cloneable {
* The ImageIO API claims to support wbmp files, however they probably * The ImageIO API claims to support wbmp files, however they probably
* require a black and white image. Basic testing produced a zero-length * require a black and white image. Basic testing produced a zero-length
* file with no error. * file with no error.
*
* @webref
* @brief Saves the image to a TIFF, TARGA, PNG, or JPEG file
* @param filename a sequence of letters and numbers
*/ */
public void save(String path) { // ignore public void save(String filename) { // ignore
boolean success = false; boolean success = false;
File file = new File(path); File file = new File(filename);
if (!file.isAbsolute()) { if (!file.isAbsolute()) {
if (parent != null) { if (parent != null) {
//file = new File(parent.savePath(filename)); //file = new File(parent.savePath(filename));
path = parent.savePath(path); filename = parent.savePath(filename);
} else { } else {
String msg = "PImage.save() requires an absolute path. " + String msg = "PImage.save() requires an absolute path. " +
"Use createImage(), or pass savePath() to save()."; "Use createImage(), or pass savePath() to save().";
@ -2678,24 +2826,24 @@ public class PImage implements PConstants, Cloneable {
} }
if (saveImageFormats != null) { if (saveImageFormats != null) {
for (int i = 0; i < saveImageFormats.length; i++) { for (int i = 0; i < saveImageFormats.length; i++) {
if (path.endsWith("." + saveImageFormats[i])) { if (filename.endsWith("." + saveImageFormats[i])) {
saveImageIO(path); saveImageIO(filename);
return; return;
} }
} }
} }
if (path.toLowerCase().endsWith(".tga")) { if (filename.toLowerCase().endsWith(".tga")) {
os = new BufferedOutputStream(new FileOutputStream(path), 32768); os = new BufferedOutputStream(new FileOutputStream(filename), 32768);
success = saveTGA(os); //, pixels, width, height, format); success = saveTGA(os); //, pixels, width, height, format);
} else { } else {
if (!path.toLowerCase().endsWith(".tif") && if (!filename.toLowerCase().endsWith(".tif") &&
!path.toLowerCase().endsWith(".tiff")) { !filename.toLowerCase().endsWith(".tiff")) {
// if no .tif extension, add it.. // if no .tif extension, add it..
path += ".tif"; filename += ".tif";
} }
os = new BufferedOutputStream(new FileOutputStream(path), 32768); os = new BufferedOutputStream(new FileOutputStream(filename), 32768);
success = saveTIFF(os); //, pixels, width, height); success = saveTIFF(os); //, pixels, width, height);
} }
os.flush(); os.flush();

View File

@ -25,8 +25,17 @@ package processing.core;
import java.util.HashMap; import java.util.HashMap;
import processing.core.PApplet;
/** /**
* Datatype for storing shapes. Processing can currently load and display SVG (Scalable Vector Graphics) shapes.
* Before a shape is used, it must be loaded with the <b>loadShape()</b> function. The <b>shape()</b> function is used to draw the shape to the display window.
* The <b>PShape</b> object contain a group of methods, linked below, that can operate on the shape data.
* <br><br>The <b>loadShape()</b> method supports SVG files created with Inkscape and Adobe Illustrator.
* It is not a full SVG implementation, but offers some straightforward support for handling vector data.
* =advanced
*
* In-progress class to handle shape data, currently to be considered of * In-progress class to handle shape data, currently to be considered of
* alpha or beta quality. Major structural work may be performed on this class * alpha or beta quality. Major structural work may be performed on this class
* after the release of Processing 1.0. Such changes may include: * after the release of Processing 1.0. Such changes may include:
@ -51,6 +60,13 @@ import java.util.HashMap;
* <p>Library developers are encouraged to create PShape objects when loading * <p>Library developers are encouraged to create PShape objects when loading
* shape data, so that they can eventually hook into the bounty that will be * shape data, so that they can eventually hook into the bounty that will be
* the PShape interface, and the ease of loadShape() and shape().</p> * the PShape interface, and the ease of loadShape() and shape().</p>
*
* @webref Shape
* @usage Web &amp; Application
* @see PApplet#shape(PShape)
* @see PApplet#loadShape(String)
* @see PApplet#shapeMode(int)
* @instanceName sh any variable of type PShape
*/ */
public class PShape implements PConstants { public class PShape implements PConstants {
@ -81,7 +97,17 @@ public class PShape implements PConstants {
//protected float y; //protected float y;
//protected float width; //protected float width;
//protected float height; //protected float height;
/**
* The width of the PShape document.
* @webref
* @brief Shape document width
*/
public float width; public float width;
/**
* The width of the PShape document.
* @webref
* @brief Shape document height
*/
public float height; public float height;
// set to false if the object is hidden in the layers palette // set to false if the object is hidden in the layers palette
@ -178,21 +204,39 @@ public class PShape implements PConstants {
return name; return name;
} }
/**
* Returns a boolean value "true" if the image is set to be visible, "false" if not. This is modified with the <b>setVisible()</b> parameter.
* <br><br>The visibility of a shape is usually controlled by whatever program created the SVG file.
* For instance, this parameter is controlled by showing or hiding the shape in the layers palette in Adobe Illustrator.
*
* @webref
* @brief Returns a boolean value "true" if the image is set to be visible, "false" if not
*/
public boolean isVisible() { public boolean isVisible() {
return visible; return visible;
} }
/**
* Sets the shape to be visible or invisible. This is determined by the value of the <b>visible</b> parameter.
* <br><br>The visibility of a shape is usually controlled by whatever program created the SVG file.
* For instance, this parameter is controlled by showing or hiding the shape in the layers palette in Adobe Illustrator.
* @param visible "false" makes the shape invisible and "true" makes it visible
* @webref
* @brief Sets the shape to be visible or invisible
*/
public void setVisible(boolean visible) { public void setVisible(boolean visible) {
this.visible = visible; this.visible = visible;
} }
/** /**
* Disables the shape's style data and uses Processing's current styles. Styles include attributes such as colors, stroke weight, and stroke joints.
* =advanced
* Overrides this shape's style information and uses PGraphics styles and * Overrides this shape's style information and uses PGraphics styles and
* colors. Identical to ignoreStyles(true). Also disables styles for all * colors. Identical to ignoreStyles(true). Also disables styles for all
* child shapes. * child shapes.
* @webref
* @brief Disables the shape's style data and uses Processing styles
*/ */
public void disableStyle() { public void disableStyle() {
style = false; style = false;
@ -204,7 +248,9 @@ public class PShape implements PConstants {
/** /**
* Re-enables style information (fill and stroke) set in the shape. * Enables the shape's style data and ignores Processing's current styles. Styles include attributes such as colors, stroke weight, and stroke joints.
* @webref
* @brief Enables the shape's style data and ignores the Processing styles
*/ */
public void enableStyle() { public void enableStyle() {
style = true; style = true;
@ -591,12 +637,21 @@ public class PShape implements PConstants {
return childCount; return childCount;
} }
/**
*
* @param index the layer position of the shape to get
*/
public PShape getChild(int index) { public PShape getChild(int index) {
return children[index]; return children[index];
} }
/**
* Extracts a child shape from a parent shape. Specify the name of the shape with the <b>target</b> parameter.
* The shape is returned as a <b>PShape</b> object, or <b>null</b> is returned if there is an error.
* @param target the name of the shape to get
* @webref
* @brief Returns a child element of a shape as a PShape object
*/
public PShape getChild(String target) { public PShape getChild(String target) {
if (name != null && name.equals(target)) { if (name != null && name.equals(target)) {
return this; return this;
@ -675,34 +730,78 @@ public class PShape implements PConstants {
// if matrix is null when one is called, // if matrix is null when one is called,
// it is created and set to identity // it is created and set to identity
public void translate(float tx, float ty) { public void translate(float tx, float ty) {
checkMatrix(2); checkMatrix(2);
matrix.translate(tx, ty); matrix.translate(tx, ty);
} }
/**
* Specifies an amount to displace the shape. The <b>x</b> parameter specifies left/right translation, the <b>y</b> parameter specifies up/down translation, and the <b>z</b> parameter specifies translations toward/away from the screen. Subsequent calls to the method accumulates the effect. For example, calling <b>translate(50, 0)</b> and then <b>translate(20, 0)</b> is the same as <b>translate(70, 0)</b>. This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run.
* <br><br>Using this method with the <b>z</b> parameter requires using the P3D or OPENGL parameter in combination with size.
* @webref
* @param tx left/right translation
* @param ty up/down translation
* @param tz forward/back translation
* @brief Displaces the shape
*/
public void translate(float tx, float ty, float tz) { public void translate(float tx, float ty, float tz) {
checkMatrix(3); checkMatrix(3);
matrix.translate(tx, ty, 0); matrix.translate(tx, ty, 0);
} }
/**
* Rotates a shape around the x-axis the amount specified by the <b>angle</b> parameter. Angles should be specified in radians (values from 0 to TWO_PI) or converted to radians with the <b>radians()</b> method.
* <br><br>Shapes are always rotated around the upper-left corner of their bounding box. Positive numbers rotate objects in a clockwise direction.
* Subsequent calls to the method accumulates the effect. For example, calling <b>rotateX(HALF_PI)</b> and then <b>rotateX(HALF_PI)</b> is the same as <b>rotateX(PI)</b>.
* This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run.
* <br><br>This method requires a 3D renderer. You need to pass P3D or OPENGL as a third parameter into the <b>size()</b> method as shown in the example above.
* @param angle angle of rotation specified in radians
* @webref
* @brief Rotates the shape around the x-axis
*/
public void rotateX(float angle) { public void rotateX(float angle) {
rotate(angle, 1, 0, 0); rotate(angle, 1, 0, 0);
} }
/**
* Rotates a shape around the y-axis the amount specified by the <b>angle</b> parameter. Angles should be specified in radians (values from 0 to TWO_PI) or converted to radians with the <b>radians()</b> method.
* <br><br>Shapes are always rotated around the upper-left corner of their bounding box. Positive numbers rotate objects in a clockwise direction.
* Subsequent calls to the method accumulates the effect. For example, calling <b>rotateY(HALF_PI)</b> and then <b>rotateY(HALF_PI)</b> is the same as <b>rotateY(PI)</b>.
* This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run.
* <br><br>This method requires a 3D renderer. You need to pass P3D or OPENGL as a third parameter into the <b>size()</b> method as shown in the example above.
* @param angle angle of rotation specified in radians
* @webref
* @brief Rotates the shape around the y-axis
*/
public void rotateY(float angle) { public void rotateY(float angle) {
rotate(angle, 0, 1, 0); rotate(angle, 0, 1, 0);
} }
/**
* Rotates a shape around the z-axis the amount specified by the <b>angle</b> parameter. Angles should be specified in radians (values from 0 to TWO_PI) or converted to radians with the <b>radians()</b> method.
* <br><br>Shapes are always rotated around the upper-left corner of their bounding box. Positive numbers rotate objects in a clockwise direction.
* Subsequent calls to the method accumulates the effect. For example, calling <b>rotateZ(HALF_PI)</b> and then <b>rotateZ(HALF_PI)</b> is the same as <b>rotateZ(PI)</b>.
* This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run.
* <br><br>This method requires a 3D renderer. You need to pass P3D or OPENGL as a third parameter into the <b>size()</b> method as shown in the example above.
* @param angle angle of rotation specified in radians
* @webref
* @brief Rotates the shape around the z-axis
*/
public void rotateZ(float angle) { public void rotateZ(float angle) {
rotate(angle, 0, 0, 1); rotate(angle, 0, 0, 1);
} }
/**
* Rotates a shape the amount specified by the <b>angle</b> parameter. Angles should be specified in radians (values from 0 to TWO_PI) or converted to radians with the <b>radians()</b> method.
* <br><br>Shapes are always rotated around the upper-left corner of their bounding box. Positive numbers rotate objects in a clockwise direction.
* Transformations apply to everything that happens after and subsequent calls to the method accumulates the effect.
* For example, calling <b>rotate(HALF_PI)</b> and then <b>rotate(HALF_PI)</b> is the same as <b>rotate(PI)</b>.
* This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run.
* @param angle angle of rotation specified in radians
* @webref
* @brief Rotates the shape
*/
public void rotate(float angle) { public void rotate(float angle) {
checkMatrix(2); // at least 2... checkMatrix(2); // at least 2...
matrix.rotate(angle); matrix.rotate(angle);
@ -717,19 +816,33 @@ public class PShape implements PConstants {
// //
/**
* @param s percentage to scale the object
*/
public void scale(float s) { public void scale(float s) {
checkMatrix(2); // at least 2... checkMatrix(2); // at least 2...
matrix.scale(s); matrix.scale(s);
} }
public void scale(float sx, float sy) { public void scale(float x, float y) {
checkMatrix(2); checkMatrix(2);
matrix.scale(sx, sy); matrix.scale(x, y);
} }
/**
* Increases or decreases the size of a shape by expanding and contracting vertices. Shapes always scale from the relative origin of their bounding box.
* Scale values are specified as decimal percentages. For example, the method call <b>scale(2.0)</b> increases the dimension of a shape by 200%.
* Subsequent calls to the method multiply the effect. For example, calling <b>scale(2.0)</b> and then <b>scale(1.5)</b> is the same as <b>scale(3.0)</b>.
* This transformation is applied directly to the shape, it's not refreshed each time <b>draw()</b> is run.
* <br><br>Using this fuction with the <b>z</b> parameter requires passing P3D or OPENGL into the size() parameter.
* @param x percentage to scale the object in the x-axis
* @param y percentage to scale the object in the y-axis
* @param z percentage to scale the object in the z-axis
* @webref
* @brief Increases and decreases the size of a shape
*/
public void scale(float x, float y, float z) { public void scale(float x, float y, float z) {
checkMatrix(3); checkMatrix(3);
matrix.scale(x, y, z); matrix.scale(x, y, z);

View File

@ -457,8 +457,12 @@ public class PShapeSVG extends PShape {
separate = false; separate = false;
} }
if (c == '-' && !lastSeparate) { if (c == '-' && !lastSeparate) {
// allow for 'e' notation in numbers, e.g. 2.10e-9
// http://dev.processing.org/bugs/show_bug.cgi?id=1408
if (i == 0 || pathDataChars[i-1] != 'e') {
pathBuffer.append("|"); pathBuffer.append("|");
} }
}
if (c != ',') { if (c != ',') {
pathBuffer.append(c); //"" + pathDataBuffer.charAt(i)); pathBuffer.append(c); //"" + pathDataBuffer.charAt(i));
} }

View File

@ -31,6 +31,10 @@ import processing.core.PApplet;
/** /**
* XMLElement is a representation of an XML object. The object is able to parse XML code. The methods described here are the most basic. More are documented in the Developer's Reference.
* <br><br>
* The encoding parameter inside XML files is ignored, only UTF-8 (or plain ASCII) are parsed properly.
* =advanced
* XMLElement is an XML element. This is the base class used for the * XMLElement is an XML element. This is the base class used for the
* Processing XML library, representing a single node of an XML tree. * Processing XML library, representing a single node of an XML tree.
* *
@ -38,6 +42,10 @@ import processing.core.PApplet;
* *
* @author Marc De Scheemaecker * @author Marc De Scheemaecker
* @author processing.org * @author processing.org
*
* @webref data:composite
* @usage Web &amp; Application
* @instanceName xml any variable of type XMLElement
*/ */
public class XMLElement implements Serializable { public class XMLElement implements Serializable {
@ -103,6 +111,7 @@ public class XMLElement implements Serializable {
/** /**
* Creates an empty element to be used for #PCDATA content. * Creates an empty element to be used for #PCDATA content.
* @nowebref
*/ */
public XMLElement() { public XMLElement() {
this(null, null, null, NO_LINE); this(null, null, null, NO_LINE);
@ -173,6 +182,7 @@ public class XMLElement implements Serializable {
* @param namespace the namespace URI. * @param namespace the namespace URI.
* @param systemID the system ID of the XML data where the element starts. * @param systemID the system ID of the XML data where the element starts.
* @param lineNr the line in the XML data where the element starts. * @param lineNr the line in the XML data where the element starts.
* @nowebref
*/ */
public XMLElement(String fullName, public XMLElement(String fullName,
String namespace, String namespace,
@ -204,21 +214,25 @@ public class XMLElement implements Serializable {
* wraps exception handling, for more advanced exception handling, * wraps exception handling, for more advanced exception handling,
* use the constructor that takes a Reader or InputStream. * use the constructor that takes a Reader or InputStream.
* @author processing.org * @author processing.org
* @param filename * @param filename name of the XML file to load
* @param parent * @param parent typically use "this"
*/ */
public XMLElement(PApplet parent, String filename) { public XMLElement(PApplet parent, String filename) {
this(); this();
parseFromReader(parent.createReader(filename)); parseFromReader(parent.createReader(filename));
} }
/**
* @nowebref
*/
public XMLElement(Reader r) { public XMLElement(Reader r) {
this(); this();
parseFromReader(r); parseFromReader(r);
} }
/**
* @nowebref
*/
public XMLElement(String xml) { public XMLElement(String xml) {
this(); this();
parseFromReader(new StringReader(xml)); parseFromReader(new StringReader(xml));
@ -348,6 +362,8 @@ public class XMLElement implements Serializable {
* Returns the full name (i.e. the name including an eventual namespace * Returns the full name (i.e. the name including an eventual namespace
* prefix) of the element. * prefix) of the element.
* *
* @webref
* @brief Returns the name of the element.
* @return the name, or null if the element only contains #PCDATA. * @return the name, or null if the element only contains #PCDATA.
*/ */
public String getName() { public String getName() {
@ -507,9 +523,12 @@ public class XMLElement implements Serializable {
/** /**
* Returns the number of children. * Returns the number of children for the element.
* *
* @return the count. * @return the count.
* @webref
* @see processing.xml.XMLElement#getChild(int)
* @see processing.xml.XMLElement#getChildren(String)
*/ */
public int getChildCount() { public int getChildCount() {
return this.children.size(); return this.children.size();
@ -554,27 +573,35 @@ public class XMLElement implements Serializable {
/** /**
* Quick accessor for an element at a particular index. * Quick accessor for an element at a particular index.
* @author processing.org * @author processing.org
* @param index the element
*/ */
public XMLElement getChild(int which) { public XMLElement getChild(int index) {
return (XMLElement) children.elementAt(which); return (XMLElement) children.elementAt(index);
} }
/** /**
* Get a child by its name or path. * Returns the child XMLElement as specified by the <b>index</b> parameter. The value of the <b>index</b> parameter must be less than the total number of children to avoid going out of the array storing the child elements.
* @param name element name or path/to/element * When the <b>path</b> parameter is specified, then it will return all children that match that path. The path is a series of elements and sub-elements, separated by slashes.
*
* @return the element * @return the element
* @author processing.org * @author processing.org
*
* @webref
* @see processing.xml.XMLElement#getChildCount()
* @see processing.xml.XMLElement#getChildren(String)
* @brief Get a child by its name or path.
* @param path path to a particular element
*/ */
public XMLElement getChild(String name) { public XMLElement getChild(String path) {
if (name.indexOf('/') != -1) { if (path.indexOf('/') != -1) {
return getChildRecursive(PApplet.split(name, '/'), 0); return getChildRecursive(PApplet.split(path, '/'), 0);
} }
int childCount = getChildCount(); int childCount = getChildCount();
for (int i = 0; i < childCount; i++) { for (int i = 0; i < childCount; i++) {
XMLElement kid = getChild(i); XMLElement kid = getChild(i);
String kidName = kid.getName(); String kidName = kid.getName();
if (kidName != null && kidName.equals(name)) { if (kidName != null && kidName.equals(path)) {
return kid; return kid;
} }
} }
@ -681,20 +708,27 @@ public class XMLElement implements Serializable {
/** /**
* Get any children that match this name or path. Similar to getChild(), * Returns all of the children as an XMLElement array.
* but will grab multiple matches rather than only the first. * When the <b>path</b> parameter is specified, then it will return all children that match that path.
* @param name element name or path/to/element * The path is a series of elements and sub-elements, separated by slashes.
*
* @param path element name or path/to/element
* @return array of child elements that match * @return array of child elements that match
* @author processing.org * @author processing.org
*
* @webref
* @brief Returns all of the children as an XMLElement array.
* @see processing.xml.XMLElement#getChildCount()
* @see processing.xml.XMLElement#getChild(int)
*/ */
public XMLElement[] getChildren(String name) { public XMLElement[] getChildren(String path) {
if (name.indexOf('/') != -1) { if (path.indexOf('/') != -1) {
return getChildrenRecursive(PApplet.split(name, '/'), 0); return getChildrenRecursive(PApplet.split(path, '/'), 0);
} }
// if it's a number, do an index instead // if it's a number, do an index instead
// (returns a single element array, since this will be a single match // (returns a single element array, since this will be a single match
if (Character.isDigit(name.charAt(0))) { if (Character.isDigit(path.charAt(0))) {
return new XMLElement[] { getChild(Integer.parseInt(name)) }; return new XMLElement[] { getChild(Integer.parseInt(path)) };
} }
int childCount = getChildCount(); int childCount = getChildCount();
XMLElement[] matches = new XMLElement[childCount]; XMLElement[] matches = new XMLElement[childCount];
@ -702,7 +736,7 @@ public class XMLElement implements Serializable {
for (int i = 0; i < childCount; i++) { for (int i = 0; i < childCount; i++) {
XMLElement kid = getChild(i); XMLElement kid = getChild(i);
String kidName = kid.getName(); String kidName = kid.getName();
if (kidName != null && kidName.equals(name)) { if (kidName != null && kidName.equals(path)) {
matches[matchCount++] = kid; matches[matchCount++] = kid;
} }
} }
@ -887,7 +921,17 @@ public class XMLElement implements Serializable {
return getAttribute(name); return getAttribute(name);
} }
/**
* Returns a String attribute of the element.
* If the <b>default</b> parameter is used and the attribute doesn't exist, the <b>default</b> value is returned.
* When using the version of the method without the <b>default</b> parameter, if the attribute doesn't exist, the value 0 is returned.
*
* @webref
* @param name the name of the attribute
* @param default Value value returned if the attribute is not found
*
* @brief Returns a String attribute of the element.
*/
public String getStringAttribute(String name, String defaultValue) { public String getStringAttribute(String name, String defaultValue) {
return getAttribute(name, defaultValue); return getAttribute(name, defaultValue);
} }
@ -899,18 +943,24 @@ public class XMLElement implements Serializable {
return getAttribute(name, namespace, defaultValue); return getAttribute(name, namespace, defaultValue);
} }
/**
* Returns an integer attribute of the element.
*/
public int getIntAttribute(String name) { public int getIntAttribute(String name) {
return getIntAttribute(name, 0); return getIntAttribute(name, 0);
} }
/** /**
* Returns the value of an attribute. * Returns an integer attribute of the element.
* If the <b>default</b> parameter is used and the attribute doesn't exist, the <b>default</b> value is returned.
* When using the version of the method without the <b>default</b> parameter, if the attribute doesn't exist, the value 0 is returned.
* *
* @param name the non-null full name of the attribute. * @param name the name of the attribute
* @param defaultValue the default value of the attribute. * @param defaultValue value returned if the attribute is not found
* *
* @webref
* @brief Returns an integer attribute of the element.
* @return the value, or defaultValue if the attribute does not exist. * @return the value, or defaultValue if the attribute does not exist.
*/ */
public int getIntAttribute(String name, public int getIntAttribute(String name,
@ -944,12 +994,17 @@ public class XMLElement implements Serializable {
/** /**
* Returns the value of an attribute. * Returns a float attribute of the element.
* If the <b>default</b> parameter is used and the attribute doesn't exist, the <b>default</b> value is returned.
* When using the version of the method without the <b>default</b> parameter, if the attribute doesn't exist, the value 0 is returned.
* *
* @param name the non-null full name of the attribute. * @param name the name of the attribute
* @param defaultValue the default value of the attribute. * @param defaultValue value returned if the attribute is not found
* *
* @return the value, or defaultValue if the attribute does not exist. * @return the value, or defaultValue if the attribute does not exist.
*
* @webref
* @brief Returns a float attribute of the element.
*/ */
public float getFloatAttribute(String name, public float getFloatAttribute(String name,
float defaultValue) { float defaultValue) {
@ -966,6 +1021,7 @@ public class XMLElement implements Serializable {
* @param defaultValue the default value of the attribute. * @param defaultValue the default value of the attribute.
* *
* @return the value, or defaultValue if the attribute does not exist. * @return the value, or defaultValue if the attribute does not exist.
* @nowebref
*/ */
public float getFloatAttribute(String name, public float getFloatAttribute(String name,
String namespace, String namespace,
@ -1253,11 +1309,15 @@ public class XMLElement implements Serializable {
/** /**
* Returns the content of an element. If there is no such content, <b>null</b> is returned.
* =advanced
* Return the #PCDATA content of the element. If the element has a * Return the #PCDATA content of the element. If the element has a
* combination of #PCDATA content and child elements, the #PCDATA * combination of #PCDATA content and child elements, the #PCDATA
* sections can be retrieved as unnamed child objects. In this case, * sections can be retrieved as unnamed child objects. In this case,
* this method returns null. * this method returns null.
* *
* @webref
* @brief Returns the content of an element
* @return the content. * @return the content.
*/ */
public String getContent() { public String getContent() {

View File

@ -1,10 +1,85 @@
0171 core 0179 core
X Blurred PImages in OPENGL sketches X screenWidth/Height instead of screenW/H
X removed NPOT texture support (for further testing) X open up the pdf library more (philho)
X http://dev.processing.org/bugs/show_bug.cgi?id=1352 X http://dev.processing.org/bugs/show_bug.cgi?id=1343
X cache font information for the PDF library to improve setup time
X when using createFont("xxxx.ttf"), should use textMode(SHAPE) with PDF
X because ttf files will not be installed on the system when opening pdf
X added error messages for users
X bring back old-style textAscent()
X needs to just quickly run characters d and p
X only takes a couple ms, so no problem
X pdf library
X throw an error with the black boxes
X throw an error if loading fonts from a file, and not using mode(SHAPE)
X implement default font
X this can be done to replace the exception handler in PGraphics
o however it needs to be a legit font, so that it works w/ pdf
o or maybe pdf just has its own default?
X create characters on the fly when createFont() is used
o memory leak problem with fonts in JAVA2D
X can't get this to crash anymore
o http://dev.processing.org/bugs/show_bug.cgi?id=1252
earlier
X if no draw() method, and renderer is not displayable, then exit
X static mode PDFs shouldn't just hang
big ones
_ ortho() behaving differently in P3D vs OPENGL
_ http://dev.processing.org/bugs/show_bug.cgi?id=100
_ shows a blank canvas
_ (was only happening once b/c was drawing first in perspective)
_ seems to be mapping to 0, 0 - width/2, height/2
_ fix 3D > OrthoVsPerspective example once ortho works properly
_ there's a depth problem in addition to the ortho weirdness
_ modelx/y/z broken when aiming a camera
_ http://dev.processing.org/bugs/show_bug.cgi?id=1074
_ opengl + resize window => window content garbled
_ http://dev.processing.org/bugs/show_bug.cgi?id=1360
_ modify PVector to include better methods for chaining operations
_ http://dev.processing.org/bugs/show_bug.cgi?id=1415
quickies
_ img.get() weirdness
_ http://dev.processing.org/bugs/show_bug.cgi?id=1198
_ copy and blend scale when unnecessary
_ http://dev.processing.org/bugs/show_bug.cgi?id=1482
_ add a limit to pushStyle() to catch unmatched sets?
_ http://dev.processing.org/bugs/show_bug.cgi?id=1368
_ P2D transformation bug from ira
_ http://dev.processing.org/bugs/show_bug.cgi?id=1175
_ resize not working in revision 5707
_ camera() and perspective() were commented out in setSize()
_ http://dev.processing.org/bugs/show_bug.cgi?id=1391
_ chopping out triangles in OpenGL (though it's only 2D drawing)
_ http://dev.processing.org/bugs/show_bug.cgi?id=1359
_ make sure that get() and set() (for pixels and subsets) work w/ loaded images
_ make sure that get() and set() (for pixels and subsets) work w/ P2D
_ make sure that get() and set() (for pixels and subsets) work w/ P3D
_ consider adding skewX/Y
_ do them as shearX/Y
_ http://dev.processing.org/bugs/show_bug.cgi?id=1448
_ add setOutput() method across other renderers?
_ opengl applet problems
_ http://dev.processing.org/bugs/show_bug.cgi?id=1364
_ method of threading but queue an event to be run when safe
_ e.g. queueing items like mouse/keybd, but generic fxns
_ inconsistent anti-aliasing with OpenGL
_ http://dev.processing.org/bugs/show_bug.cgi?id=1413
_ modify PVector to include better methods for chaining operations
_ http://dev.processing.org/bugs/show_bug.cgi?id=1415
_ selectInput() fails when called from within keyPressed()
_ http://dev.processing.org/bugs/show_bug.cgi?id=1220
_ add java.io.Reader (and Writer?) to imports
_ open up the pdf library more (philho)
_ http://dev.processing.org/bugs/show_bug.cgi?id=1343
_ changing vertex alpha in P3D in a QUAD_STRIP is ignored _ changing vertex alpha in P3D in a QUAD_STRIP is ignored
_ with smoothing, it works fine, but with PTriangle, it's not _ with smoothing, it works fine, but with PTriangle, it's not
_ smooth() not working with applets an createGraphics(JAVA2D) _ smooth() not working with applets an createGraphics(JAVA2D)
@ -12,6 +87,9 @@ _ but works fine with applications
_ get() with OPENGL is grabbing the wrong coords _ get() with OPENGL is grabbing the wrong coords
_ http://dev.processing.org/bugs/show_bug.cgi?id=1349 _ http://dev.processing.org/bugs/show_bug.cgi?id=1349
_ gl power of 2 with textures
_ P3D also seems to have trouble w/ textures edges.. bad math?
_ No textures render with hint(ENABLE_ACCURATE_TEXTURES) _ No textures render with hint(ENABLE_ACCURATE_TEXTURES)
_ http://dev.processing.org/bugs/show_bug.cgi?id=985 _ http://dev.processing.org/bugs/show_bug.cgi?id=985
_ need to remove the hint from the reference _ need to remove the hint from the reference
@ -20,11 +98,14 @@ _ deal with issue of single pixel seam at the edge of textures
_ http://dev.processing.org/bugs/show_bug.cgi?id=602 _ http://dev.processing.org/bugs/show_bug.cgi?id=602
_ should vertexTexture() divide by width/height or width-1/height-1? _ should vertexTexture() divide by width/height or width-1/height-1?
looping/events
_ key and mouse events delivered out of order _ key and mouse events delivered out of order
_ http://dev.processing.org/bugs/show_bug.cgi?id=638 _ http://dev.processing.org/bugs/show_bug.cgi?id=638
_ key/mouse events have concurrency problems with noLoop() _ key/mouse events have concurrency problems with noLoop()
_ http://dev.processing.org/bugs/show_bug.cgi?id=1323 _ http://dev.processing.org/bugs/show_bug.cgi?id=1323
_ need to say "no drawing inside mouse/key events w/ noLoop" _ need to say "no drawing inside mouse/key events w/ noLoop"
_ redraw() doesn't work from within draw()
_ http://dev.processing.org/bugs/show_bug.cgi?id=1363
_ make the index lookup use numbers up to 256? _ make the index lookup use numbers up to 256?
@ -34,8 +115,6 @@ _ public float textWidth(char[] chars, int start, int length)
_ textAlign(JUSTIFY) (with implementation) _ textAlign(JUSTIFY) (with implementation)
_ http://dev.processing.org/bugs/show_bug.cgi?id=1309 _ http://dev.processing.org/bugs/show_bug.cgi?id=1309
_ create characters on the fly when createFont() is used
_ Semitransparent rect drawn over image not rendered correctly _ Semitransparent rect drawn over image not rendered correctly
_ http://dev.processing.org/bugs/show_bug.cgi?id=1280 _ http://dev.processing.org/bugs/show_bug.cgi?id=1280
@ -49,8 +128,6 @@ _ http://dev.processing.org/bugs/show_bug.cgi?id=1176
_ what's the difference with ascent on loadFont vs. createFont? _ what's the difference with ascent on loadFont vs. createFont?
_ noCursor() doesn't work in present mode _ noCursor() doesn't work in present mode
_ http://dev.processing.org/bugs/show_bug.cgi?id=1177 _ http://dev.processing.org/bugs/show_bug.cgi?id=1177
_ modelx/y/z broken when aiming a camera
_ http://dev.processing.org/bugs/show_bug.cgi?id=1074
_ in P2D, two vertex() line calls with fill() causes duplicate output _ in P2D, two vertex() line calls with fill() causes duplicate output
_ works fine in other renderers, has to do with tesselation _ works fine in other renderers, has to do with tesselation
_ http://dev.processing.org/bugs/show_bug.cgi?id=1191 _ http://dev.processing.org/bugs/show_bug.cgi?id=1191
@ -67,14 +144,10 @@ _ what other methods should work with doubles? all math functions?
_ seems like internal (mostly static) things, but not graphics api _ seems like internal (mostly static) things, but not graphics api
_ look into replacing nanoxml _ look into replacing nanoxml
_ http://www.exampledepot.com/egs/javax.xml.parsers/pkg.html _ http://www.exampledepot.com/egs/javax.xml.parsers/pkg.html
_ if no draw() method, and renderer is not displayable, then exit
_ static mode PDFs shouldn't just hang
[ known problems ] [ known problems ]
_ memory leak problem with fonts in JAVA2D
_ http://dev.processing.org/bugs/show_bug.cgi?id=1252
_ OPENGL sketches flicker w/ Vista when background() not used inside draw() _ OPENGL sketches flicker w/ Vista when background() not used inside draw()
_ http://dev.processing.org/bugs/show_bug.cgi?id=930 _ http://dev.processing.org/bugs/show_bug.cgi?id=930
_ Disabling Aero scheme sometimes prevents the problem _ Disabling Aero scheme sometimes prevents the problem
@ -142,16 +215,11 @@ _ make sure that filter, blend, copy, etc say that no loadPixels necessary
rework some text/font code [1.0] rework some text/font code [1.0]
_ PFont not working well with lots of characters
_ only create bitmap chars on the fly when needed (in createFont)
_ text placement is ugly, seems like fractional metrics problem _ text placement is ugly, seems like fractional metrics problem
_ http://dev.processing.org/bugs/show_bug.cgi?id=866 _ http://dev.processing.org/bugs/show_bug.cgi?id=866
_ text(char c) with char 0 and undefined should print nothing _ text(char c) with char 0 and undefined should print nothing
_ perhaps also DEL or other nonprintables? _ perhaps also DEL or other nonprintables?
_ book example 25-03 _ book example 25-03
_ when using createFont("xxxx.ttf"), should use textMode(SHAPE) with PDF
_ because ttf files will not be installed on the system when opening pdf
_ maybe just add this to the reference so that people know
_ text position is quantized in JAVA2D _ text position is quantized in JAVA2D
_ http://dev.processing.org/bugs/show_bug.cgi?id=806 _ http://dev.processing.org/bugs/show_bug.cgi?id=806
_ accessors inside PFont need a lot of work _ accessors inside PFont need a lot of work
@ -159,8 +227,6 @@ _ osx 10.5 (not 10.4) performing text width calculation differently
_ http://dev.processing.org/bugs/show_bug.cgi?id=972 _ http://dev.processing.org/bugs/show_bug.cgi?id=972
_ Automatically use textMode(SCREEN) with text() when possible _ Automatically use textMode(SCREEN) with text() when possible
_ http://dev.processing.org/bugs/show_bug.cgi?id=1020 _ http://dev.processing.org/bugs/show_bug.cgi?id=1020
_ Implement better caching mechanism when creating large fonts
_ http://dev.processing.org/bugs/show_bug.cgi?id=1111
P2D, P3D, PPolygon [1.0] P2D, P3D, PPolygon [1.0]
@ -200,19 +266,12 @@ _ also needs fix for last edge and the seam
threading and exiting threading and exiting
_ pdf sketches exiting before writing has finished
_ writing image file (missing a flush() call?) on exit() fails _ writing image file (missing a flush() call?) on exit() fails
_ lots of zero length files _ lots of zero length files
_ saveFrame() at the end of a draw mode program is problematic _ saveFrame() at the end of a draw mode program is problematic
_ app might exit before the file has finished writing to disk _ app might exit before the file has finished writing to disk
_ need to block other activity inside screenGrab until finished _ need to block other activity inside screenGrab until finished
_ http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1081706752 _ http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1081706752
_ what's up with stop() vs exit()?
_ need to get this straightened for p5 (i.e. bc has this problem)
_ make sure the main() doesn't exit until the applet has finished
_ i.e. problem with main calling itself multiple times in Alpheus
_ if exit() (or stop) is called, then System.exit() gets called,
_ even though the main() wants to keep going
_ for begin/endRecord, use a piggyback mechanism _ for begin/endRecord, use a piggyback mechanism
_ that way won't have to pass a PApplet around _ that way won't have to pass a PApplet around
@ -220,24 +279,32 @@ _ this has a big impact on the SVG library
_ in fact, this maybe should be a library that does it _ in fact, this maybe should be a library that does it
_ so that the file size can be much smaller _ so that the file size can be much smaller
_ when closing a sketch via the close box, make sure stop() getting called
X found a problem for release 0133
_ test to see if it's working
_ STROKE_WEIGHT field in PGraphics3 is a disaster, because it's an int _ STROKE_WEIGHT field in PGraphics3 is a disaster, because it's an int
_ use the SW from vertex instead.. why set stroke in triangle vars at all? _ use the SW from vertex instead.. why set stroke in triangle vars at all?
_ currently truncating to an int inside add_line_no_clip _ currently truncating to an int inside add_line_no_clip
_ need to clean all this crap up _ need to clean all this crap up
stop() mess
_ double stop() called with noLoop()
_ http://dev.processing.org/bugs/show_bug.cgi?id=1270
_ stop() not getting called _ stop() not getting called
_ http://dev.processing.org/bugs/show_bug.cgi?id=183 _ http://dev.processing.org/bugs/show_bug.cgi?id=183
_ major problem for libraries _ major problem for libraries
_ and start() is supposedly called by the applet viewer _ and start() is supposedly called by the applet viewer
_ http://java.sun.com/j2se/1.4.2/docs/api/java/applet/Applet.html#start() _ http://java.sun.com/j2se/1.4.2/docs/api/java/applet/Applet.html#start()
_ need to track this stuff down a bit _ need to track this stuff down a bit
_ when closing a sketch via the close box, make sure stop() getting called
X found a problem for release 0133
_ test to see if it's working
_ what's up with stop() vs exit()?
_ need to get this straightened for p5 (i.e. bc has this problem)
_ make sure the main() doesn't exit until the applet has finished
_ i.e. problem with main calling itself multiple times in Alpheus
_ if exit() (or stop) is called, then System.exit() gets called,
_ even though the main() wants to keep going
_ more chatter with this
_ http://dev.processing.org/bugs/show_bug.cgi?id=131
_ method of threading but queue an event to be run when safe
_ e.g. queueing items like mouse/keybd, but generic fxns
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -280,6 +347,8 @@ _ don't bother using a buffering stream, just handle internally. gah!
_ remove some of the bloat, how can we make things more compact? _ remove some of the bloat, how can we make things more compact?
_ i.e. if not using 3D, can leave out PGraphics3, PTriangle, PLine _ i.e. if not using 3D, can leave out PGraphics3, PTriangle, PLine
_ http://dev.processing.org/bugs/show_bug.cgi?id=127 _ http://dev.processing.org/bugs/show_bug.cgi?id=127
E4 _ add shuffle methods for arrays
E4 _ http://dev.processing.org/bugs/show_bug.cgi?id=1462
CORE / PApplet - main() CORE / PApplet - main()
@ -309,7 +378,8 @@ _ or if the sketch window is foremost
_ maybe a hack where a new menubar is added? _ maybe a hack where a new menubar is added?
_ --display not working on osx _ --display not working on osx
_ http://dev.processing.org/bugs/show_bug.cgi?id=531 _ http://dev.processing.org/bugs/show_bug.cgi?id=531
_ "Target VM failed to initialize" when using Present mode on Mac OS X
_ http://dev.processing.org/bugs/show_bug.cgi?id=1257
CORE / PFont and text() CORE / PFont and text()
@ -412,13 +482,6 @@ CORE / PGraphics3D
_ make thick lines draw perpendicular to the screen with P3D _ make thick lines draw perpendicular to the screen with P3D
_ http://dev.processing.org/bugs/show_bug.cgi?id=956 _ http://dev.processing.org/bugs/show_bug.cgi?id=956
_ ewjordan suggests building the quad in screen coords after perspective _ ewjordan suggests building the quad in screen coords after perspective
_ ortho() behaving differently in P3D vs OPENGL
_ http://dev.processing.org/bugs/show_bug.cgi?id=100
_ shows a blank canvas
_ (was only happening once b/c was drawing first in perspective)
_ seems to be mapping to 0, 0 - width/2, height/2
_ fix 3D > OrthoVsPerspective example once ortho works properly
_ there's a depth problem in addition to the ortho weirdness
_ improve hint(ENABLE_DEPTH_SORT) to use proper painter's algo _ improve hint(ENABLE_DEPTH_SORT) to use proper painter's algo
_ http://dev.processing.org/bugs/show_bug.cgi?id=176 _ http://dev.processing.org/bugs/show_bug.cgi?id=176
_ polygon z-order depth sorting with alpha in opengl _ polygon z-order depth sorting with alpha in opengl
@ -433,11 +496,9 @@ _ images are losing pixels at the edges
_ http://dev.processing.org/bugs/show_bug.cgi?id=102 _ http://dev.processing.org/bugs/show_bug.cgi?id=102
_ odd error with some pixels from images not drawing properly _ odd error with some pixels from images not drawing properly
_ http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1115681453 _ http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1115681453
_ clipping not yet completely implemented _ clipping not implemented
_ http://dev.processing.org/bugs/show_bug.cgi?id=1393
_ http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1114184516 _ http://processing.org/discourse/yabb_beta/YaBB.cgi?board=SoftwareBugs;action=display;num=1114184516
_ Stroking a rect() leaves off the upper right pixel
_ http://dev.processing.org/bugs/show_bug.cgi?id=501
_ clipping planes
_ http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1058491568;start=0 _ http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1058491568;start=0
_ http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1052313604;start=0 _ http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_software_bugs;action=display;num=1052313604;start=0
_ http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_Software;action=display;num=1095170607;start=0 _ http://processing.org/discourse/yabb/YaBB.cgi?board=Proce55ing_Software;action=display;num=1095170607;start=0
@ -449,6 +510,8 @@ _ or at least that things get ridiculously slow
_ clipping issues here.. but also something in scan converter _ clipping issues here.. but also something in scan converter
_ not clipping areas from offscreen _ not clipping areas from offscreen
_ huge geometry slows things way down _ huge geometry slows things way down
_ Stroking a rect() leaves off the upper right pixel
_ http://dev.processing.org/bugs/show_bug.cgi?id=501
_ box is not opaque _ box is not opaque
_ problem is that lines are drawn second _ problem is that lines are drawn second
_ one pixel lines have no z value.. argh _ one pixel lines have no z value.. argh
@ -462,6 +525,8 @@ _ box(40);
CORE / PImage CORE / PImage
_ accuracy problems make alpha channel go to FE with image.copy()
_ http://dev.processing.org/bugs/show_bug.cgi?id=1420
_ improve blend() accuracy when using ADD _ improve blend() accuracy when using ADD
_ http://dev.processing.org/bugs/show_bug.cgi?id=1008 _ http://dev.processing.org/bugs/show_bug.cgi?id=1008
_ includes code for a slow but more accurate mode _ includes code for a slow but more accurate mode
@ -603,6 +668,10 @@ LIBRARIES / PGraphicsPDF
_ pdf not rendering unicode with beginRecord() _ pdf not rendering unicode with beginRecord()
_ http://dev.processing.org/bugs/show_bug.cgi?id=727 _ http://dev.processing.org/bugs/show_bug.cgi?id=727
_ pdf sketches exiting before writing has finished
_ people have to call exit() (so that dispose() is called in particular)
_ when using noLoop() and the PDF renderer, sketch should exit gracefully
_ because isDisplayable() returns false, there's no coming back from noLoop
@ -710,3 +779,4 @@ _ exactly how should pixel filling work with single pixel strokes?
_ http://dev.processing.org/bugs/show_bug.cgi?id=1025 _ http://dev.processing.org/bugs/show_bug.cgi?id=1025
_ Writing XML files (clean up the API) _ Writing XML files (clean up the API)
_ http://dev.processing.org/bugs/show_bug.cgi?id=964 _ http://dev.processing.org/bugs/show_bug.cgi?id=964
_ consider bringing back text/image using cache/names