Merging r327:r331 of the branches/processing-sync into the trunk. This adds the Processing core, and some new features including printing, copy for discourse, better auto-format, improved keyboard shortcuts, etc.

This commit is contained in:
David A. Mellis 2007-09-25 14:04:01 +00:00
parent 413b439974
commit 616d65d32a
40 changed files with 31946 additions and 779 deletions

View File

@ -42,6 +42,7 @@ import javax.swing.undo.*;
import com.apple.mrj.*;
import com.ice.jni.registry.*;
import processing.core.*;
/**
@ -52,21 +53,8 @@ import com.ice.jni.registry.*;
* files and images, etc) that comes from that.
*/
public class Base {
static final int VERSION = 3;
static final int VERSION = 10;
static final String VERSION_NAME = "0010 Alpha";
// platform IDs for PApplet.platform
static final int WINDOWS = 1;
static final int MACOS9 = 2;
static final int MACOSX = 3;
static final int LINUX = 4;
static final int OTHER = 0;
// used by split, all the standard whitespace chars
// (uncludes unicode nbsp, that little bostage)
static final String WHITESPACE = " \t\n\r\f\u00A0";
/**
* Path of filename opened on the command line,
@ -76,79 +64,18 @@ public class Base {
Editor editor;
/**
* "1.3" or "1.1" or whatever (just the first three chars)
*/
public static final String javaVersionName =
System.getProperty("java.version").substring(0,3);
/**
* Version of Java that's in use, whether 1.1 or 1.3 or whatever,
* stored as a float.
* <P>
* Note that because this is stored as a float, the values may
* not be <EM>exactly</EM> 1.3 or 1.4. Instead, make sure you're
* comparing against 1.3f or 1.4f, which will have the same amount
* of error (i.e. 1.40000001). This could just be a double, but
* since Processing only uses floats, it's safer to do this,
* because there's no good way to specify a double with the preproc.
*/
public static final float javaVersion =
new Float(javaVersionName).floatValue();
/**
* Current platform in use, one of the
* PConstants WINDOWS, MACOSX, MACOS9, LINUX or OTHER.
*/
static public int platform;
/**
* Current platform in use.
* <P>
* Equivalent to System.getProperty("os.name"), just used internally.
*/
static public String platformName =
System.getProperty("os.name");
static {
// figure out which operating system
// this has to be first, since editor needs to know
if (platformName.toLowerCase().indexOf("mac") != -1) {
// can only check this property if running on a mac
// on a pc it throws a security exception and kills the applet
// (but on the mac it does just fine)
if (System.getProperty("mrj.version") != null) { // running on a mac
platform = (platformName.equals("Mac OS X")) ?
MACOSX : MACOS9;
}
} else {
String osname = System.getProperty("os.name");
if (osname.indexOf("Windows") != -1) {
platform = WINDOWS;
} else if (osname.equals("Linux")) { // true for the ibm vm
platform = LINUX;
} else {
platform = OTHER;
}
}
}
static public void main(String args[]) {
// make sure that this is running on java 1.4
//if (PApplet.javaVersion < 1.4f) {
if (PApplet.javaVersion < 1.4f) {
//System.err.println("no way man");
// Base.showError("Need to install Java 1.4",
// "This version of Arduino requires \n" +
// "Java 1.4 or later to run properly.\n" +
// "Please visit java.com to upgrade.", null);
// }
Base.showError("Need to install Java 1.4",
"This version of Processing requires \n" +
"Java 1.4 or later to run properly.\n" +
"Please visit java.com to upgrade.", null);
}
// grab any opened file from the command line
@ -183,14 +110,34 @@ public class Base {
// set the look and feel before opening the window
try {
if (Base.isLinux()) {
// linux is by default (motif?) even uglier than metal
// actually, i'm using native menus, so they're ugly and
// motif-looking. ick. need to fix this.
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
if (Base.isMacOS()) {
// Use the Quaqua L & F on OS X to make JFileChooser less awful
UIManager.setLookAndFeel("ch.randelshofer.quaqua.QuaquaLookAndFeel");
// undo quaqua trying to fix the margins, since we've already
// hacked that in, bit by bit, over the years
UIManager.put("Component.visualMargin", new Insets(1, 1, 1, 1));
} else if (Base.isLinux()) {
// Linux is by default even uglier than metal (Motif?).
// Actually, i'm using native menus, so they're even uglier
// and Motif-looking (Lesstif?). Ick. Need to fix this.
//String lfname = UIManager.getCrossPlatformLookAndFeelClassName();
//UIManager.setLookAndFeel(lfname);
// For 0120, trying out the gtk+ look and feel as the default.
// This is available in Java 1.4.2 and later, and it can't possibly
// be any worse than Metal. (Ocean might also work, but that's for
// Java 1.5, and we aren't going there yet)
UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
} else {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
//} catch (ClassNotFoundException cnfe) {
// just default to the native look and feel for this platform
// i.e. appears that some linux systems don't have the gtk l&f
//UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
@ -228,7 +175,7 @@ public class Base {
* specifically a Mac OS X machine because it doesn't un on OS 9 anymore.
*/
static public boolean isMacOS() {
return platform == MACOSX;
return PApplet.platform == PConstants.MACOSX;
}
@ -236,7 +183,7 @@ public class Base {
* returns true if running on windows.
*/
static public boolean isWindows() {
return platform == WINDOWS;
return PApplet.platform == PConstants.WINDOWS;
}
@ -244,7 +191,7 @@ public class Base {
* true if running on linux.
*/
static public boolean isLinux() {
return platform == LINUX;
return PApplet.platform == PConstants.LINUX;
}
@ -472,8 +419,9 @@ public class Base {
sketchbookFolder = new File(documentsFolder, "Arduino");
} catch (Exception e) {
showError("sketch folder problem",
"Could not locate default sketch folder location.", e);
//showError("Could not find folder",
// "Could not locate the Documents folder.", e);
sketchbookFolder = promptSketchbookLocation();
}
} else if (isWindows()) {
@ -502,11 +450,15 @@ public class Base {
sketchbookFolder = new File(personalPath, "Arduino");
} catch (Exception e) {
showError("Problem getting documents folder",
"Error getting the Arduino sketchbook folder.", e);
//showError("Problem getting folder",
// "Could not locate the Documents folder.", e);
sketchbookFolder = promptSketchbookLocation();
}
} else {
sketchbookFolder = promptSketchbookLocation();
/*
// on linux (or elsewhere?) prompt the user for the location
JFileChooser fc = new JFileChooser();
fc.setDialogTitle("Select the folder where " +
@ -523,6 +475,7 @@ public class Base {
} else {
System.exit(0);
}
*/
}
// create the folder if it doesn't exist already
@ -551,6 +504,68 @@ public class Base {
}
/**
* Check for a new sketchbook location.
*/
static protected File promptSketchbookLocation() {
File folder = null;
folder = new File(System.getProperty("user.home"), "sketchbook");
if (!folder.exists()) {
folder.mkdirs();
return folder;
}
folder = Base.selectFolder("Select (or create new) folder for sketches...",
null, null);
if (folder == null) {
System.exit(0);
}
return folder;
}
/**
* Implementation for choosing directories that handles both the
* Mac OS X hack to allow the native AWT file dialog, or uses
* the JFileChooser on other platforms. Mac AWT trick obtained from
* <A HREF="http://lists.apple.com/archives/java-dev/2003/Jul/msg00243.html">this post</A>
* on the OS X Java dev archive which explains the cryptic note in
* Apple's Java 1.4 release docs about the special System property.
*/
static public File selectFolder(String prompt, File folder, Frame frame) {
if (Base.isMacOS()) {
if (frame == null) frame = new Frame(); //.pack();
FileDialog fd = new FileDialog(frame, prompt, FileDialog.LOAD);
if (folder != null) {
fd.setDirectory(folder.getParent());
//fd.setFile(folder.getName());
}
System.setProperty("apple.awt.fileDialogForDirectories", "true");
fd.show();
System.setProperty("apple.awt.fileDialogForDirectories", "false");
if (fd.getFile() == null) {
return null;
}
return new File(fd.getDirectory(), fd.getFile());
} else {
JFileChooser fc = new JFileChooser();
fc.setDialogTitle(prompt);
if (folder != null) {
fc.setSelectedFile(folder);
}
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int returned = fc.showOpenDialog(new JDialog());
if (returned == JFileChooser.APPROVE_OPTION) {
return fc.getSelectedFile();
}
}
return null;
}
static public String cleanKey(String what) {
// jnireg seems to be reading the chars as bytes
// so maybe be as simple as & 0xff and then running through decoder
@ -631,20 +646,44 @@ public class Base {
// .................................................................
/**
* Given the reference filename from the keywords list,
* builds a URL and passes it to openURL.
*/
static public void showReference(String referenceFile) {
String currentDir = System.getProperty("user.dir");
openURL(currentDir + File.separator +
"reference" + File.separator +
referenceFile + ".html");
openURL(Base.getContents("reference" + File.separator + referenceFile));
}
static public void showReference() {
showReference("index.html");
}
static public void showEnvironment() {
showReference("Guide_Environment.html");
}
static public void showTroubleshooting() {
showReference("Guide_Troubleshooting.html");
}
/**
* Opens the local copy of the FAQ that's included
* with the Processing download.
*/
static public void showFAQ() {
showReference("faq.html");
}
// .................................................................
/**
* Implements the cross-platform headache of opening URLs
* TODO This code should be replaced by PApplet.link(),
* however that's not a static method (because it requires
* an AppletContext when used as an applet), so it's mildly
* trickier than just removing this method.
*/
static public void openURL(String url) {
//System.out.println("opening url " + url);
@ -707,11 +746,19 @@ public class Base {
} else if (Base.isLinux()) {
// how's mozilla sound to ya, laddie?
//Runtime.getRuntime().exec(new String[] { "mozilla", url });
String browser = Preferences.get("browser");
Runtime.getRuntime().exec(new String[] { browser, url });
//String browser = Preferences.get("browser");
//Runtime.getRuntime().exec(new String[] { browser, url });
String launcher = Preferences.get("launcher.linux");
if (launcher != null) {
Runtime.getRuntime().exec(new String[] { launcher, url });
}
} else {
System.err.println("unspecified platform");
String launcher = Preferences.get("launcher");
if (launcher != null) {
Runtime.getRuntime().exec(new String[] { launcher, url });
} else {
System.err.println("Unspecified platform, no launcher available.");
}
}
} catch (IOException e) {
@ -721,6 +768,36 @@ public class Base {
}
static boolean openFolderAvailable() {
if (Base.isWindows() || Base.isMacOS()) return true;
if (Base.isLinux()) {
// Assume that this is set to something valid
if (Preferences.get("launcher.linux") != null) {
return true;
}
// Attempt to use gnome-open
try {
Process p = Runtime.getRuntime().exec(new String[] { "gnome-open" });
int result = p.waitFor();
// Not installed will throw an IOException (JDK 1.4.2, Ubuntu 7.04)
Preferences.set("launcher.linux", "gnome-open");
return true;
} catch (Exception e) { }
// Attempt with kde-open
try {
Process p = Runtime.getRuntime().exec(new String[] { "kde-open" });
int result = p.waitFor();
Preferences.set("launcher.linux", "kde-open");
return true;
} catch (Exception e) { }
}
return false;
}
/**
* Implements the other cross-platform headache of opening
* a folder in the machine's native file browser.
@ -742,6 +819,11 @@ public class Base {
} else if (Base.isMacOS()) {
openURL(folder); // handles char replacement, etc
} else if (Base.isLinux()) {
String launcher = Preferences.get("launcher.linux");
if (launcher != null) {
Runtime.getRuntime().exec(new String[] { launcher, folder });
}
}
} catch (IOException e) {
e.printStackTrace();
@ -780,7 +862,7 @@ public class Base {
* for errors that allow P5 to continue running.
*/
static public void showError(String title, String message,
Exception e) {
Throwable e) {
if (title == null) title = "Error";
JOptionPane.showMessageDialog(new Frame(), message, title,
JOptionPane.ERROR_MESSAGE);
@ -793,23 +875,29 @@ public class Base {
// ...................................................................
static public String getContents(String what) {
String basePath = System.getProperty("user.dir");
/*
// do this later, when moving to .app package
if (PApplet.platform == PConstants.MACOSX) {
basePath = System.getProperty("processing.contents");
}
*/
return basePath + File.separator + what;
}
static public String getLibContents(String what) {
return getContents("lib" + File.separator + what);
}
static public Image getImage(String name, Component who) {
Image image = null;
Toolkit tk = Toolkit.getDefaultToolkit();
//if ((Base.platform == Base.MACOSX) ||
//(Base.platform == Base.MACOS9)) {
image = tk.getImage("lib/" + name);
//} else {
//image = tk.getImage(who.getClass().getResource(name));
//}
//image = tk.getImage("lib/" + name);
//URL url = PdeApplet.class.getResource(name);
//image = tk.getImage(url);
//}
//MediaTracker tracker = new MediaTracker(applet);
MediaTracker tracker = new MediaTracker(who); //frame);
image = tk.getImage(getLibContents(name));
MediaTracker tracker = new MediaTracker(who);
tracker.addImage(image, 0);
try {
tracker.waitForAll();
@ -819,17 +907,7 @@ public class Base {
static public InputStream getStream(String filename) throws IOException {
//if (Base.platform == Base.MACOSX) {
// macos doesn't seem to think that files in the lib folder
// are part of the resources, unlike windows or linux.
// actually, this is only the case when running as a .app,
// since it works fine from run.sh, but not Arduino.app
return new FileInputStream("lib/" + filename);
//}
// all other, more reasonable operating systems
//return cls.getResource(filename).openStream();
//return Base.class.getResource(filename).openStream();
return new FileInputStream(getLibContents(filename));
}
@ -965,7 +1043,7 @@ public class Base {
if (!Preferences.getBoolean("compiler.save_build_files")) {
if (!dead.delete()) {
// temporarily disabled
//System.err.println("couldn't delete " + dead);
System.err.println("Could not delete " + dead);
}
}
} else {
@ -1040,197 +1118,4 @@ public class Base {
}
}
}
/**
* Equivalent to the one in PApplet, but static (die() is removed)
*/
static public String[] loadStrings(File file) {
try {
FileInputStream input = new FileInputStream(file);
BufferedReader reader =
new BufferedReader(new InputStreamReader(input));
String lines[] = new String[100];
int lineCount = 0;
String line = null;
while ((line = reader.readLine()) != null) {
if (lineCount == lines.length) {
String temp[] = new String[lineCount << 1];
System.arraycopy(lines, 0, temp, 0, lineCount);
lines = temp;
}
lines[lineCount++] = line;
}
reader.close();
if (lineCount == lines.length) {
return lines;
}
// resize array to appropraite amount for these lines
String output[] = new String[lineCount];
System.arraycopy(lines, 0, output, 0, lineCount);
return output;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
//////////////////////////////////////////////////////////////
// STRINGS
/**
* Remove whitespace characters from the beginning and ending
* of a String. Works like String.trim() but includes the
* unicode nbsp character as well.
*/
static public String trim(String str) {
return str.replace('\u00A0', ' ').trim();
/*
int left = 0;
int right = str.length() - 1;
while ((left <= right) &&
(WHITESPACE.indexOf(str.charAt(left)) != -1)) left++;
if (left == right) return "";
while (WHITESPACE.indexOf(str.charAt(right)) != -1) --right;
return str.substring(left, right-left+1);
*/
}
/**
* Join an array of Strings together as a single String,
* separated by the whatever's passed in for the separator.
*/
static public String join(String str[], char separator) {
return join(str, String.valueOf(separator));
}
/**
* Join an array of Strings together as a single String,
* separated by the whatever's passed in for the separator.
* <P>
* To use this on numbers, first pass the array to nf() or nfs()
* to get a list of String objects, then use join on that.
* <PRE>
* e.g. String stuff[] = { "apple", "bear", "cat" };
* String list = join(stuff, ", ");
* // list is now "apple, bear, cat"</PRE>
*/
static public String join(String str[], String separator) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < str.length; i++) {
if (i != 0) buffer.append(separator);
buffer.append(str[i]);
}
return buffer.toString();
}
/**
* Split the provided String at wherever whitespace occurs.
* Multiple whitespace (extra spaces or tabs or whatever)
* between items will count as a single break.
* <P>
* The whitespace characters are "\t\n\r\f", which are the defaults
* for java.util.StringTokenizer, plus the unicode non-breaking space
* character, which is found commonly on files created by or used
* in conjunction with Mac OS X (character 160, or 0x00A0 in hex).
* <PRE>
* i.e. split("a b") -> { "a", "b" }
* split("a b") -> { "a", "b" }
* split("a\tb") -> { "a", "b" }
* split("a \t b ") -> { "a", "b" }</PRE>
*/
static public String[] split(String what) {
return split(what, WHITESPACE);
}
/**
* Splits a string into pieces, using any of the chars in the
* String 'delim' as separator characters. For instance,
* in addition to white space, you might want to treat commas
* as a separator. The delimeter characters won't appear in
* the returned String array.
* <PRE>
* i.e. split("a, b", " ,") -> { "a", "b" }
* </PRE>
* To include all the whitespace possibilities, use the variable
* WHITESPACE, found in PConstants:
* <PRE>
* i.e. split("a | b", WHITESPACE + "|"); -> { "a", "b" }</PRE>
*/
static public String[] split(String what, String delim) {
StringTokenizer toker = new StringTokenizer(what, delim);
String pieces[] = new String[toker.countTokens()];
int index = 0;
while (toker.hasMoreTokens()) {
pieces[index++] = toker.nextToken();
}
return pieces;
}
/**
* Split a string into pieces along a specific character.
* Most commonly used to break up a String along tab characters.
* <P>
* This operates differently than the others, where the
* single delimeter is the only breaking point, and consecutive
* delimeters will produce an empty string (""). This way,
* one can split on tab characters, but maintain the column
* alignments (of say an excel file) where there are empty columns.
*/
static public String[] split(String what, char delim) {
// do this so that the exception occurs inside the user's
// program, rather than appearing to be a bug inside split()
if (what == null) return null;
//return split(what, String.valueOf(delim)); // huh
char chars[] = what.toCharArray();
int splitCount = 0; //1;
for (int i = 0; i < chars.length; i++) {
if (chars[i] == delim) splitCount++;
}
// make sure that there is something in the input string
//if (chars.length > 0) {
// if the last char is a delimeter, get rid of it..
//if (chars[chars.length-1] == delim) splitCount--;
// on second thought, i don't agree with this, will disable
//}
if (splitCount == 0) {
String splits[] = new String[1];
splits[0] = new String(what);
return splits;
}
//int pieceCount = splitCount + 1;
String splits[] = new String[splitCount + 1];
int splitIndex = 0;
int startIndex = 0;
for (int i = 0; i < chars.length; i++) {
if (chars[i] == delim) {
splits[splitIndex++] =
new String(chars, startIndex, i-startIndex);
startIndex = i + 1;
}
}
//if (startIndex != chars.length) {
splits[splitIndex] =
new String(chars, startIndex, chars.length-startIndex);
//}
return splits;
}
}

View File

@ -28,11 +28,13 @@ package processing.app;
import processing.app.syntax.*;
import processing.app.tools.*;
import processing.core.*;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.awt.event.*;
import java.awt.print.*;
import java.io.*;
import java.lang.reflect.*;
import java.net.*;
@ -45,7 +47,9 @@ import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.undo.*;
import com.apple.mrj.*;
import com.oroinc.text.regex.*;
//import de.hunsicker.jalopy.*;
import com.apple.mrj.*;
import gnu.io.*;
@ -78,6 +82,9 @@ public class Editor extends JFrame
boolean handleNewShift;
boolean handleNewLibrary;
PageFormat pageFormat;
PrinterJob printerJob;
EditorButtons buttons;
EditorHeader header;
EditorStatus status;
@ -133,14 +140,12 @@ public class Editor extends JFrame
// used internally, and only briefly
CompoundEdit compoundEdit;
//static public UndoManager undo = new UndoManager(); // editor needs this guy
//
//SketchHistory history; // TODO re-enable history
Sketchbook sketchbook;
//Preferences preferences;
//FindReplace find;
FindReplace find;
//static Properties keywords; // keyword -> reference html lookup
@ -167,9 +172,13 @@ public class Editor extends JFrame
// add listener to handle window close box hit event
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
handleQuit();
handleQuitInternal();
}
});
// don't close the window when clicked, the app will take care
// of that via the handleQuitInternal() methods
// http://dev.processing.org/bugs/show_bug.cgi?id=440
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
PdeKeywords keywords = new PdeKeywords();
sketchbook = new Sketchbook(this);
@ -188,8 +197,14 @@ public class Editor extends JFrame
// doesn't matter when this is created, just make it happen at some point
//find = new FindReplace(Editor.this);
Container pain = getContentPane();
//Container pain = getContentPane();
//pain.setLayout(new BorderLayout());
// for rev 0120, placing things inside a JPanel because
Container contentPain = getContentPane();
contentPain.setLayout(new BorderLayout());
JPanel pain = new JPanel();
pain.setLayout(new BorderLayout());
contentPain.add(pain, BorderLayout.CENTER);
Box box = Box.createVerticalBox();
Box upper = Box.createVerticalBox();
@ -251,6 +266,17 @@ public class Editor extends JFrame
listener = new EditorListener(this, textarea);
pain.add(box);
pain.setTransferHandler(new TransferHandler() {
public boolean canImport(JComponent dest, DataFlavor[] flavors) {
// claim that we can import everything
return true;
}
public boolean importData(JComponent src, Transferable transferable) {
DataFlavor[] flavors = transferable.getTransferDataFlavors();
/*
DropTarget dt = new DropTarget(this, new DropTargetListener() {
public void dragEnter(DropTargetDragEvent event) {
@ -278,14 +304,17 @@ public class Editor extends JFrame
Transferable transferable = event.getTransferable();
DataFlavor flavors[] = transferable.getTransferDataFlavors();
*/
int successful = 0;
for (int i = 0; i < flavors.length; i++) {
try {
//System.out.println(flavors[i]);
//System.out.println(transferable.getTransferData(flavors[i]));
java.util.List list =
(java.util.List) transferable.getTransferData(flavors[i]);
Object stuff = transferable.getTransferData(flavors[i]);
if (!(stuff instanceof java.util.List)) continue;
java.util.List list = (java.util.List) stuff;
for (int j = 0; j < list.size(); j++) {
Object item = list.get(j);
if (item instanceof File) {
@ -298,7 +327,7 @@ public class Editor extends JFrame
File parent = file.getParentFile();
if (name.equals(parent.getName())) {
handleOpenFile(file);
return;
return true;
}
}
@ -310,6 +339,7 @@ public class Editor extends JFrame
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
@ -322,6 +352,7 @@ public class Editor extends JFrame
} else {
message(successful + " files added to the sketch.");
}
return true;
}
});
}
@ -488,7 +519,9 @@ public class Editor extends JFrame
listener.applyPreferences();
// in case moved to a new location
sketchbook.rebuildMenus();
// For 0125, changing to async version (to be implemented later)
//sketchbook.rebuildMenus();
sketchbook.rebuildMenusAsync();
}
@ -576,11 +609,19 @@ public class Editor extends JFrame
menu.addSeparator();
item = newJMenuItem("Page Setup", 'P', true);
item.setEnabled(false);
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
handlePageSetup();
}
});
menu.add(item);
item = newJMenuItem("Print", 'P');
item.setEnabled(false);
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
handlePrint();
}
});
menu.add(item);
// macosx already has its own preferences and quit menu
@ -600,7 +641,7 @@ public class Editor extends JFrame
item = newJMenuItem("Quit", 'Q');
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
handleQuit();
handleQuitInternal();
}
});
menu.add(item);
@ -639,17 +680,9 @@ public class Editor extends JFrame
menu.addSeparator();
item = new JMenuItem("Add File...");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
sketch.addFile();
}
});
menu.add(item);
menu.add(sketchbook.getImportMenu());
if (Base.isWindows() || Base.isMacOS()) {
//if (Base.isWindows() || Base.isMacOS()) {
// no way to do an 'open in file browser' on other platforms
// since there isn't any sort of standard
item = newJMenuItem("Show Sketch Folder", 'K', false);
@ -660,8 +693,20 @@ public class Editor extends JFrame
}
});
menu.add(item);
if (!Base.openFolderAvailable()) {
item.setEnabled(false);
}
//menu.addSeparator();
item = new JMenuItem("Add File...");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
sketch.addFile();
}
});
menu.add(item);
// TODO re-enable history
//history.attachMenu(menu);
return menu;
@ -681,20 +726,39 @@ public class Editor extends JFrame
item.addActionListener(new ActionListener() {
synchronized public void actionPerformed(ActionEvent e) {
new AutoFormat(Editor.this).show();
//handleBeautify();
/*
Jalopy jalopy = new Jalopy();
jalopy.setInput(getText(), sketch.current.file.getAbsolutePath());
StringBuffer buffer = new StringBuffer();
jalopy.setOutput(buffer);
jalopy.setInspect(false);
jalopy.format();
setText(buffer.toString(), 0, 0);
if (jalopy.getState() == Jalopy.State.OK)
System.out.println("successfully formatted");
else if (jalopy.getState() == Jalopy.State.WARN)
System.out.println(" formatted with warnings");
else if (jalopy.getState() == Jalopy.State.ERROR)
System.out.println(" could not be formatted");
*/
}
});
menu.add(item);
/*item = new JMenuItem("Create Font...");
item = new JMenuItem("Copy for Discourse");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//new CreateFont().show(sketch.dataFolder);
new CreateFont(Editor.this).show();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new DiscourseFormat(Editor.this).show();
}
});
}
});
menu.add(item);
*/
item = new JMenuItem("Archive Sketch");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
@ -706,13 +770,17 @@ public class Editor extends JFrame
});
menu.add(item);
/*
item = new JMenuItem("Export Folder...");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new ExportFolder(Editor.this).show();
}
});
menu.add(item);
*/
menu.addSeparator();
mcuMenu = new JMenu("Microcontroller (MCU)");
@ -946,21 +1014,18 @@ public class Editor extends JFrame
menu.add(item);
}
item = new JMenuItem("Troubleshooting");
item = new JMenuItem("Environment");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Base.openURL(System.getProperty("user.dir") + File.separator +
"reference" + File.separator +
"Guide_Troubleshooting.html");
Base.showEnvironment();
}
});
menu.add(item);
item = new JMenuItem("Environment");
item = new JMenuItem("Troubleshooting");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Base.openURL(System.getProperty("user.dir") + File.separator +
"reference" + File.separator + "Guide_Environment.html");
Base.showTroubleshooting();
}
});
menu.add(item);
@ -968,8 +1033,17 @@ public class Editor extends JFrame
item = new JMenuItem("Reference");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Base.openURL(System.getProperty("user.dir") + File.separator +
"reference" + File.separator + "index.html");
Base.showReference();
}
});
menu.add(item);
item = newJMenuItem("Find in Reference", 'F', true);
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (textarea.isSelectionActive()) {
handleReference();
}
}
});
menu.add(item);
@ -977,33 +1051,11 @@ public class Editor extends JFrame
item = new JMenuItem("Frequently Asked Questions");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Base.openURL(System.getProperty("user.dir") + File.separator +
"reference" + File.separator + "FAQ.html");
Base.showFAQ();
}
});
menu.add(item);
// item = newJMenuItem("Find in Reference", 'F', true);
// item.addActionListener(new ActionListener() {
// public void actionPerformed(ActionEvent e) {
// if (textarea.isSelectionActive()) {
// String text = textarea.getSelectedText();
// if (text.length() == 0) {
// message("First select a word to find in the reference.");
//
// } else {
// String referenceFile = PdeKeywords.getReference(text);
// if (referenceFile == null) {
// message("No reference available for \"" + text + "\"");
// } else {
// Base.showReference(referenceFile);
// }
// }
// }
// }
// });
// menu.add(item);
item = newJMenuItem("Visit www.arduino.cc", '5');
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
@ -1083,22 +1135,27 @@ public class Editor extends JFrame
item = newJMenuItem("Find...", 'F');
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
new FindReplace(Editor.this).show();
//find.show();
if (find == null) {
find = new FindReplace(Editor.this);
}
//new FindReplace(Editor.this).show();
find.show();
//find.setVisible(true);
}
});
menu.add(item);
// TODO find next should only be enabled after a
// search has actually taken place
item = newJMenuItem("Find Next", 'G');
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// TODO find next should only be enabled after a
// search has actually taken place
if (find != null) {
//find.find(true);
FindReplace find = new FindReplace(Editor.this); //.show();
//FindReplace find = new FindReplace(Editor.this); //.show();
find.find(true);
}
}
});
menu.add(item);
@ -1116,9 +1173,9 @@ public class Editor extends JFrame
/**
* A software engineer, somewhere, needs to have his abstraction
* taken away. In some countries they jail people for writing the
* sort of crappy api that would require a four line helper function
* to set the command key for a menu item.
* taken away. In some countries they jail or beat people for writing
* the sort of API that would require a five line helper function
* just to set the command key for a menu item.
*/
static public JMenuItem newJMenuItem(String title,
int what, boolean shift) {
@ -1191,7 +1248,6 @@ public class Editor extends JFrame
protected void updateRedoState() {
if (undo.canRedo()) {
//this.setEnabled(true);
redoItem.setEnabled(true);
redoItem.setText(undo.getRedoPresentationName());
putValue(Action.NAME, undo.getRedoPresentationName());
@ -1339,10 +1395,12 @@ public class Editor extends JFrame
redoAction.updateRedoState();
}
public void beginCompoundEdit() {
compoundEdit = new CompoundEdit();
}
public void endCompoundEdit() {
compoundEdit.end();
undo.addEdit(compoundEdit);
@ -1352,6 +1410,8 @@ public class Editor extends JFrame
}
// ...................................................................
public void handleRun(final boolean present) {
doClose();
@ -1576,42 +1636,71 @@ public class Editor extends JFrame
String prompt = "Save changes to " + sketch.name + "? ";
if (checkModifiedMode != HANDLE_QUIT) {
// if the user is not quitting, then use the nicer
// if the user is not quitting, then use simpler nicer
// dialog that's actually inside the p5 window.
status.prompt(prompt);
} else {
// if the user selected quit, then this has to be done with
// a JOptionPane instead of internally in the editor.
// TODO this is actually just a bug to be fixed.
// macosx java kills the app even though cancel might get hit
// so the cancel button is (temporarily) left off
// this may be treated differently in macosx java 1.4,
// but 1.4 isn't currently stable enough to use.
// turns out windows has the same problem (sometimes)
// disable cancel for now until a fix can be found.
Object[] options = { "Yes", "No" };
int result = JOptionPane.showOptionDialog(this,
prompt,
"Quit",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE,
null,
options,
options[0]);
if (!Base.isMacOS() || PApplet.javaVersion < 1.5f) {
int result =
JOptionPane.showConfirmDialog(this, prompt, "Quit",
JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.QUESTION_MESSAGE);
if (result == JOptionPane.YES_OPTION) {
handleSave(true);
checkModified2();
} else if (result == JOptionPane.NO_OPTION) {
checkModified2(); // though this may just quit
checkModified2();
}
// cancel is ignored altogether
} else if (result == JOptionPane.CANCEL_OPTION) {
// ignored
} else {
// This code is disabled unless Java 1.5 is being used on Mac OS X
// because of a Java bug that prevents the initial value of the
// dialog from being set properly (at least on my MacBook Pro).
// The bug causes the "Don't Save" option to be the highlighted,
// blinking, default. This sucks. But I'll tell you what doesn't
// suck--workarounds for the Mac and Apple's snobby attitude about it!
// 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(this, null);
dialog.show();
Object result = pane.getValue();
if (result == options[0]) { // save (and quit)
handleSave(true);
checkModified2();
} else if (result == options[2]) { // don't save (still quit)
checkModified2();
}
}
}
}
@ -1739,9 +1828,15 @@ public class Editor extends JFrame
* Open a sketch from a particular path, but don't check to save changes.
* Used by Sketch.saveAs() to re-open a sketch after the "Save As"
*/
public void handleOpenUnchecked(String path) {
public void handleOpenUnchecked(String path, int codeIndex,
int selStart, int selStop, int scrollPos) {
doClose();
handleOpen2(path);
sketch.setCurrent(codeIndex);
textarea.select(selStart, selStop);
//textarea.updateScrollBars();
textarea.setScrollPosition(scrollPos);
}
@ -1761,7 +1856,8 @@ public class Editor extends JFrame
if (!oldPath.equals(newPath)) {
if (Base.calcFolderSize(sketch.folder) == 0) {
Base.removeDir(sketch.folder);
sketchbook.rebuildMenus();
//sketchbook.rebuildMenus();
sketchbook.rebuildMenusAsync();
}
}
} catch (Exception e) { } // oh well
@ -1893,7 +1989,11 @@ public class Editor extends JFrame
message(EMPTY);
}
// rebuild sketch menu in case a save-as was forced
sketchbook.rebuildMenus();
// Disabling this for 0125, instead rebuild the menu inside
// the Save As method of the Sketch object, since that's the
// only one who knows whether something was renamed.
//sketchbook.rebuildMenus();
//sketchbook.rebuildMenusAsync();
} catch (Exception e) {
// show the error as a message in the window
@ -1918,7 +2018,10 @@ public class Editor extends JFrame
try {
if (sketch.saveAs()) {
message("Done Saving.");
sketchbook.rebuildMenus();
// Disabling this for 0125, instead rebuild the menu inside
// the Save As method of the Sketch object, since that's the
// only one who knows whether something was renamed.
//sketchbook.rebuildMenusAsync();
} else {
message("Save Cancelled.");
}
@ -2007,6 +2110,7 @@ public class Editor extends JFrame
null,
options,
options[0]);
if (result == JOptionPane.OK_OPTION) {
handleSave(true);
@ -2021,13 +2125,57 @@ public class Editor extends JFrame
return true;
}
public void handlePageSetup() {
//printerJob = null;
if (printerJob == null) {
printerJob = PrinterJob.getPrinterJob();
}
if (pageFormat == null) {
pageFormat = printerJob.defaultPage();
}
pageFormat = printerJob.pageDialog(pageFormat);
//System.out.println("page format is " + pageFormat);
}
public void handlePrint() {
message("Printing...");
//printerJob = null;
if (printerJob == null) {
printerJob = PrinterJob.getPrinterJob();
}
if (pageFormat != null) {
//System.out.println("setting page format " + pageFormat);
printerJob.setPrintable(textarea.getPainter(), pageFormat);
} else {
printerJob.setPrintable(textarea.getPainter());
}
// set the name of the job to the code name
printerJob.setJobName(sketch.current.name);
if (printerJob.printDialog()) {
try {
printerJob.print();
message("Done printing.");
} catch (PrinterException pe) {
error("Error while printing.");
pe.printStackTrace();
}
} else {
message("Printing canceled.");
}
//printerJob = null; // clear this out?
}
/**
* Quit, but first ask user if it's ok. Also store preferences
* to disk just in case they want to quit. Final exit() happens
* in Editor since it has the callback from EditorStatus.
*/
public void handleQuit() {
public void handleQuitInternal() {
// doStop() isn't sufficient with external vm & quit
// instead use doClose() which will kill the external vm
doClose();
@ -2036,6 +2184,27 @@ public class Editor extends JFrame
}
/**
* Method for the MRJQuitHandler, needs to be dealt with differently
* than the regular handler because OS X has an annoying implementation
* <A HREF="http://developer.apple.com/qa/qa2001/qa1187.html">quirk</A>
* that requires an exception to be thrown in order to properly cancel
* a quit message.
*/
public void handleQuit() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
handleQuitInternal();
}
});
// Throw IllegalStateException so new thread can execute.
// If showing dialog on this thread in 10.2, we would throw
// upon JOptionPane.NO_OPTION
throw new IllegalStateException("Quit Pending User Confirmation");
}
/**
* Actually do the quit action.
*/
@ -2050,6 +2219,26 @@ public class Editor extends JFrame
System.exit(0);
}
protected void handleReference() {
String text = textarea.getSelectedText().trim();
if (text.length() == 0) {
message("First select a word to find in the reference.");
} else {
String referenceFile = PdeKeywords.getReference(text);
//System.out.println("reference file is " + referenceFile);
if (referenceFile == null) {
message("No reference available for \"" + text + "\"");
} else {
Base.showReference(referenceFile + ".html");
}
}
}
protected void handleBurnBootloader(final String target, final boolean parallel) {
if(debugging)
doStop();
@ -2083,6 +2272,7 @@ public class Editor extends JFrame
}});
}
public void highlightLine(int lnum) {
if (lnum < 0) {
textarea.select(0, 0);
@ -2169,7 +2359,7 @@ public class Editor extends JFrame
public void error(RunnerException e) {
//System.out.println("ERORROOROROR 2");
//System.out.println("file and line is " + e.file + " " + e.line);
if (e.file >= 0) sketch.setCurrent(e.file);
if (e.line >= 0) highlightLine(e.line);
@ -2205,7 +2395,7 @@ public class Editor extends JFrame
* Returns the edit popup menu.
*/
class TextAreaPopup extends JPopupMenu {
String currentDir = System.getProperty("user.dir");
//String currentDir = System.getProperty("user.dir");
String referenceFile = null;
JMenuItem cutItem, copyItem;
@ -2251,13 +2441,14 @@ public class Editor extends JFrame
this.addSeparator();
// referenceItem = new JMenuItem("Find in Reference");
// referenceItem.addActionListener(new ActionListener() {
// public void actionPerformed(ActionEvent e) {
// Base.showReference(referenceFile);
// }
// });
// this.add(referenceItem);
referenceItem = new JMenuItem("Find in Reference");
referenceItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//Base.showReference(referenceFile + ".html");
handleReference(); //textarea.getSelectedText());
}
});
this.add(referenceItem);
}
// if no text is selected, disable copy and cut menu items
@ -2266,14 +2457,14 @@ public class Editor extends JFrame
cutItem.setEnabled(true);
copyItem.setEnabled(true);
//referenceFile = PdeKeywords.getReference(textarea.getSelectedText());
//if (referenceFile != null) {
//referenceItem.setEnabled(true);
//}
String sel = textarea.getSelectedText().trim();
referenceFile = PdeKeywords.getReference(sel);
referenceItem.setEnabled(referenceFile != null);
} else {
cutItem.setEnabled(false);
copyItem.setEnabled(false);
//referenceItem.setEnabled(false);
referenceItem.setEnabled(false);
}
super.show(component, x, y);
}

View File

@ -241,6 +241,7 @@ public class EditorHeader extends JComponent {
public void rebuildMenu() {
//System.out.println("rebuilding");
if (menu != null) {
menu.removeAll();
@ -248,6 +249,9 @@ public class EditorHeader extends JComponent {
menu = new JMenu();
popup = menu.getPopupMenu();
add(popup);
popup.setLightWeightPopupEnabled(true);
/*
popup.addPopupMenuListener(new PopupMenuListener() {
public void popupMenuCanceled(PopupMenuEvent e) {
// on redraw, the isVisible() will get checked.
@ -259,6 +263,7 @@ public class EditorHeader extends JComponent {
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { }
public void popupMenuWillBecomeVisible(PopupMenuEvent e) { }
});
*/
}
JMenuItem item;
@ -352,6 +357,43 @@ public class EditorHeader extends JComponent {
}
menu.add(unhide);
menu.addSeparator();
// KeyEvent.VK_LEFT and VK_RIGHT will make Windows beep
int ctrlAlt = ActionEvent.ALT_MASK |
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
//item = Editor.newJMenuItem("Previous Tab", '[', true);
item = new JMenuItem("Previous Tab");
//int shortcut = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
KeyStroke ctrlAltLeft = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, ctrlAlt);
item.setAccelerator(ctrlAltLeft);
//int modifiers = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
//KeyStroke tabby = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, modifiers);
// this didn't want to work consistently
/*
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
editor.sketch.prevCode();
}
});
*/
menu.add(item);
//item = Editor.newJMenuItem("Next Tab", ']', true);
item = new JMenuItem("Next Tab");
KeyStroke ctrlAltRight = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, ctrlAlt);
item.setAccelerator(ctrlAltRight);
/*
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
editor.sketch.nextCode();
}
});
*/
menu.add(item);
if (sketch != null) {
menu.addSeparator();

View File

@ -60,6 +60,10 @@ public class EditorListener {
int selectionStart, selectionEnd;
int position;
/** ctrl-alt on windows and linux, cmd-alt on mac os x */
static final int CTRL_ALT = ActionEvent.ALT_MASK |
Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
public EditorListener(Editor editor, JEditTextArea textarea) {
this.editor = editor;
@ -105,6 +109,16 @@ public class EditorListener {
//System.out.println(c + " " + code + " " + event);
//System.out.println();
if ((event.getModifiers() & CTRL_ALT) == CTRL_ALT) {
if (code == KeyEvent.VK_LEFT) {
editor.sketch.prevCode();
return true;
} else if (code == KeyEvent.VK_RIGHT) {
editor.sketch.nextCode();
return true;
}
}
if ((event.getModifiers() & KeyEvent.META_MASK) != 0) {
//event.consume(); // does nothing
return false;
@ -195,8 +209,8 @@ public class EditorListener {
switch ((int) c) {
case 9: // expand tabs
if (tabsExpand) {
case 9:
if (tabsExpand) { // expand tabs
textarea.setSelectedText(tabString);
event.consume();
return true;
@ -286,12 +300,40 @@ public class EditorListener {
origIndex += offset; // ARGH!#(* WINDOWS#@($*
*/
// if the previous thing is a brace (whether prev line or
// up farther) then the correct indent is the number of spaces
// on that line + 'indent'.
// if the previous line is not a brace, then just use the
// identical indentation to the previous line
// calculate the amount of indent on the previous line
// this will be used *only if the prev line is not an indent*
int spaceCount = calcSpaceCount(origIndex, contents);
//int origCount = spaceCount;
// If the last character was a left curly brace, then indent.
// For 0122, walk backwards a bit to make sure that the there
// isn't a curly brace several spaces (or lines) back. Also
// moved this before calculating extraCount, since it'll affect
// that as well.
int index2 = origIndex;
while ((index2 >= 0) &&
Character.isWhitespace(contents[index2])) {
index2--;
}
if (index2 != -1) {
// still won't catch a case where prev stuff is a comment
if (contents[index2] == '{') {
// intermediate lines be damned,
// use the indent for this line instead
spaceCount = calcSpaceCount(index2, contents);
spaceCount += tabSize;
}
}
//System.out.println("spaceCount should be " + spaceCount);
// now before inserting this many spaces, walk forward from
// the caret position, so that the number of spaces aren't
// just being duplicated again
// the caret position and count the number of spaces,
// so that the number of spaces aren't duplicated again
int index = origIndex + 1;
int extraCount = 0;
while ((index < contents.length) &&
@ -300,23 +342,58 @@ public class EditorListener {
extraCount++;
index++;
}
int braceCount = 0;
while ((index < contents.length) && (contents[index] != '\n')) {
if (contents[index] == '}') {
braceCount++;
}
index++;
}
// hitting return on a line with spaces *after* the caret
// can cause trouble. for simplicity's sake, just ignore this case.
//if (spaceCount < 0) spaceCount = origCount;
// can cause trouble. for 0099, was ignoring the case, but this is
// annoying, so in 0122 we're trying to fix that.
/*
if (spaceCount - extraCount > 0) {
spaceCount -= extraCount;
}
*/
spaceCount -= extraCount;
//if (spaceCount < 0) spaceCount = 0;
//System.out.println("extraCount is " + extraCount);
// if the last character was a left curly brace, then indent
if (origIndex != -1) {
if (contents[origIndex] == '{') {
spaceCount += tabSize;
}
}
// now, check to see if the current line contains a } and if so,
// outdent again by indent
//if (braceCount > 0) {
//spaceCount -= 2;
//}
if (spaceCount < 0) {
// for rev 0122, actually delete extra space
//textarea.setSelectionStart(origIndex + 1);
textarea.setSelectionEnd(textarea.getSelectionEnd() - spaceCount);
textarea.setSelectedText("\n");
} else {
String insertion = "\n" + Editor.EMPTY.substring(0, spaceCount);
textarea.setSelectedText(insertion);
}
// not gonna bother handling more than one brace
if (braceCount > 0) {
int sel = textarea.getSelectionStart();
// sel - tabSize will be -1 if start/end parens on the same line
// http://dev.processing.org/bugs/show_bug.cgi?id=484
if (sel - tabSize >= 0) {
textarea.select(sel - tabSize, sel);
String s = Editor.EMPTY.substring(0, tabSize);
// if these are spaces that we can delete
if (textarea.getSelectedText().equals(s)) {
textarea.setSelectedText("");
} else {
textarea.select(sel, sel);
}
}
}
// mark this event as already handled
event.consume();
@ -424,6 +501,34 @@ public class EditorListener {
}
/** Cmd-Shift or Ctrl-Shift depending on the platform */
//static final int CMD_SHIFT = ActionEvent.SHIFT_MASK |
// Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
/** ctrl-alt on windows and linux, cmd-alt on mac os x */
//static final int CTRL_ALT = ActionEvent.ALT_MASK |
// Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
/*
public boolean keyTyped(KeyEvent event) {
char c = event.getKeyChar();
int code = event.getKeyCode();
if ((event.getModifiers() & CMD_ALT) == CMD_ALT) {
if (code == KeyEvent.VK_LEFT) {
//if (c == '[') {
editor.sketch.prevCode();
return true;
} else if (code == KeyEvent.VK_RIGHT) {
//} else if (c == ']') {
editor.sketch.nextCode();
return true;
}
}
return false;
}
*/
/**
* Return the index for the first character on this line.
*/

View File

@ -57,6 +57,7 @@ public class FindReplace extends JFrame implements ActionListener {
JButton replaceButton;
JButton replaceAllButton;
JButton replaceFindButton;
JButton findButton;
JCheckBox ignoreCaseBox;
@ -132,12 +133,14 @@ public class FindReplace extends JFrame implements ActionListener {
// ordering is different on mac versus pc
if (Base.isMacOS()) {
buttons.add(replaceButton = new JButton("Replace"));
buttons.add(replaceAllButton = new JButton("Replace All"));
buttons.add(replaceButton = new JButton("Replace"));
buttons.add(replaceFindButton = new JButton("Replace & Find"));
buttons.add(findButton = new JButton("Find"));
} else {
buttons.add(findButton = new JButton("Find"));
buttons.add(replaceFindButton = new JButton("Replace & Find"));
buttons.add(replaceButton = new JButton("Replace"));
buttons.add(replaceAllButton = new JButton("Replace All"));
}
@ -169,10 +172,12 @@ public class FindReplace extends JFrame implements ActionListener {
replaceButton.addActionListener(this);
replaceAllButton.addActionListener(this);
replaceFindButton.addActionListener(this);
findButton.addActionListener(this);
// you mustn't replace what you haven't found, my son
replaceButton.setEnabled(false);
replaceFindButton.setEnabled(false);
// so that typing will go straight to this field
//findField.requestFocus();
@ -189,44 +194,28 @@ public class FindReplace extends JFrame implements ActionListener {
setBounds((screen.width - wide) / 2,
(screen.height - high) / 2, wide, high);
// add key listener to trap esc and ctrl/cmd-w
/*
KeyListener listener = new KeyAdapter() {
public void keyPressed(KeyEvent e) {
if (Base.isCloseWindowEvent(e)) hide();
}
};
findField.addKeyListener(listener);
replaceField.addKeyListener(listener);
addKeyListener(listener);
*/
ActionListener disposer = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
//hide();
handleClose();
}
};
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
handleClose();
}
});
Base.registerWindowCloseKeys(getRootPane(), disposer);
Base.registerWindowCloseKeys(getRootPane(), new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
//hide();
handleClose();
}
});
/*
// hack to to get first field to focus properly on osx
// though this still doesn't seem to work
addWindowListener(new WindowAdapter() {
public void windowActivated(WindowEvent e) {
//System.out.println("activating");
//boolean ok = findField.requestFocusInWindow();
boolean ok = findField.requestFocusInWindow();
//System.out.println("got " + ok);
//findField.selectAll();
findField.selectAll();
}
});
*/
}
@ -256,6 +245,10 @@ public class FindReplace extends JFrame implements ActionListener {
if (source == findButton) {
find(true);
} else if (source == replaceFindButton) {
replace();
find(true);
} else if (source == replaceButton) {
replace();
@ -276,6 +269,7 @@ public class FindReplace extends JFrame implements ActionListener {
found = false;
String search = findField.getText();
//System.out.println("finding for " + search + " " + findString);
// this will catch "find next" being called when no search yet
if (search.length() == 0) return;
@ -299,12 +293,14 @@ public class FindReplace extends JFrame implements ActionListener {
if (nextIndex == -1) {
found = false;
replaceButton.setEnabled(false);
replaceFindButton.setEnabled(false);
//Toolkit.getDefaultToolkit().beep();
return;
}
}
found = true;
replaceButton.setEnabled(true);
replaceFindButton.setEnabled(true);
editor.textarea.select(nextIndex, nextIndex + search.length());
}
@ -322,6 +318,7 @@ public class FindReplace extends JFrame implements ActionListener {
if (sel.equals(replaceField.getText())) {
found = false;
replaceButton.setEnabled(false);
replaceFindButton.setEnabled(false);
return;
}
@ -332,6 +329,7 @@ public class FindReplace extends JFrame implements ActionListener {
// don't allow a double replace
replaceButton.setEnabled(false);
replaceFindButton.setEnabled(false);
}

View File

@ -31,6 +31,8 @@ import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import processing.core.*;
/*
* Provides information about and builds a library
*/
@ -552,7 +554,7 @@ public class Library implements MessageConsumer{
continue;
}
String pieces[] = Base.split(line, '\t');
String pieces[] = PApplet.split(line, '\t');
if (pieces.length >= 2) {
String keyword = pieces[0].trim();

View File

@ -41,7 +41,12 @@ import javax.swing.filechooser.*;
import javax.swing.text.*;
import javax.swing.undo.*;
//import processing.core.PApplet;
import processing.core.PApplet;
// TODO change this to use the Java Preferences API
// http://www.onjava.com/pub/a/onjava/synd/2001/10/17/j2se.html
// http://www.particle.kth.se/~lindsey/JavaCourse/Book/Part1/Java/Chapter10/Preferences.html
/**
@ -50,6 +55,10 @@ import javax.swing.undo.*;
* This class no longer uses the Properties class, since
* properties files are iso8859-1, which is highly likely to
* be a problem when trying to save sketch folders and locations.
* <p>
* This is very poorly put together, that the prefs panel and the
* actual prefs i/o is part of the same code. But there hasn't yet
* been a compelling reason to bother with the separation.
*/
public class Preferences {
@ -88,9 +97,12 @@ public class Preferences {
* inside a static block.
*/
static public int BUTTON_HEIGHT = 24;
/*
// remove this for 0121, because quaqua takes care of it
static {
if (Base.isMacOS()) BUTTON_HEIGHT = 29;
}
*/
// value for the size bars, buttons, etc
@ -107,15 +119,18 @@ public class Preferences {
// gui elements
JDialog dialog;
//JDialog dialog;
JFrame dialog;
int wide, high;
JTextField sketchbookLocationField;
JCheckBox exportSeparateBox;
JCheckBox sketchPromptBox;
JCheckBox sketchCleanBox;
JCheckBox externalEditorBox;
JCheckBox memoryOverrideBox;
JTextField memoryField;
JCheckBox checkUpdatesBox;
JTextField fontSizeField;
@ -145,7 +160,7 @@ public class Preferences {
// check for platform-specific properties in the defaults
String platformExtension = "." +
platforms[Base.platform];
platforms[processing.core.PApplet.platform];
int extensionLength = platformExtension.length();
Enumeration e = table.keys(); //properties.propertyNames();
@ -195,7 +210,8 @@ public class Preferences {
// setup dialog for the prefs
dialog = new JDialog(editor, "Preferences", true);
//dialog = new JDialog(editor, "Preferences", true);
dialog = new JFrame("Preferences");
dialog.setResizable(false);
Container pain = dialog.getContentPane();
@ -249,6 +265,7 @@ public class Preferences {
button = new JButton(PROMPT_BROWSE);
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
/*
JFileChooser fc = new JFileChooser();
fc.setSelectedFile(new File(sketchbookLocationField.getText()));
fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
@ -258,6 +275,13 @@ public class Preferences {
File file = fc.getSelectedFile();
sketchbookLocationField.setText(file.getAbsolutePath());
}
*/
File dflt = new File(sketchbookLocationField.getText());
File file =
Base.selectFolder("Select new sketchbook location", dflt, dialog);
if (file != null) {
sketchbookLocationField.setText(file.getAbsolutePath());
}
}
});
pain.add(button);
@ -286,6 +310,8 @@ public class Preferences {
box.add(label);
fontSizeField = new JTextField(4);
box.add(fontSizeField);
label = new JLabel(" (requires restart of Arduino)");
box.add(label);
pain.add(box);
d = box.getPreferredSize();
box.setBounds(left, top, d.width, d.height);
@ -468,9 +494,9 @@ public class Preferences {
String newSizeText = fontSizeField.getText();
try {
int newSize = Integer.parseInt(newSizeText.trim());
String pieces[] = Base.split(get("editor.font"), ',');
String pieces[] = PApplet.split(get("editor.font"), ',');
pieces[2] = String.valueOf(newSize);
set("editor.font", Base.join(pieces, ','));
set("editor.font", PApplet.join(pieces, ','));
} catch (Exception e) {
System.err.println("ignoring invalid font size " + newSizeText);

View File

@ -23,7 +23,7 @@
package processing.app;
//import processing.core.*;
import processing.core.*;
import java.awt.*;
import java.awt.event.*;
@ -40,7 +40,7 @@ import com.oroinc.text.regex.*;
*/
public class Runner implements MessageConsumer {
//PApplet applet;
PApplet applet;
RunnerException exception;
Window window;
PrintStream leechErr;
@ -497,6 +497,7 @@ java.lang.NullPointerException
}
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.code[codeIndex].preprocOffset;

View File

@ -24,7 +24,7 @@
package processing.app;
import processing.app.preproc.*;
//import processing.core.*;
import processing.core.*;
import java.awt.*;
import java.io.*;
@ -73,6 +73,7 @@ public class Sketch {
static final String flavorExtensionsShown[] = new String[] { "", ".cpp", ".c", ".h" };
public SketchCode current;
int currentIndex;
int codeCount;
SketchCode code[];
@ -225,7 +226,11 @@ public class Sketch {
}
}
// remove any entries that didn't load properly
// some of the hidden files may be bad too, so use hiddenCounter
// added for rev 0121, fixes bug found by axel
hiddenCount = hiddenCounter;
// remove any entries that didn't load properly from codeCount
int index = 0;
while (index < codeCount) {
if ((code[index] == null) ||
@ -330,7 +335,7 @@ public class Sketch {
// ask for new name of file (internal to window)
// TODO maybe just popup a text area?
renamingCode = true;
String prompt = (current == code[0]) ?
String prompt = (currentIndex == 0) ?
"New name for sketch:" : "New name for file:";
String oldName = current.name + flavorExtensionsShown[current.flavor];
editor.status.edit(prompt, oldName);
@ -436,7 +441,7 @@ public class Sketch {
}
if (renamingCode) {
if (current == code[0]) {
if (currentIndex == 0) {
// get the new folder name/location
File newFolder = new File(folder.getParentFile(), newName);
if (newFolder.exists()) {
@ -494,43 +499,17 @@ public class Sketch {
// having saved everything and renamed the folder and the main .pde,
// use the editor to re-open the sketch to re-init state
// (unfortunately this will kill positions for carets etc)
editor.handleOpenUnchecked(mainFilename);
/*
// backtrack and don't rename the sketch folder
success = newFolder.renameTo(folder);
if (!success) {
String msg =
"Started renaming sketch and then ran into\n" +
"nasty trouble. Try to salvage with Copy & Paste\n" +
"or attempt a \"Save As\" to see if that works.";
Base.showWarning("Serious Error", msg, null);
}
return;
}
*/
/*
// set the sketch name... used by the pde and whatnot.
// the name is only set in the sketch constructor,
// so it's important here
name = newName;
code[0].name = newName;
code[0].file = mainFile;
code[0].program = editor.getText();
code[0].save();
folder = newFolder;
editor.handleOpenUnchecked(mainFilename,
currentIndex,
editor.textarea.getSelectionStart(),
editor.textarea.getSelectionEnd(),
editor.textarea.getScrollPosition());
// get the changes into the sketchbook menu
// (re-enabled in 0115 to fix bug #332)
editor.sketchbook.rebuildMenus();
// reload the sketch
load();
*/
} else {
} else { // else if something besides code[0]
if (!current.file.renameTo(newFile)) {
Base.showWarning("Error",
"Could not rename \"" + current.file.getName() +
@ -593,7 +572,7 @@ public class Sketch {
// confirm deletion with user, yes/no
Object[] options = { "OK", "Cancel" };
String prompt = (current == code[0]) ?
String prompt = (currentIndex == 0) ?
"Are you sure you want to delete this sketch?" :
"Are you sure you want to delete \"" + current.name +
flavorExtensionsShown[current.flavor] + "\"?";
@ -606,7 +585,7 @@ public class Sketch {
options,
options[0]);
if (result == JOptionPane.YES_OPTION) {
if (current == code[0]) {
if (currentIndex == 0) {
// need to unset all the modified flags, otherwise tries
// to do a save on the handleNew()
@ -672,7 +651,7 @@ public class Sketch {
// don't allow hide of the main code
// TODO maybe gray out the menu on setCurrent(0)
if (current == code[0]) {
if (currentIndex == 0) {
Base.showMessage("Can't do that",
"You cannot hide the main " +
".pde file from a sketch\n");
@ -933,57 +912,14 @@ public class Sketch {
File newFile = new File(newFolder, newName + ".pde");
code[0].saveAs(newFile);
editor.handleOpenUnchecked(newFile.getPath());
editor.handleOpenUnchecked(newFile.getPath(),
currentIndex,
editor.textarea.getSelectionStart(),
editor.textarea.getSelectionEnd(),
editor.textarea.getScrollPosition());
/*
// copy the entire contents of the sketch folder
Base.copyDir(folder, newFolder);
// change the references to the dir location in SketchCode files
for (int i = 0; i < codeCount; i++) {
code[i].file = new File(newFolder, code[i].file.getName());
}
for (int i = 0; i < hiddenCount; i++) {
hidden[i].file = new File(newFolder, hidden[i].file.getName());
}
// remove the old sketch file from the new dir
code[0].file.delete();
// name for the new main .pde file
code[0].file = new File(newFolder, newName + ".pde");
code[0].name = newName;
// write the contents to the renamed file
// (this may be resaved if the code is modified)
code[0].modified = true;
//code[0].save();
//System.out.println("modified is " + modified);
// change the other paths
String oldName = name;
name = newName;
File oldFolder = folder;
folder = newFolder;
dataFolder = new File(folder, "data");
codeFolder = new File(folder, "code");
// remove the 'applet', 'application', 'library' folders
// from the copied version.
// otherwise their .class and .jar files can cause conflicts.
Base.removeDir(new File(folder, "applet"));
Base.removeDir(new File(folder, "application"));
//Base.removeDir(new File(folder, "library"));
// do a "save"
// this will take care of the unsaved changes in each of the tabs
save();
// get the changes into the sketchbook menu
//sketchbook.rebuildMenu();
// done inside Editor instead
// update the tabs for the name change
editor.header.repaint();
*/
// Name changed, rebuild the sketch menus
editor.sketchbook.rebuildMenusAsync();
// let Editor know that the save was successful
return true;
@ -1168,8 +1104,8 @@ public class Sketch {
* </OL>
*/
public void setCurrent(int which) {
if (current == code[which]) {
//System.out.println("already current, ignoring");
// if current is null, then this is the first setCurrent(0)
if ((currentIndex == which) && (current != null)) {
return;
}
@ -1182,6 +1118,7 @@ public class Sketch {
}
current = code[which];
currentIndex = which;
editor.setCode(current);
//editor.setDocument(current.document,
// current.selectionStart, current.selectionStop,
@ -1286,6 +1223,9 @@ public class Sketch {
//handleOpen(sketch);
//history.lastRecorded = historySaved;
// set current to null so that the tab gets updated
// http://dev.processing.org/bugs/show_bug.cgi?id=515
current = null;
// nuke previous files and settings, just get things loaded
load();
}
@ -1746,7 +1686,12 @@ public class Sketch {
// make sure the user didn't hide the sketch folder
ensureExistence();
current.program = editor.getText();
// fix for issue posted on the board. make sure that the code
// is reloaded when exporting and an external editor is being used.
if (Preferences.getBoolean("editor.external")) {
// nuke previous files and settings
load();
}
zipFileContents = new Hashtable();
@ -1773,6 +1718,7 @@ public class Sketch {
/* int wide = PApplet.DEFAULT_WIDTH;
int high = PApplet.DEFAULT_HEIGHT;
String renderer = "";
PatternMatcher matcher = new Perl5Matcher();
PatternCompiler compiler = new Perl5Compiler();
@ -1785,20 +1731,26 @@ public class Sketch {
// modified for 83 to match size(XXX, ddd so that it'll
// properly handle size(200, 200) and size(200, 200, P3D)
String sizing =
"[\\s\\;]size\\s*\\(\\s*(\\S+)\\s*,\\s*(\\d+)";
// match the renderer string as well
"[\\s\\;]size\\s*\\(\\s*(\\S+)\\s*,\\s*(\\d+),?\\s*([^\\)]*)\\s*\\)";
// match just the width and height
//"[\\s\\;]size\\s*\\(\\s*(\\S+)\\s*,\\s*(\\d+)(.*)\\)";
Pattern pattern = compiler.compile(sizing);
// adds a space at the beginning, in case size() is the very
// first thing in the program (very common), since the regexp
// needs to check for things in front of it.
PatternMatcherInput input =
new PatternMatcherInput(" " + code[0].program);
new PatternMatcherInput(" " + scrubComments(code[0].program));
if (matcher.contains(input, pattern)) {
MatchResult result = matcher.getMatch();
try {
wide = Integer.parseInt(result.group(1).toString());
high = Integer.parseInt(result.group(2).toString());
renderer = result.group(3).toString(); //.trim();
} catch (NumberFormatException e) {
// found a reference to size, but it didn't
// seem to contain numbers
@ -1865,45 +1817,6 @@ public class Sketch {
if (is == null) {
is = Base.getStream("applet.html");
}
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
while ((line = reader.readLine()) != null) {
if (line.indexOf("@@") != -1) {
StringBuffer sb = new StringBuffer(line);
int index = 0;
while ((index = sb.indexOf("@@sketch@@")) != -1) {
sb.replace(index, index + "@@sketch@@".length(),
name);
}
while ((index = sb.indexOf("@@source@@")) != -1) {
sb.replace(index, index + "@@source@@".length(),
sources.toString());
}
while ((index = sb.indexOf("@@archive@@")) != -1) {
sb.replace(index, index + "@@archive@@".length(),
name + ".jar");
}
while ((index = sb.indexOf("@@width@@")) != -1) {
sb.replace(index, index + "@@width@@".length(),
String.valueOf(wide));
}
while ((index = sb.indexOf("@@height@@")) != -1) {
sb.replace(index, index + "@@height@@".length(),
String.valueOf(high));
}
while ((index = sb.indexOf("@@description@@")) != -1) {
sb.replace(index, index + "@@description@@".length(),
description);
}
line = sb.toString();
}
ps.println(line);
}
reader.close();
ps.flush();
ps.close();
// copy the loading gif to the applet
String LOADING_IMAGE = "loading.gif";
@ -1929,13 +1842,13 @@ public class Sketch {
new FileOutputStream(new File(appletFolder, name + ".jar"));
ZipOutputStream zos = new ZipOutputStream(zipOutputFile);
ZipEntry entry;
archives.append(name + ".jar");
// add the manifest file
addManifest(zos);
// add the contents of the code folder to the jar
// unpacks all jar files
//File codeFolder = new File(folder, "code");
// unpacks all jar files, unless multi jar files selected in prefs
if (codeFolder.exists()) {
String includes = Compiler.contentsToClassPath(codeFolder);
packClassPathIntoZipFile(includes, zos);
@ -1980,7 +1893,18 @@ public class Sketch {
} else if (exportFile.getName().toLowerCase().endsWith(".zip") ||
exportFile.getName().toLowerCase().endsWith(".jar")) {
if (separateJar) {
String exportFilename = exportFile.getName();
Base.copyFile(exportFile, new File(appletFolder, exportFilename));
if (renderer.equals("OPENGL") &&
exportFilename.indexOf("natives") != -1) {
// don't add these to the archives list
} else {
archives.append("," + exportFilename);
}
} else {
packClassPathIntoZipFile(exportFile.getAbsolutePath(), zos);
}
} else { // just copy the file over.. prolly a .dll or something
Base.copyFile(exportFile,
@ -1991,6 +1915,7 @@ public class Sketch {
*/
/* String bagelJar = "lib/core.jar";
packClassPathIntoZipFile(bagelJar, zos);
}
// files to include from data directory
// TODO this needs to be recursive
@ -2049,6 +1974,53 @@ public class Sketch {
}
static public String scrubComments(String what) {
char p[] = what.toCharArray();
int index = 0;
while (index < p.length) {
// for any double slash comments, ignore until the end of the line
if ((p[index] == '/') &&
(index < p.length - 1) &&
(p[index+1] == '/')) {
p[index++] = ' ';
p[index++] = ' ';
while ((index < p.length) &&
(p[index] != '\n')) {
p[index++] = ' ';
}
// check to see if this is the start of a new multiline comment.
// if it is, then make sure it's actually terminated somewhere.
} else if ((p[index] == '/') &&
(index < p.length - 1) &&
(p[index+1] == '*')) {
p[index++] = ' ';
p[index++] = ' ';
boolean endOfRainbow = false;
while (index < p.length - 1) {
if ((p[index] == '*') && (p[index+1] == '/')) {
p[index++] = ' ';
p[index++] = ' ';
endOfRainbow = true;
break;
} else {
index++;
}
}
if (!endOfRainbow) {
throw new RuntimeException("Missing the */ from the end of a " +
"/* comment */");
}
} else { // any old character, move along
index++;
}
}
return new String(p);
}
/**
* Export to application.
* <PRE>
@ -2135,7 +2107,6 @@ public class Sketch {
for (int i = 0; i < pieces.length; i++) {
if (pieces[i].length() == 0) continue;
//System.out.println("checking piece " + pieces[i]);
// is it a jar file or directory?
if (pieces[i].toLowerCase().endsWith(".jar") ||
@ -2299,4 +2270,16 @@ public class Sketch {
public String getMainFilePath() {
return code[0].file.getAbsolutePath();
}
public void prevCode() {
int prev = currentIndex - 1;
if (prev < 0) prev = codeCount-1;
setCurrent(prev);
}
public void nextCode() {
setCurrent((currentIndex + 1) % codeCount);
}
}

View File

@ -130,6 +130,7 @@ public class Sketchbook {
//System.out.println("resetting sketchbook path");
File sketchbookFolder = Base.getDefaultSketchbookFolder();
//System.out.println("default is " + sketchbookFolder);
Preferences.set("sketchbook.path",
sketchbookFolder.getAbsolutePath());
@ -170,11 +171,8 @@ public class Sketchbook {
if (noPrompt) prompt = false;
if (prompt) {
//if (!startup) {
// prompt for the filename and location for the new sketch
FileDialog fd = new FileDialog(editor, //new Frame(),
//"Create new sketch named",
FileDialog fd = new FileDialog(editor,
"Create sketch folder named:",
FileDialog.SAVE);
fd.setDirectory(getSketchbookPath());
@ -228,7 +226,7 @@ public class Sketchbook {
}
// make a note of a newly added sketch in the sketchbook menu
rebuildMenus();
rebuildMenusAsync();
// now open it up
//handleOpen(newbieName, newbieFile, newbieDir);
@ -257,10 +255,25 @@ public class Sketchbook {
/**
* Java classes are pretty limited about what you can use
* for their naming. This helper function replaces everything
* but A-Z, a-z, and 0-9 with underscores. Also disallows
* starting the sketch name with a digit.
* Return true if the name is valid for a Processing sketch.
*/
static public boolean isSanitary(String name) {
return sanitizedName(name).equals(name);
}
/**
* Produce a sanitized name that fits our standards for likely to work.
* <p/>
* Java classes have a wider range of names that are technically allowed
* (supposedly any Unicode name) than what we support. The reason for
* going more narrow is to avoid situations with text encodings and
* converting during the process of moving files between operating
* systems, i.e. uploading from a Windows machine to a Linux server,
* or reading a FAT32 partition in OS X and using a thumb drive.
* <p/>
* This helper function replaces everything but A-Z, a-z, and 0-9 with
* underscores. Also disallows starting the sketch name with a digit.
*/
static public String sanitizedName(String origName) {
char c[] = origName.toCharArray();
@ -280,7 +293,12 @@ public class Sketchbook {
buffer.append('_');
}
}
// let's not be ridiculous about the length of filenames
// let's not be ridiculous about the length of filenames.
// in fact, Mac OS 9 can handle 255 chars, though it can't really
// deal with filenames longer than 31 chars in the Finder.
// but limiting to that for sketches would mean setting the
// upper-bound on the character limit here to 25 characters
// (to handle the base name + ".class")
if (buffer.length() > 63) {
buffer.setLength(63);
}
@ -290,12 +308,12 @@ public class Sketchbook {
public String handleOpen() {
// swing's file choosers are ass ugly, so we use the
// native (awt peered) dialogs instead
// native (awt peered) dialogs where possible
FileDialog fd = new FileDialog(editor, //new Frame(),
"Open a Processing sketch...",
FileDialog.LOAD);
//fd.setDirectory(Preferences.get("sketchbook.path"));
fd.setDirectory(getSketchbookPath());
//fd.setDirectory(getSketchbookPath());
// only show .pde files as eligible bachelors
// TODO this doesn't seem to ever be used. AWESOME.
@ -324,6 +342,23 @@ public class Sketchbook {
}
/**
* Asynchronous version of menu rebuild to be used on 'new' and 'save',
* to prevent the interface from locking up until the menus are done.
*/
public void rebuildMenusAsync() {
// disabling the async option for actual release, this hasn't been tested
/*
SwingUtilities.invokeLater(new Runnable() {
public void run() {
rebuildMenus();
}
});
*/
rebuildMenus();
}
/**
* Rebuild the menu full of sketches based on the
* contents of the sketchbook.
@ -333,6 +368,7 @@ public class Sketchbook {
* the menu will disappear from its original location.
*/
public void rebuildMenus() {
//EditorConsole.systemOut.println("rebuilding menus");
try {
// rebuild file/open and the toolbar popup menus
buildMenu(openMenu);
@ -359,6 +395,7 @@ public class Sketchbook {
"sketchbook menu. Things might get a little\n" +
"kooky around here.", e);
}
//EditorConsole.systemOut.println("done rebuilding menus");
}
@ -444,25 +481,8 @@ public class Sketchbook {
if (list == null) return false;
// alphabetize list, since it's not always alpha order
// use cheapie bubble-style sort which should be fine
// since not a tone of files, and things will mostly be sorted
// or may be completely sorted already by the os
for (int i = 0; i < list.length; i++) {
int who = i;
for (int j = i+1; j < list.length; j++) {
if (list[j].compareToIgnoreCase(list[who]) < 0) {
who = j; // this guy is earlier in the alphabet
}
}
if (who != i) { // swap with someone if changes made
String temp = list[who];
list[who] = list[i];
list[i] = temp;
}
}
//SketchbookMenuListener listener =
//new SketchbookMenuListener(folder.getAbsolutePath());
// replaced hella slow bubble sort with this feller for 0093
Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
@ -477,18 +497,23 @@ public class Sketchbook {
list[i].equals("CVS")) continue;
File subfolder = new File(folder, list[i]);
File lib = new File(subfolder, "library");
if (!subfolder.isDirectory()) continue;
File entry = new File(subfolder, list[i] + ".pde");
// if a .pde file of the same prefix as the folder exists..
if (entry.exists()) {
String sanityCheck = sanitizedName(list[i]);
if (!sanityCheck.equals(list[i])) {
//String sanityCheck = sanitizedName(list[i]);
//if (!sanityCheck.equals(list[i])) {
if (!Sketchbook.isSanitary(list[i])) {
if (!builtOnce) {
String mess =
String complaining =
"The sketch \"" + list[i] + "\" cannot be used.\n" +
"Sketch names must contain only basic letters and numbers.\n" +
"(ascii only and no spaces, and it cannot start with a number)";
Base.showMessage("Ignoring bad sketch name", mess);
"Sketch names must contain only basic letters and numbers\n" +
"(ASCII-only with no spaces, " +
"and it cannot start with a number).\n" +
"To get rid of this message, remove the sketch from\n" +
entry.getAbsolutePath();
Base.showMessage("Ignoring sketch with bad name", complaining);
}
continue;
}
@ -499,7 +524,8 @@ public class Sketchbook {
menu.add(item);
ifound = true;
} else { // might contain other dirs, get recursive
} else {
// not a sketch folder, but maybe a subfolder containing sketches
JMenu submenu = new JMenu(list[i]);
// needs to be separate var
// otherwise would set ifound to false
@ -523,22 +549,8 @@ public class Sketchbook {
if (list == null) return false;
// alphabetize list, since it's not always alpha order
// use cheapie bubble-style sort which should be fine
// since not a tone of files, and things will mostly be sorted
// or may be completely sorted already by the os
for (int i = 0; i < list.length; i++) {
int who = i;
for (int j = i+1; j < list.length; j++) {
if (list[j].compareToIgnoreCase(list[who]) < 0) {
who = j; // this guy is earlier in the alphabet
}
}
if (who != i) { // swap with someone if changes made
String temp = list[who];
list[who] = list[i];
list[i] = temp;
}
}
// replaced hella slow bubble sort with this feller for 0093
Arrays.sort(list, String.CASE_INSENSITIVE_ORDER);
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
@ -591,6 +603,8 @@ public class Sketchbook {
String packages[] =
Compiler.packageListFromClassPath(libraryClassPath);
for (int k = 0; k < packages.length; k++) {
//System.out.println(packages[k] + " -> " + exported);
//String already = (String) importToLibraryTable.get(packages[k]);
importToLibraryTable.put(packages[k], exported);
}
*/
@ -600,11 +614,10 @@ public class Sketchbook {
menu.add(item);
ifound = true;
} else { // might contain other dirs, get recursive
} else { // not a library, but is still a folder, so recurse
JMenu submenu = new JMenu(list[i]);
// needs to be separate var
// otherwise would set ifound to false
boolean found = addLibraries(submenu, subfolder); //, false);
// needs to be separate var, otherwise would set ifound to false
boolean found = addLibraries(submenu, subfolder);
if (found) {
menu.add(submenu);
ifound = true;

View File

@ -30,7 +30,7 @@
package processing.app.preproc;
import processing.app.*;
//import processing.core.*;
import processing.core.*;
import java.io.*;
@ -99,6 +99,7 @@ public class PdePreprocessor {
/**
* preprocesses a pde file and write out a java file
* @param pretty true if should also space out/indent lines
* @return the classname of the exported Java
*/
//public String write(String program, String buildPath, String name,
@ -109,10 +110,19 @@ public class PdePreprocessor {
throws java.lang.Exception {
// 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:
if ((program.length() > 0) &&
program.charAt(program.length()-1) != '\n') {
// bug filed at http://dev.processing.org/bugs/show_bug.cgi?id=5
//if ((program.length() > 0) &&
//program.charAt(program.length()-1) != '\n') {
program += "\n";
}
//}
// if the program ends with an unterminated multiline comment,
// an OutOfMemoryError or NullPointerException will happen.
// again, not gonna bother tracking this down, but here's a hack.
// http://dev.processing.org/bugs/show_bug.cgi?id=16
Sketch.scrubComments(program);
// this returns the scrubbed version, but more important for this
// function, it'll check to see if there are errors with the comments.
if (Preferences.getBoolean("preproc.substitute_unicode")) {
// check for non-ascii chars (these will be/must be in unicode format)
@ -193,26 +203,6 @@ public class PdePreprocessor {
extraImports = new String[imports.size()];
imports.copyInto(extraImports);
// if using opengl, add it to the special imports
/*
if (Preferences.get("renderer").equals("opengl")) {
extraImports = new String[imports.size() + 1];
imports.copyInto(extraImports);
extraImports[extraImports.length - 1] = "processing.opengl.*";
}
*/
/*
if (codeFolderPackages != null) {
extraImports = new String[importsCount + codeFolderPackages.length];
imports.copyInto(extraImports);
for (int i = 0; i < codeFolderPackages.length; i++) {
extraImports[importsCount + i] = codeFolderPackages[i] + ".*";
}
codeFolderImports = null;
}
*/
if (codeFolderPackages != null) {
codeFolderImports = new String[codeFolderPackages.length];
for (int i = 0; i < codeFolderPackages.length; i++) {

View File

@ -136,9 +136,10 @@ public abstract class InputHandler extends KeyAdapter
{
String name = (String)en.nextElement();
ActionListener _listener = getAction(name);
if(_listener == listener)
if(_listener == listener) {
return name;
}
}
return null;
}
@ -180,7 +181,6 @@ public abstract class InputHandler extends KeyAdapter
/**
* Grabs the next key typed event and invokes the specified
* action with the key as a the action command.
* @param action The action
*/
public void grabNextKeyStroke(ActionListener listener)
{
@ -743,19 +743,32 @@ public abstract class InputHandler extends KeyAdapter
{
JEditTextArea textArea = getTextArea(evt);
int caret = textArea.getCaretPosition();
if(caret == textArea.getDocumentLength())
{
if (textArea.getSelectionStart() !=
textArea.getSelectionEnd()) {
// just move to the end of the selection
textArea.select(caret, caret);
} else {
// beep at the user for being annoying
textArea.getToolkit().beep();
return;
}
if(select)
textArea.select(textArea.getMarkPosition(),
caret + 1);
else
} else if (select) {
textArea.select(textArea.getMarkPosition(), caret+1);
} else {
int start = textArea.getSelectionStart();
int end = textArea.getSelectionEnd();
if (start != end) {
textArea.select(end, end);
} else {
textArea.setCaretPosition(caret + 1);
}
}
}
}
public static class next_line implements ActionListener
{
@ -774,7 +787,13 @@ public abstract class InputHandler extends KeyAdapter
if(line == textArea.getLineCount() - 1)
{
textArea.getToolkit().beep();
//textArea.getToolkit().beep();
int doc = textArea.getDocumentLength();
if (select) {
textArea.select(textArea.getMarkPosition(), doc);
} else {
textArea.setCaretPosition(doc);
}
return;
}
@ -901,13 +920,19 @@ public abstract class InputHandler extends KeyAdapter
return;
}
if(select)
textArea.select(textArea.getMarkPosition(),
caret - 1);
else
if (select) {
textArea.select(textArea.getMarkPosition(), caret-1);
} else {
int start = textArea.getSelectionStart();
int end = textArea.getSelectionEnd();
if (start != end) {
textArea.select(start, start);
} else {
textArea.setCaretPosition(caret - 1);
}
}
}
}
public static class prev_line implements ActionListener
{
@ -926,7 +951,14 @@ public abstract class InputHandler extends KeyAdapter
if(line == 0)
{
textArea.getToolkit().beep();
if (select) {
if (textArea.getSelectionStart() != 0) {
textArea.select(textArea.getMarkPosition(), 0);
}
} else {
textArea.setCaretPosition(0);
}
//textArea.getToolkit().beep();
return;
}

View File

@ -888,22 +888,20 @@ public class JEditTextArea extends JComponent
*/
public void setText(String text)
{
try
{
try {
document.beginCompoundEdit();
document.remove(0,document.getLength());
document.insertString(0,text,null);
}
catch(BadLocationException bl)
{
} catch (BadLocationException bl) {
bl.printStackTrace();
}
finally
{
} finally {
document.endCompoundEdit();
}
}
/**
* Returns the specified substring of the document.
* @param start The start offset
@ -1502,7 +1500,7 @@ public class JEditTextArea extends JComponent
/**
* Sets if the selection should be rectangular.
* @param overwrite True if the selection should be rectangular,
* @param rectSelect True if the selection should be rectangular,
* false otherwise.
*/
public final void setSelectionRectangular(boolean rectSelect)
@ -1644,6 +1642,7 @@ public class JEditTextArea extends JComponent
switch(evt.getID()) {
case KeyEvent.KEY_TYPED:
//if ((editorListener != null) && !editorListener.keyTyped(evt)) {
inputHandler.keyTyped(evt);
break;
case KeyEvent.KEY_PRESSED:
@ -2145,21 +2144,52 @@ public class JEditTextArea extends JComponent
bl.printStackTrace();
}
// Ok, it's not a bracket... select the word
String lineText = getLineText(line);
char ch = lineText.charAt(Math.max(0,offset - 1));
String noWordSep = (String)document.getProperty("noWordSep");
if(noWordSep == null)
noWordSep = "";
// If the user clicked on a non-letter char,
// we select the surrounding non-letters
boolean selectNoLetter = (!Character
.isLetterOrDigit(ch)
&& noWordSep.indexOf(ch) == -1);
// Ok, it's not a bracket... select the word
String lineText = getLineText(line);
int wordStart = 0;
int wordEnd = lineText.length();
char ch = lineText.charAt(Math.max(0,offset - 1));
// special case for whitespace (fry 0122, bug #348)
// this is really nasty.. turns out that double-clicking any non-letter
// or digit char gets lumped together.. sooo, this quickly gets messy,
// because really it needs to check whether the chars are of the same
// type.. so a double space or double - might be grouped together,
// but what about a +=1? do + and - get grouped but not the 1? blech,
// coming back to this later. it's not a difficult fix, just a
// time-consuming one to track down all the proper cases.
/*
if (ch == ' ') {
//System.out.println("yeehaa");
for(int i = offset - 1; i >= 0; i--) {
if (lineText.charAt(i) == ' ') {
wordStart = i;
} else {
break;
}
}
for(int i = offset; i < lineText.length(); i++) {
if (lineText.charAt(i) == ' ') {
wordEnd = i + 1;
} else {
break;
}
}
} else {
*/
// If the user clicked on a non-letter char,
// we select the surrounding non-letters
boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
&& noWordSep.indexOf(ch) == -1);
for(int i = offset - 1; i >= 0; i--) {
ch = lineText.charAt(i);
@ -2170,18 +2200,15 @@ public class JEditTextArea extends JComponent
}
}
int wordEnd = lineText.length();
for(int i = offset; i < lineText.length(); i++)
{
for(int i = offset; i < lineText.length(); i++) {
ch = lineText.charAt(i);
if(selectNoLetter ^ (!Character
.isLetterOrDigit(ch) &&
noWordSep.indexOf(ch) == -1))
{
if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
noWordSep.indexOf(ch) == -1)) {
wordEnd = i;
break;
}
}
//}
int lineStart = getLineStartOffset(line);
select(lineStart + wordStart,lineStart + wordEnd);

View File

@ -76,7 +76,7 @@ public class KeywordMap
/**
* Adds a key-value mapping.
* @param keyword The key
* @Param id The value
* @param id The value
*/
public void add(String keyword, byte id)
{

View File

@ -76,7 +76,7 @@ public class PdeKeywords extends CTokenMarker {
}
}
String pieces[] = Base.split(line, '\t');
String pieces[] = processing.core.PApplet.split(line, '\t');
if (pieces.length >= 2) {
//int tab = line.indexOf('\t');
// any line with no tab is ignored

View File

@ -2,9 +2,9 @@
/*
PdeTextAreaDefaults - grabs font/color settings for the editor
Part of the Processing project - http://Proce55ing.net
Part of the Processing project - http://processing.org
Except where noted, code is written by Ben Fry
Copyright (c) 2004-06 Ben Fry and Casey Reas
Copyright (c) 2001-03 Massachusetts Institute of Technology
This program is free software; you can redistribute it and/or modify
@ -32,41 +32,65 @@ public class PdeTextAreaDefaults extends TextAreaDefaults {
public PdeTextAreaDefaults() {
inputHandler = new DefaultInputHandler();
inputHandler.addDefaultKeyBindings();
//inputHandler.addDefaultKeyBindings(); // 0122
// use option on mac for things that are ctrl on windows/linux
String mod = Base.isMacOS() ? "A" : "C";
inputHandler.addKeyBinding("S+BACK_SPACE", InputHandler.BACKSPACE);
inputHandler.addKeyBinding("S+DELETE", InputHandler.DELETE);
// right now, ctrl-up/down is select up/down, but mod should be
// used instead, because the mac expects it to be option(alt)
inputHandler.addKeyBinding("BACK_SPACE", InputHandler.BACKSPACE);
inputHandler.addKeyBinding("C+BACK_SPACE", InputHandler.BACKSPACE_WORD);
inputHandler.addKeyBinding("DELETE", InputHandler.DELETE);
inputHandler.addKeyBinding("C+DELETE", InputHandler.DELETE_WORD);
inputHandler.addKeyBinding("ENTER", InputHandler.INSERT_BREAK);
inputHandler.addKeyBinding("TAB", InputHandler.INSERT_TAB);
//inputHandler.addKeyBinding("S+BACK_SPACE", InputHandler.BACKSPACE);
// for 0122, shift-backspace is delete
inputHandler.addKeyBinding("S+BACK_SPACE", InputHandler.DELETE);
inputHandler.addKeyBinding("S+DELETE", InputHandler.DELETE);
// the following two were changing for 0122 for better mac/pc compatability
inputHandler.addKeyBinding(mod+"+BACK_SPACE", InputHandler.BACKSPACE_WORD);
inputHandler.addKeyBinding(mod+"+DELETE", InputHandler.DELETE_WORD);
// handled by listener, don't bother here
//inputHandler.addKeyBinding("ENTER", InputHandler.INSERT_BREAK);
//inputHandler.addKeyBinding("TAB", InputHandler.INSERT_TAB);
inputHandler.addKeyBinding("INSERT", InputHandler.OVERWRITE);
inputHandler.addKeyBinding("C+\\", InputHandler.TOGGLE_RECT);
// disabling for 0122, not sure what this does
//inputHandler.addKeyBinding("C+\\", InputHandler.TOGGLE_RECT);
// beginning and ending of the current line
// for 0122, these have been changed for better compatability
// HOME and END now mean the beginning/end of the document
if (Base.isMacOS()) {
inputHandler.addKeyBinding("HOME", InputHandler.DOCUMENT_HOME);
inputHandler.addKeyBinding("END", InputHandler.DOCUMENT_END);
inputHandler.addKeyBinding("S+HOME", InputHandler.SELECT_DOC_HOME);
inputHandler.addKeyBinding("S+END", InputHandler.SELECT_DOC_END);
} else {
// for 0123 added the proper windows defaults
inputHandler.addKeyBinding("HOME", InputHandler.HOME);
inputHandler.addKeyBinding("END", InputHandler.END);
inputHandler.addKeyBinding("S+HOME", InputHandler.SELECT_HOME);
inputHandler.addKeyBinding("S+END", InputHandler.SELECT_END);
inputHandler.addKeyBinding("C+HOME", InputHandler.DOCUMENT_HOME);
inputHandler.addKeyBinding("C+END", InputHandler.DOCUMENT_END);
inputHandler.addKeyBinding("CS+HOME", InputHandler.SELECT_DOC_HOME);
inputHandler.addKeyBinding("CS+END", InputHandler.SELECT_DOC_END);
}
if (Base.isMacOS()) {
inputHandler.addKeyBinding("M+LEFT", InputHandler.HOME);
inputHandler.addKeyBinding("M+RIGHT", InputHandler.END);
inputHandler.addKeyBinding("MS+LEFT", InputHandler.SELECT_HOME); // 0122
inputHandler.addKeyBinding("MS+RIGHT", InputHandler.SELECT_END); // 0122
} else {
inputHandler.addKeyBinding("C+LEFT", InputHandler.HOME); // 0122
inputHandler.addKeyBinding("C+RIGHT", InputHandler.END); // 0122
inputHandler.addKeyBinding("CS+HOME", InputHandler.SELECT_HOME); // 0122
inputHandler.addKeyBinding("CS+END", InputHandler.SELECT_END); // 0122
}
inputHandler.addKeyBinding("S+HOME", InputHandler.SELECT_HOME);
inputHandler.addKeyBinding("S+END", InputHandler.SELECT_END);
inputHandler.addKeyBinding(mod + "+HOME", InputHandler.DOCUMENT_HOME);
inputHandler.addKeyBinding(mod + "+END", InputHandler.DOCUMENT_END);
inputHandler.addKeyBinding(mod + "S+HOME", InputHandler.SELECT_DOC_HOME);
inputHandler.addKeyBinding(mod + "S+END", InputHandler.SELECT_DOC_END);
inputHandler.addKeyBinding("PAGE_UP", InputHandler.PREV_PAGE);
inputHandler.addKeyBinding("PAGE_DOWN", InputHandler.NEXT_PAGE);
inputHandler.addKeyBinding("S+PAGE_UP", InputHandler.SELECT_PREV_PAGE);
@ -80,6 +104,7 @@ public class PdeTextAreaDefaults extends TextAreaDefaults {
inputHandler.addKeyBinding("S+RIGHT", InputHandler.SELECT_NEXT_CHAR);
inputHandler.addKeyBinding(mod + "+RIGHT", InputHandler.NEXT_WORD);
inputHandler.addKeyBinding(mod + "S+RIGHT", InputHandler.SELECT_NEXT_WORD);
inputHandler.addKeyBinding("UP", InputHandler.PREV_LINE);
inputHandler.addKeyBinding(mod + "+UP", InputHandler.PREV_LINE); // p5
inputHandler.addKeyBinding("S+UP", InputHandler.SELECT_PREV_LINE);
@ -87,6 +112,11 @@ public class PdeTextAreaDefaults extends TextAreaDefaults {
inputHandler.addKeyBinding(mod + "+DOWN", InputHandler.NEXT_LINE); // p5
inputHandler.addKeyBinding("S+DOWN", InputHandler.SELECT_NEXT_LINE);
inputHandler.addKeyBinding("MS+UP", InputHandler.SELECT_DOC_HOME);
inputHandler.addKeyBinding("CS+UP", InputHandler.SELECT_DOC_HOME);
inputHandler.addKeyBinding("MS+DOWN", InputHandler.SELECT_DOC_END);
inputHandler.addKeyBinding("CS+DOWN", InputHandler.SELECT_DOC_END);
inputHandler.addKeyBinding(mod + "+ENTER", InputHandler.REPEAT);
document = new SyntaxDocument();

View File

@ -18,6 +18,7 @@ import javax.swing.text.*;
import javax.swing.JComponent;
import java.awt.event.MouseEvent;
import java.awt.*;
import java.awt.print.*;
/**
* The text area repaint manager. It performs double buffering and paints
@ -25,8 +26,12 @@ import java.awt.*;
* @author Slava Pestov
* @version $Id$
*/
public class TextAreaPainter extends JComponent implements TabExpander
public class TextAreaPainter extends JComponent
implements TabExpander, Printable
{
/** True if inside printing, will handle disabling the highlight */
boolean printing;
/**
* Creates a new repaint manager. This should be not be called
* directly.
@ -405,6 +410,32 @@ public class TextAreaPainter extends JComponent implements TabExpander
}
}
public int print(Graphics g, PageFormat pageFormat, int pageIndex) {
int lineHeight = fm.getHeight();
int linesPerPage = (int) (pageFormat.getImageableHeight() / lineHeight);
int lineCount = textArea.getLineCount();
int lastPage = lineCount / linesPerPage;
if (pageIndex > lastPage) {
return NO_SUCH_PAGE;
} else {
Graphics2D g2d = (Graphics2D)g;
TokenMarker tokenMarker = textArea.getDocument().getTokenMarker();
int firstLine = pageIndex*linesPerPage;
g2d.translate(Math.max(54, pageFormat.getImageableX()),
pageFormat.getImageableY() - firstLine*lineHeight);
printing = true;
for (int line = firstLine; line < firstLine + linesPerPage; line++) {
paintLine(g2d, tokenMarker, line, 0);
}
printing = false;
return PAGE_EXISTS;
}
}
/**
* Marks a line as needing a repaint.
* @param line The line to invalidate
@ -600,6 +631,7 @@ public class TextAreaPainter extends JComponent implements TabExpander
protected void paintHighlight(Graphics gfx, int line, int y)
{
if (!printing) {
if (line >= textArea.getSelectionStartLine()
&& line <= textArea.getSelectionEndLine())
paintLineHighlight(gfx,line,y);
@ -613,6 +645,7 @@ public class TextAreaPainter extends JComponent implements TabExpander
if (line == textArea.getCaretLine())
paintCaret(gfx,line,y);
}
}
protected void paintLineHighlight(Graphics gfx, int line, int y)
{

View File

@ -25,6 +25,7 @@ package processing.app.tools;
import processing.app.*;
import java.awt.FileDialog;
import java.io.*;
import java.text.*;
import java.util.*;
@ -35,7 +36,7 @@ public class Archiver {
Editor editor;
// someday these will be settable
boolean useDate = true; //false;
boolean useDate;
int digits = 3;
NumberFormat numberFormat;
@ -79,6 +80,9 @@ public class Archiver {
String namely = null;
int index = 0;
do {
// only use the date if the sketch name isn't the default name
useDate = !name.startsWith("sketch_");
if (useDate) {
String purty = dateFormat.format(new Date());
String stamp = purty + ((char) ('a' + index));
@ -93,6 +97,20 @@ public class Archiver {
index++;
} while (newbie.exists());
// open up a prompt for where to save this fella
FileDialog fd =
new FileDialog(editor, "Archive sketch as:", FileDialog.SAVE);
fd.setDirectory(parent.getAbsolutePath());
fd.setFile(newbie.getName());
fd.show();
String directory = fd.getDirectory();
String filename = fd.getFile();
// only write the file if not canceled
if (filename != null) {
newbie = new File(directory, filename);
try {
//System.out.println(newbie);
FileOutputStream zipOutputFile = new FileOutputStream(newbie);
@ -110,6 +128,9 @@ public class Archiver {
} catch (IOException e) {
e.printStackTrace();
}
} else {
editor.message("Archive sketch canceled.");
}
}

View File

@ -24,7 +24,7 @@
package processing.app.tools;
import processing.app.*;
//import processing.core.*;
import processing.core.*;
import java.io.*;
import java.util.StringTokenizer;
@ -915,26 +915,25 @@ public class AutoFormat {
if (formattedText.equals(originalText)) {
editor.message("No changes necessary for Auto Format.");
} else {
// replace with new bootiful text
// selectionEnd hopefully at least in the neighborhood
editor.setText(formattedText, selectionEnd, selectionEnd);
editor.sketch.setModified(true);
} else if (paren != 0) {
// warn user if there are too many parens in either direction
if (paren != 0) {
editor.error("Warning: Too many " +
editor.error("Auto Format Canceled: Too many " +
((paren < 0) ? "right" : "left") +
" parentheses.");
} else if (c_level != 0) { // check braces only if parens are ok
editor.error("Warning: Too many " +
editor.error("Auto Format Canceled: Too many " +
((c_level < 0) ? "right" : "left") +
" curly braces.");
} else {
// replace with new bootiful text
// selectionEnd hopefully at least in the neighborhood
editor.setText(formattedText, selectionEnd, selectionEnd);
editor.sketch.setModified(true);
// mark as finished
editor.message("Auto Format finished.");
}
}
} catch (Exception e) {
editor.error(e);

View File

@ -0,0 +1,313 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2005-06 Ignacio Manuel González Moreta
Copyright (c) 2006 Ben Fry and Casey Reas
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package processing.app.tools;
import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.text.Segment;
import processing.app.*;
import processing.app.syntax.*;
import processing.core.PApplet;
/**
* Format for Discourse Tool
* <p/>
* Original code by <A HREF="http://usuarios.iponet.es/imoreta">owd</A>.
* Revised and updated for revision 0108 by Ben Fry (10 March 2006).
* This code will later be removed but is included with release 0108+
* while features for the "Tools" menu are in testing.
* <p/>
* Updated for 0122 to simply copy the code directly to the clipboard,
* rather than opening a new window.
* <p/>
* Notes from the original source:
* Discourse.java This is a dirty-mix source.
* NOTE that: No macs and no keyboard. Unreliable source.
* Only format processing code using fontMetrics.
* It works under my windows XP + PentiumIV + Processing 0091.
*/
public class DiscourseFormat {
//static final String WINDOW_TITLE = "Format for Discourse by owd";
// p5 icon for the window
//static Image icon;
Editor editor;
//JEditTextArea textarea;
// JTextArea of the actual Editor
JEditTextArea parent;
//JFrame frame;
/**
* Creates a new window with the formated (YaBB tags) sketchcode
* from the actual Processing Tab ready to send to the processing discourse
* web (copy & paste)
*/
public DiscourseFormat(Editor editor) {
this.editor = editor;
this.parent = editor.textarea;
/*
textarea = new JEditTextArea(new PdeTextAreaDefaults());
textarea.setRightClickPopup(new DiscourseTextAreaPopup());
textarea.setTokenMarker(new PdeKeywords());
textarea.setHorizontalOffset(6);
textarea.setEditable(false);
// Create and set up the window.
frame = new JFrame(WINDOW_TITLE);
frame.setSize(500, 500);
// set the window icon
try {
icon = Base.getImage("icon.gif", frame);
frame.setIconImage(icon);
} catch (Exception e) { } // fail silently, no big whup
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
Container pain = frame.getContentPane();
pain.setLayout(new BorderLayout());
pain.add(textarea, BorderLayout.CENTER);
frame.setResizable(true);
frame.pack();
frame.setLocation(100, 100);
//frame.setVisible(true);
*/
}
public void show() {
// Format and render sketchcode
// [code] tag cancels other tags, using [quote]
StringBuffer cf = new StringBuffer("[quote] \n \n");
// Line by line
for (int i = 0; i < parent.getLineCount(); i++) {
cf.append(formatCode(i));
}
cf.append("\n [/quote]");
/*
// Send the text to the textarea
textarea.setText(cf.toString());
textarea.select(0, 0);
frame.show();
*/
StringSelection formatted = new StringSelection(cf.toString());
Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
clipboard.setContents(formatted, new ClipboardOwner() {
public void lostOwnership(Clipboard clipboard, Transferable contents) {
// i don't care about ownership
}
});
editor.message("Discourse-formatted code has been " +
"copied to the clipboard.");
}
// A terrible headache...
public String formatCode(int line) {
StringBuffer cf = new StringBuffer();
// Segment
Segment lineSegment = new Segment();
TextAreaPainter painter = parent.getPainter();
TokenMarker tokenMarker = parent.getTokenMarker();
// Use painter's cached info for speed
FontMetrics fm = painter.getFontMetrics();
// get line text from parent textarea
parent.getLineText(line, lineSegment);
char[] segmentArray = lineSegment.array;
int limit = lineSegment.getEndIndex();
int segmentOffset = lineSegment.offset;
int segmentCount = lineSegment.count;
int width = 0; //parent.getHorizontalOffset();
int x = 0; //parent.getHorizontalOffset();
// If syntax coloring is disabled, do simple translation
if (tokenMarker == null) {
for (int j = 0; j < segmentCount; j++) {
char c = segmentArray[j + segmentOffset];
cf = cf.append(c); //concat(character(c));
int charWidth;
if (c == '\t') {
charWidth = (int) painter.nextTabStop(width, j) - width;
} else {
charWidth = fm.charWidth(c);
}
width += charWidth;
}
} else {
// If syntax coloring is enabled, we have to do this
// because tokens can vary in width
Token tokens;
if ((painter.getCurrentLineIndex() == line) &&
(painter.getCurrentLineTokens() != null)) {
tokens = painter.getCurrentLineTokens();
} else {
painter.setCurrentLineIndex(line);
//painter.currentLineIndex = line;
painter.setCurrentLineTokens(tokenMarker.markTokens(lineSegment, line));
tokens = painter.getCurrentLineTokens();
}
int offset = 0;
Toolkit toolkit = painter.getToolkit();
Font defaultFont = painter.getFont();
SyntaxStyle[] styles = painter.getStyles();
for (;;) {
byte id = tokens.id;
if (id == Token.END) {
char c = segmentArray[segmentOffset + offset];
if (segmentOffset + offset < limit) {
cf.append(c);
} else {
cf.append('\n');
}
return cf.toString();
}
if (id == Token.NULL) {
fm = painter.getFontMetrics();
} else {
// Place open tags []
//cf.append("[color=" + color() + "]");
cf.append("[color=#");
cf.append(PApplet.hex(styles[id].getColor().getRGB() & 0xFFFFFF, 6));
cf.append("]");
if (styles[id].isBold())
cf.append("[b]");
fm = styles[id].getFontMetrics(defaultFont);
}
int length = tokens.length;
for (int j = 0; j < length; j++) {
char c = segmentArray[segmentOffset + offset + j];
cf.append(c);
// Place close tags [/]
if (j == (length - 1) && id != Token.NULL && styles[id].isBold())
cf.append("[/b]");
if (j == (length - 1) && id != Token.NULL)
cf.append("[/color]");
int charWidth;
if (c == '\t') {
charWidth = (int) painter
.nextTabStop(width, offset + j)
- width;
} else {
charWidth = fm.charWidth(c);
}
width += charWidth;
}
offset += length;
tokens = tokens.next;
}
}
return cf.toString();
}
/**
* Returns the discourse popup menu. Another features can be added: format
* selected text with a determinated tag (I'm thinking about [url]selected
* text[/url])
*/
/*
class DiscourseTextAreaPopup extends JPopupMenu {
JMenuItem copyItem;
public DiscourseTextAreaPopup() {
JMenuItem item;
copyItem = new JMenuItem("Copy");
copyItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
textarea.copy();
}
});
this.add(copyItem);
item = new JMenuItem("Select All");
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
textarea.selectAll();
}
});
this.add(item);
}
// if no text is selected, disable copy menu item
public void show(Component component, int x, int y) {
if (textarea.isSelectionActive()) {
copyItem.setEnabled(true);
} else {
copyItem.setEnabled(false);
}
super.show(component, x, y);
}
}
*/
/*
// A false listener (use the mouse)
public class DiscourseListener {
public DiscourseListener(JEditTextArea thisTextarea) {
// I'm a... I know this gives peoblems, but all this code
// is a funny hacking experiment
thisTextarea.editorListener = parent.editorListener;
}
public boolean keyPressed(KeyEvent event) {
System.out.println("Is your mouse lone some tonight...");
return false;
}
}
*/
}

View File

@ -99,6 +99,8 @@ public class ExportFolder {
// skip .DS_Store files, etc
if (!folder.isDirectory()) return; // false;
System.out.println(folder.getAbsolutePath());
String list[] = folder.list();
// if a bad folder or something like that, this might come back null
if (list == null) return; // false;

View File

@ -151,6 +151,7 @@
<string>$JAVAROOT/mrj.jar</string>
<string>$JAVAROOT/registry.jar</string>
<string>$JAVAROOT/RXTXcomm.jar</string>
<string>$JAVAROOT/quaqua.jar</string>
</array>
<key>JVMVersion</key>
<string>1.4+</string>
@ -170,6 +171,22 @@
/* Begin PBXBuildFile section */
332D4DB609CF147F00BF81F6 /* Sizer.java in Sources */ = {isa = PBXBuildFile; fileRef = 332D4DB509CF147F00BF81F6 /* Sizer.java */; };
335A28F50C8CCB0A00D8A7F4 /* quaqua.jar in CopyFiles */ = {isa = PBXBuildFile; fileRef = 335A28F30C8CCAF700D8A7F4 /* quaqua.jar */; };
335A28FE0C8CCB4000D8A7F4 /* libquaqua.jnilib in CopyFiles */ = {isa = PBXBuildFile; fileRef = 335A28F20C8CCAF700D8A7F4 /* libquaqua.jnilib */; };
335A29140C8CCC0900D8A7F4 /* PApplet.java in Sources */ = {isa = PBXBuildFile; fileRef = 335A29070C8CCC0900D8A7F4 /* PApplet.java */; };
335A29150C8CCC0900D8A7F4 /* PConstants.java in Sources */ = {isa = PBXBuildFile; fileRef = 335A29080C8CCC0900D8A7F4 /* PConstants.java */; };
335A29160C8CCC0900D8A7F4 /* PFont.java in Sources */ = {isa = PBXBuildFile; fileRef = 335A29090C8CCC0900D8A7F4 /* PFont.java */; };
335A29170C8CCC0900D8A7F4 /* PGraphics.java in Sources */ = {isa = PBXBuildFile; fileRef = 335A290A0C8CCC0900D8A7F4 /* PGraphics.java */; };
335A29180C8CCC0900D8A7F4 /* PGraphics2D.java in Sources */ = {isa = PBXBuildFile; fileRef = 335A290B0C8CCC0900D8A7F4 /* PGraphics2D.java */; };
335A29190C8CCC0900D8A7F4 /* PGraphics3D.java in Sources */ = {isa = PBXBuildFile; fileRef = 335A290C0C8CCC0900D8A7F4 /* PGraphics3D.java */; };
335A291A0C8CCC0900D8A7F4 /* PGraphicsJava2D.java in Sources */ = {isa = PBXBuildFile; fileRef = 335A290D0C8CCC0900D8A7F4 /* PGraphicsJava2D.java */; };
335A291B0C8CCC0900D8A7F4 /* PImage.java in Sources */ = {isa = PBXBuildFile; fileRef = 335A290E0C8CCC0900D8A7F4 /* PImage.java */; };
335A291C0C8CCC0900D8A7F4 /* PLine.java in Sources */ = {isa = PBXBuildFile; fileRef = 335A290F0C8CCC0900D8A7F4 /* PLine.java */; };
335A291D0C8CCC0900D8A7F4 /* PMatrix.java in Sources */ = {isa = PBXBuildFile; fileRef = 335A29100C8CCC0900D8A7F4 /* PMatrix.java */; };
335A291E0C8CCC0900D8A7F4 /* PPolygon.java in Sources */ = {isa = PBXBuildFile; fileRef = 335A29110C8CCC0900D8A7F4 /* PPolygon.java */; };
335A291F0C8CCC0900D8A7F4 /* PShape.java in Sources */ = {isa = PBXBuildFile; fileRef = 335A29120C8CCC0900D8A7F4 /* PShape.java */; };
335A29200C8CCC0900D8A7F4 /* PTriangle.java in Sources */ = {isa = PBXBuildFile; fileRef = 335A29130C8CCC0900D8A7F4 /* PTriangle.java */; };
335A29240C8CCC5E00D8A7F4 /* DiscourseFormat.java in Sources */ = {isa = PBXBuildFile; fileRef = 335A29230C8CCC5E00D8A7F4 /* DiscourseFormat.java */; };
335D3B010C4EE1B80065B27E /* ATmegaBOOT_168.c in CopyFiles */ = {isa = PBXBuildFile; fileRef = 335D3AFD0C4EE19D0065B27E /* ATmegaBOOT_168.c */; };
335D3B020C4EE1B80065B27E /* ATmegaBOOT_168_diecimila.hex in CopyFiles */ = {isa = PBXBuildFile; fileRef = 335D3AFE0C4EE19D0065B27E /* ATmegaBOOT_168_diecimila.hex */; };
335D3B030C4EE1B80065B27E /* ATmegaBOOT_168_ng.hex in CopyFiles */ = {isa = PBXBuildFile; fileRef = 335D3AFF0C4EE19D0065B27E /* ATmegaBOOT_168_ng.hex */; };
@ -363,6 +380,7 @@
dstPath = "";
dstSubfolderSpec = 15;
files = (
335A28F50C8CCB0A00D8A7F4 /* quaqua.jar in CopyFiles */,
33CF03CC09662DC000F2C9A9 /* mrj.jar in CopyFiles */,
33CF03CD09662DC000F2C9A9 /* RXTXcomm.jar in CopyFiles */,
33CF03CE09662DC000F2C9A9 /* antlr.jar in CopyFiles */,
@ -424,6 +442,7 @@
dstPath = "";
dstSubfolderSpec = 16;
files = (
335A28FE0C8CCB4000D8A7F4 /* libquaqua.jnilib in CopyFiles */,
339514FA097AEB8000193C89 /* license.txt in CopyFiles */,
339514FB097AEB8000193C89 /* readme.txt in CopyFiles */,
);
@ -433,6 +452,22 @@
/* Begin PBXFileReference section */
332D4DB509CF147F00BF81F6 /* Sizer.java */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.java; path = Sizer.java; sourceTree = "<group>"; };
335A28F20C8CCAF700D8A7F4 /* libquaqua.jnilib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; path = libquaqua.jnilib; sourceTree = "<group>"; };
335A28F30C8CCAF700D8A7F4 /* quaqua.jar */ = {isa = PBXFileReference; lastKnownFileType = archive.jar; path = quaqua.jar; sourceTree = "<group>"; };
335A29070C8CCC0900D8A7F4 /* PApplet.java */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.java; path = PApplet.java; sourceTree = "<group>"; };
335A29080C8CCC0900D8A7F4 /* PConstants.java */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.java; path = PConstants.java; sourceTree = "<group>"; };
335A29090C8CCC0900D8A7F4 /* PFont.java */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.java; path = PFont.java; sourceTree = "<group>"; };
335A290A0C8CCC0900D8A7F4 /* PGraphics.java */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.java; path = PGraphics.java; sourceTree = "<group>"; };
335A290B0C8CCC0900D8A7F4 /* PGraphics2D.java */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.java; path = PGraphics2D.java; sourceTree = "<group>"; };
335A290C0C8CCC0900D8A7F4 /* PGraphics3D.java */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.java; path = PGraphics3D.java; sourceTree = "<group>"; };
335A290D0C8CCC0900D8A7F4 /* PGraphicsJava2D.java */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.java; path = PGraphicsJava2D.java; sourceTree = "<group>"; };
335A290E0C8CCC0900D8A7F4 /* PImage.java */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.java; path = PImage.java; sourceTree = "<group>"; };
335A290F0C8CCC0900D8A7F4 /* PLine.java */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.java; path = PLine.java; sourceTree = "<group>"; };
335A29100C8CCC0900D8A7F4 /* PMatrix.java */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.java; path = PMatrix.java; sourceTree = "<group>"; };
335A29110C8CCC0900D8A7F4 /* PPolygon.java */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.java; path = PPolygon.java; sourceTree = "<group>"; };
335A29120C8CCC0900D8A7F4 /* PShape.java */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.java; path = PShape.java; sourceTree = "<group>"; };
335A29130C8CCC0900D8A7F4 /* PTriangle.java */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.java; path = PTriangle.java; sourceTree = "<group>"; };
335A29230C8CCC5E00D8A7F4 /* DiscourseFormat.java */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.java; path = DiscourseFormat.java; sourceTree = "<group>"; };
335D3AFD0C4EE19D0065B27E /* ATmegaBOOT_168.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = ATmegaBOOT_168.c; sourceTree = "<group>"; };
335D3AFE0C4EE19D0065B27E /* ATmegaBOOT_168_diecimila.hex */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = ATmegaBOOT_168_diecimila.hex; sourceTree = "<group>"; };
335D3AFF0C4EE19D0065B27E /* ATmegaBOOT_168_ng.hex */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = ATmegaBOOT_168_ng.hex; sourceTree = "<group>"; };
@ -576,6 +611,27 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
335A29060C8CCC0800D8A7F4 /* core */ = {
isa = PBXGroup;
children = (
335A29070C8CCC0900D8A7F4 /* PApplet.java */,
335A29080C8CCC0900D8A7F4 /* PConstants.java */,
335A29090C8CCC0900D8A7F4 /* PFont.java */,
335A290A0C8CCC0900D8A7F4 /* PGraphics.java */,
335A290B0C8CCC0900D8A7F4 /* PGraphics2D.java */,
335A290C0C8CCC0900D8A7F4 /* PGraphics3D.java */,
335A290D0C8CCC0900D8A7F4 /* PGraphicsJava2D.java */,
335A290E0C8CCC0900D8A7F4 /* PImage.java */,
335A290F0C8CCC0900D8A7F4 /* PLine.java */,
335A29100C8CCC0900D8A7F4 /* PMatrix.java */,
335A29110C8CCC0900D8A7F4 /* PPolygon.java */,
335A29120C8CCC0900D8A7F4 /* PShape.java */,
335A29130C8CCC0900D8A7F4 /* PTriangle.java */,
);
name = core;
path = ../../core;
sourceTree = SOURCE_ROOT;
};
335D3AFC0C4EE19D0065B27E /* bootloader168 */ = {
isa = PBXGroup;
children = (
@ -660,6 +716,7 @@
33FFFD3D0965B1E40016AC38 = {
isa = PBXGroup;
children = (
335A29060C8CCC0800D8A7F4 /* core */,
33CF03B009662CA800F2C9A9 /* arduino.icns */,
33FF07D50965C3560016AC38 /* targets */,
33FFFE220965BD100016AC38 /* app */,
@ -789,6 +846,7 @@
33FFFE710965BD110016AC38 /* tools */ = {
isa = PBXGroup;
children = (
335A29230C8CCC5E00D8A7F4 /* DiscourseFormat.java */,
33BEDDD309D6E8D800430D5B /* Archiver.java */,
33BEDDD409D6E8D800430D5B /* ExportFolder.java */,
33FFFE720965BD110016AC38 /* AutoFormat.java */,
@ -843,6 +901,8 @@
33FFFEAC0965BD110016AC38 /* dist */ = {
isa = PBXGroup;
children = (
335A28F20C8CCAF700D8A7F4 /* libquaqua.jnilib */,
335A28F30C8CCAF700D8A7F4 /* quaqua.jar */,
33FFFEAE0965BD110016AC38 /* bootloader */,
33FFFEB20965BD110016AC38 /* drivers */,
33FFFEB50965BD110016AC38 /* DS_Store */,
@ -1065,6 +1125,20 @@
33BEE0CE09D7446100430D5B /* Library.java in Sources */,
33F9446D0C2B2F6F0093EB9C /* UispUploader.java in Sources */,
33F944E10C2B33560093EB9C /* AvrdudeUploader.java in Sources */,
335A29140C8CCC0900D8A7F4 /* PApplet.java in Sources */,
335A29150C8CCC0900D8A7F4 /* PConstants.java in Sources */,
335A29160C8CCC0900D8A7F4 /* PFont.java in Sources */,
335A29170C8CCC0900D8A7F4 /* PGraphics.java in Sources */,
335A29180C8CCC0900D8A7F4 /* PGraphics2D.java in Sources */,
335A29190C8CCC0900D8A7F4 /* PGraphics3D.java in Sources */,
335A291A0C8CCC0900D8A7F4 /* PGraphicsJava2D.java in Sources */,
335A291B0C8CCC0900D8A7F4 /* PImage.java in Sources */,
335A291C0C8CCC0900D8A7F4 /* PLine.java in Sources */,
335A291D0C8CCC0900D8A7F4 /* PMatrix.java in Sources */,
335A291E0C8CCC0900D8A7F4 /* PPolygon.java in Sources */,
335A291F0C8CCC0900D8A7F4 /* PShape.java in Sources */,
335A29200C8CCC0900D8A7F4 /* PTriangle.java in Sources */,
335A29240C8CCC5E00D8A7F4 /* DiscourseFormat.java in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

BIN
build/macosx/dist/libquaqua.jnilib vendored Executable file

Binary file not shown.

BIN
build/macosx/dist/quaqua.jar vendored Executable file

Binary file not shown.

View File

@ -30,8 +30,8 @@ void loop()
digitalWrite(pins[i], LOW); // and turning it off.
}
for (i = num_pins - 1; i >= 0; i--) {
digitalWrite(i, HIGH);
digitalWrite(pins[i], HIGH);
delay(timer);
digitalWrite(i, LOW);
digitalWrite(pins[i], LOW);
}
}

Binary file not shown.

View File

@ -145,8 +145,8 @@ CLASSPATH="..\\build\\windows\\work\\lib\\RXTXcomm.jar;..\\build\\windows\\work\
# show the user an error, rather than crapping out with some strange
# "class not found" crap
# need to do this twice because otherwise dependencies aren't resolved right.
../build/windows/work/jikes -target 1.3 +D -classpath "$CLASSPATH;..\\build\\windows\\work\\classes" -d ..\\build\\windows\\work\\classes preproc/*.java syntax/*.java tools/*.java *.java
../build/windows/work/jikes -target 1.3 +D -classpath "$CLASSPATH;..\\build\\windows\\work\\classes" -d ..\\build\\windows\\work\\classes preproc/*.java syntax/*.java tools/*.java *.java
../build/windows/work/jikes -target 1.3 +D -classpath "$CLASSPATH;..\\build\\windows\\work\\classes" -d ..\\build\\windows\\work\\classes ../core/*.java preproc/*.java syntax/*.java tools/*.java *.java
../build/windows/work/jikes -target 1.3 +D -classpath "$CLASSPATH;..\\build\\windows\\work\\classes" -d ..\\build\\windows\\work\\classes ../core/*.java preproc/*.java syntax/*.java tools/*.java *.java
cd ../build/windows/work/classes
rm -f ../lib/pde.jar

8334
core/PApplet.java Normal file

File diff suppressed because it is too large Load Diff

322
core/PConstants.java Normal file
View File

@ -0,0 +1,322 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2004-06 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
*/
package processing.core;
import java.awt.Cursor;
import java.awt.event.KeyEvent;
/**
* Numbers shared throughout processing.core.
* <P>
* An attempt is made to keep the constants as short/non-verbose
* 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.
*/
public interface PConstants {
// renderers known to processing.core
static final String P2D = "processing.core.PGraphics2D";
static final String P3D = "processing.core.PGraphics3D";
static final String JAVA2D = "processing.core.PGraphicsJava2D";
static final String OPENGL = "processing.opengl.PGraphicsOpenGL";
static final String PDF = "processing.pdf.PGraphicsPDF";
static final String DXF = "processing.dxf.RawDXF";
//static final String SVG = "processing.dxf.PGraphicsSVG";
// platform IDs for PApplet.platform
static final int WINDOWS = 1;
static final int MACOS9 = 2;
static final int MACOSX = 3;
static final int LINUX = 4;
static final int OTHER = 0;
// for better parity between c++ version (at no speed cost)
static final float EPSILON = 0.0001f;
// was around for auto-port to mobile version
//static final float ONE = 1.0f;
// useful goodness
static final float PI = (float) Math.PI;
static final float HALF_PI = PI / 2.0f;
static final float THIRD_PI = PI / 3.0f;
static final float QUARTER_PI = PI / 4.0f;
static final float TWO_PI = PI * 2.0f;
static final float DEG_TO_RAD = PI/180.0f;
static final float RAD_TO_DEG = 180.0f/PI;
// angle modes
//static final int RADIANS = 0;
//static final int DEGREES = 1;
// used by split, all the standard whitespace chars
// (also includes unicode nbsp, that little bostage)
static final String WHITESPACE = " \t\n\r\f\u00A0";
// for colors and/or images
static final int RGB = 1; // image & color
static final int ARGB = 2; // image
static final int HSB = 3; // color
static final int ALPHA = 4; // image
// image file types
static final int TIFF = 0;
static final int TARGA = 1;
static final int JPEG = 2;
static final int GIF = 3;
// filter/convert types
static final int BLUR = 11;
static final int GRAY = 12;
static final int INVERT = 13;
static final int OPAQUE = 14;
static final int POSTERIZE = 15;
static final int THRESHOLD = 16;
static final int ERODE = 17;
static final int DILATE = 18;
// blend mode keyword definitions
// @see processing.core.PImage#blendColor(int,int,int)
public final static int REPLACE = 0;
public final static int BLEND = 1 << 0;
public final static int ADD = 1 << 1;
public final static int SUBTRACT = 1 << 2;
public final static int LIGHTEST = 1 << 3;
public final static int DARKEST = 1 << 4;
public final static int DIFFERENCE = 1 << 5;
public final static int EXCLUSION = 1 << 6;
public final static int MULTIPLY = 1 << 7;
public final static int SCREEN = 1 << 8;
public final static int OVERLAY = 1 << 9;
public final static int HARD_LIGHT = 1 << 10;
public final static int SOFT_LIGHT = 1 << 11;
public final static int DODGE = 1 << 12;
public final static int BURN = 1 << 13;
// colour component bitmasks
public static final int ALPHA_MASK = 0xff000000;
public static final int RED_MASK = 0x00ff0000;
public static final int GREEN_MASK = 0x0000ff00;
public static final int BLUE_MASK = 0x000000ff;
// for messages
static final int CHATTER = 0;
static final int COMPLAINT = 1;
static final int PROBLEM = 2;
// types of projection matrices
static final int CUSTOM = 0; // user-specified fanciness
static final int ORTHOGRAPHIC = 2; // 2D isometric projection
static final int PERSPECTIVE = 3; // perspective matrix
// rendering settings
static final float PIXEL_CENTER = 0.5f; // for polygon aa
// shapes
// the low four bits set the variety,
// higher bits set the specific shape type
static final int POINTS = (1 << 4) | 0;
static final int LINES = (1 << 5) | 0;
//static final int LINE_STRIP = (1 << 5) | 1;
//static final int LINE_LOOP = (1 << 5) | 2;
static final int TRIANGLES = (1 << 6) | 0;
static final int TRIANGLE_STRIP = (1 << 6) | 1;
static final int TRIANGLE_FAN = (1 << 6) | 2;
static final int QUADS = (1 << 7) | 0;
static final int QUAD_STRIP = (1 << 7) | 1;
static final int POLYGON = (1 << 8) | 0;
//static final int CONCAVE_POLYGON = (1 << 8) | 1;
//static final int CONVEX_POLYGON = (1 << 8) | 2;
static final int OPEN = 1;
static final int CLOSE = 2;
// shape drawing modes
/** Draw mode convention to use (x, y) to (width, height) */
static final int CORNER = 0;
/** Draw mode convention to use (x1, y1) to (x2, y2) coordinates */
static final int CORNERS = 1;
/** @deprecated Use RADIUS instead (as of 0125) */
static final int CENTER_RADIUS = 2;
/** Draw mode from the center, and using the radius */
static final int RADIUS = 2;
/** Draw from the center, using second pair of values as the diameter.
Formerly called CENTER_DIAMETER in alpha releases */
static final int CENTER = 3;
// vertically alignment modes for text
/** Default vertical alignment for text placement */
static final int BASELINE = 0;
/** Align text to the top */
static final int TOP = 101;
/** Align text from the bottom, using the baseline. */
static final int BOTTOM = 102;
// uv texture orientation modes
static final int NORMALIZED = 1; //_SPACE = 0; // 0..1
static final int IMAGE = 2;
// text placement modes
/**
* textMode(MODEL) is the default, meaning that characters
* will be affected by transformations like any other shapes.
* <p/>
* Changed value in 0093 to not interfere with LEFT, CENTER, and RIGHT.
*/
static final int MODEL = 4;
/**
* textMode(SHAPE) draws text using the the glyph outlines of
* individual characters rather than as textures. If the outlines are
* not available, then textMode(SHAPE) will be ignored and textMode(MODEL)
* will be used instead. For this reason, be sure to call textMode()
* <EM>after</EM> calling textFont().
* <p/>
* Currently, textMode(SHAPE) is only supported by OPENGL mode.
* It also requires Java 1.2 or higher (OPENGL requires 1.4 anyway)
*/
static final int SHAPE = 5;
// text alignment modes
// are inherited from LEFT, CENTER, RIGHT
// stroke modes
static final int SQUARE = 1 << 0; // called 'butt' in the svg spec
static final int ROUND = 1 << 1;
static final int PROJECT = 1 << 2; // called 'square' in the svg spec
static final int MITER = 1 << 3;
static final int BEVEL = 1 << 5;
// lighting
static final int AMBIENT = 0;
static final int DIRECTIONAL = 1;
static final int POINT = 2;
static final int SPOT = 3;
// key constants
// only including the most-used of these guys
// if people need more esoteric keys, they can learn about
// the esoteric java KeyEvent api and of virtual keys
// both key and keyCode will equal these values
// for 0125, these were changed to 'char' values, because they
// can be upgraded to ints automatically by Java, but having them
// as ints prevented split(blah, TAB) from working
static final char BACKSPACE = 8;
static final char TAB = 9;
static final char ENTER = 10;
static final char RETURN = 13;
static final char ESC = 27;
static final char DELETE = 127;
// i.e. if ((key == CODED) && (keyCode == UP))
static final int CODED = 0xffff;
// key will be CODED and keyCode will be this value
static final int UP = KeyEvent.VK_UP;
static final int DOWN = KeyEvent.VK_DOWN;
static final int LEFT = KeyEvent.VK_LEFT;
static final int RIGHT = KeyEvent.VK_RIGHT;
// key will be CODED and keyCode will be this value
static final int ALT = KeyEvent.VK_ALT;
static final int CONTROL = KeyEvent.VK_CONTROL;
static final int SHIFT = KeyEvent.VK_SHIFT;
// cursor types
static final int ARROW = Cursor.DEFAULT_CURSOR;
static final int CROSS = Cursor.CROSSHAIR_CURSOR;
static final int HAND = Cursor.HAND_CURSOR;
static final int MOVE = Cursor.MOVE_CURSOR;
static final int TEXT = Cursor.TEXT_CURSOR;
static final int WAIT = Cursor.WAIT_CURSOR;
// hints
//static final int SCALE_STROKE_WIDTH = 0;
//static final int LIGHTING_AFFECTS_STROKE = 1;
static final int ENABLE_NATIVE_FONTS = 2;
static final int DISABLE_TEXT_SMOOTH = 3;
//static final int DISABLE_SMOOTH_HACK = 4;
static final int DISABLE_DEPTH_TEST = 5;
static final int NO_FLYING_POO = 6;
static final int ENABLE_DEPTH_SORT = 7;
static final int DISABLE_ERROR_REPORT = 8;
static final int ENABLE_ACCURATE_TEXTURES = 9;
static final int HINT_COUNT = 10;
}

1019
core/PFont.java Normal file

File diff suppressed because it is too large Load Diff

4308
core/PGraphics.java Normal file

File diff suppressed because it is too large Load Diff

1672
core/PGraphics2D.java Normal file

File diff suppressed because it is too large Load Diff

3943
core/PGraphics3D.java Normal file

File diff suppressed because it is too large Load Diff

1381
core/PGraphicsJava2D.java Normal file

File diff suppressed because it is too large Load Diff

2598
core/PImage.java Normal file

File diff suppressed because it is too large Load Diff

1295
core/PLine.java Normal file

File diff suppressed because it is too large Load Diff

640
core/PMatrix.java Normal file
View File

@ -0,0 +1,640 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://Proce55ing.net
Copyright (c) 2005-06 Ben Fry and Casey Reas
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
*/
package processing.core;
/**
* 4x4 matrix implementation.
*/
public final class PMatrix implements PConstants {
public float m00, m01, m02, m03;
public float m10, m11, m12, m13;
public float m20, m21, m22, m23;
public float m30, m31, m32, m33;
final static int DEFAULT_STACK_DEPTH = 0;
int maxStackDepth;
int stackPointer = 0;
float stack[][];
// locally allocated version to avoid creating new memory
static protected PMatrix inverseCopy;
public PMatrix() {
set(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
maxStackDepth = DEFAULT_STACK_DEPTH;
}
public PMatrix(int stackDepth) {
set(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
stack = new float[stackDepth][16];
maxStackDepth = stackDepth;
}
public PMatrix(float m00, float m01, float m02, float m03,
float m10, float m11, float m12, float m13,
float m20, float m21, float m22, float m23,
float m30, float m31, float m32, float m33) {
set(m00, m01, m02, m03,
m10, m11, m12, m13,
m20, m21, m22, m23,
m30, m31, m32, m33);
maxStackDepth = DEFAULT_STACK_DEPTH;
}
// Make a copy of a matrix. We copy the stack depth,
// but we don't make a copy of the stack or the stack pointer.
public PMatrix(PMatrix src) {
set(src);
maxStackDepth = src.maxStackDepth;
stack = new float[maxStackDepth][16];
}
public void reset() {
set(1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1);
}
public void clearStack() {
stackPointer = 0;
}
public boolean push() {
if (stackPointer == maxStackDepth) return false;
stack[stackPointer][0] = m00;
stack[stackPointer][1] = m01;
stack[stackPointer][2] = m02;
stack[stackPointer][3] = m03;
stack[stackPointer][4] = m10;
stack[stackPointer][5] = m11;
stack[stackPointer][6] = m12;
stack[stackPointer][7] = m13;
stack[stackPointer][8] = m20;
stack[stackPointer][9] = m21;
stack[stackPointer][10] = m22;
stack[stackPointer][11] = m23;
stack[stackPointer][12] = m30;
stack[stackPointer][13] = m31;
stack[stackPointer][14] = m32;
stack[stackPointer][15] = m33;
stackPointer++;
return true;
}
public boolean pop() {
if (stackPointer == 0) return false;
stackPointer--;
m00 = stack[stackPointer][0];
m01 = stack[stackPointer][1];
m02 = stack[stackPointer][2];
m03 = stack[stackPointer][3];
m10 = stack[stackPointer][4];
m11 = stack[stackPointer][5];
m12 = stack[stackPointer][6];
m13 = stack[stackPointer][7];
m20 = stack[stackPointer][8];
m21 = stack[stackPointer][9];
m22 = stack[stackPointer][10];
m23 = stack[stackPointer][11];
m30 = stack[stackPointer][12];
m31 = stack[stackPointer][13];
m32 = stack[stackPointer][14];
m33 = stack[stackPointer][15];
return true;
}
public void set(PMatrix src) {
set(src.m00, src.m01, src.m02, src.m03,
src.m10, src.m11, src.m12, src.m13,
src.m20, src.m21, src.m22, src.m23,
src.m30, src.m31, src.m32, src.m33);
}
public void set(float m00, float m01, float m02, float m03,
float m10, float m11, float m12, float m13,
float m20, float m21, float m22, float m23,
float m30, float m31, float m32, float m33) {
this.m00 = m00; this.m01 = m01; this.m02 = m02; this.m03 = m03;
this.m10 = m10; this.m11 = m11; this.m12 = m12; this.m13 = m13;
this.m20 = m20; this.m21 = m21; this.m22 = m22; this.m23 = m23;
this.m30 = m30; this.m31 = m31; this.m32 = m32; this.m33 = m33;
}
public void translate(float tx, float ty) {
translate(tx, ty, 0);
}
public void invTranslate(float tx, float ty) {
invTranslate(tx, ty, 0);
}
public void translate(float tx, float ty, float tz) {
m03 += tx*m00 + ty*m01 + tz*m02;
m13 += tx*m10 + ty*m11 + tz*m12;
m23 += tx*m20 + ty*m21 + tz*m22;
m33 += tx*m30 + ty*m31 + tz*m32;
}
public void invTranslate(float tx, float ty, float tz) {
preApply(1, 0, 0, -tx,
0, 1, 0, -ty,
0, 0, 1, -tz,
0, 0, 0, 1);
}
// OPT could save several multiplies for the 0s and 1s by just
// putting the multMatrix code here and removing uneccessary terms
public void rotateX(float angle) {
float c = cos(angle);
float s = sin(angle);
apply(1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1);
}
public void invRotateX(float angle) {
float c = cos(-angle);
float s = sin(-angle);
preApply(1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1);
}
public void rotateY(float angle) {
float c = cos(angle);
float s = sin(angle);
apply(c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1);
}
public void invRotateY(float angle) {
float c = cos(-angle);
float s = sin(-angle);
preApply(c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1);
}
/**
* Just calls rotateZ because two dimensional rotation
* is the same as rotating along the z-axis.
*/
public void rotate(float angle) {
rotateZ(angle);
}
public void invRotate(float angle) {
invRotateZ(angle);
}
public void rotateZ(float angle) {
float c = cos(angle);
float s = sin(angle);
apply(c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
public void invRotateZ(float angle) {
float c = cos(-angle);
float s = sin(-angle);
preApply(c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
public void rotate(float angle, float v0, float v1, float v2) {
// should be in radians (i think), instead of degrees (gl uses degrees)
// based on 15-463 code, but similar to opengl ref p.443
// TODO should make sure this vector is normalized
float c = cos(angle);
float s = sin(angle);
float t = 1.0f - c;
apply((t*v0*v0) + c, (t*v0*v1) - (s*v2), (t*v0*v2) + (s*v1), 0,
(t*v0*v1) + (s*v2), (t*v1*v1) + c, (t*v1*v2) - (s*v0), 0,
(t*v0*v2) - (s*v1), (t*v1*v2) + (s*v0), (t*v2*v2) + c, 0,
0, 0, 0, 1);
}
public void invRotate(float angle, float v0, float v1, float v2) {
// TODO should make sure this vector is normalized
float c = cos(-angle);
float s = sin(-angle);
float t = 1.0f - c;
preApply((t*v0*v0) + c, (t*v0*v1) - (s*v2), (t*v0*v2) + (s*v1), 0,
(t*v0*v1) + (s*v2), (t*v1*v1) + c, (t*v1*v2) - (s*v0), 0,
(t*v0*v2) - (s*v1), (t*v1*v2) + (s*v0), (t*v2*v2) + c, 0,
0, 0, 0, 1);
}
public void scale(float s) {
apply(s, 0, 0, 0, 0, s, 0, 0, 0, 0, s, 0, 0, 0, 0, 1);
}
public void invScale(float s) {
preApply(1/s, 0, 0, 0, 0, 1/s, 0, 0, 0, 0, 1/s, 0, 0, 0, 0, 1);
}
public void scale(float sx, float sy) {
apply(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
public void invScale(float sx, float sy) {
preApply(1/sx, 0, 0, 0, 0, 1/sy, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
}
// OPTIMIZE: same as above
public void scale(float x, float y, float z) {
apply(x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1);
}
public void invScale(float x, float y, float z) {
preApply(1/x, 0, 0, 0, 0, 1/y, 0, 0, 0, 0, 1/z, 0, 0, 0, 0, 1);
}
/*
public void transform(float n00, float n01, float n02, float n03,
float n10, float n11, float n12, float n13,
float n20, float n21, float n22, float n23,
float n30, float n31, float n32, float n33) {
apply(n00, n01, n02, n03,
n10, n11, n12, n13,
n20, n21, n22, n23,
n30, n31, n32, n33);
}
*/
public void preApply(PMatrix lhs) {
preApply(lhs.m00, lhs.m01, lhs.m02, lhs.m03,
lhs.m10, lhs.m11, lhs.m12, lhs.m13,
lhs.m20, lhs.m21, lhs.m22, lhs.m23,
lhs.m30, lhs.m31, lhs.m32, lhs.m33);
}
// for inverse operations, like multiplying the matrix on the left
public void preApply(float n00, float n01, float n02, float n03,
float n10, float n11, float n12, float n13,
float n20, float n21, float n22, float n23,
float n30, float n31, float n32, float n33) {
float r00 = n00*m00 + n01*m10 + n02*m20 + n03*m30;
float r01 = n00*m01 + n01*m11 + n02*m21 + n03*m31;
float r02 = n00*m02 + n01*m12 + n02*m22 + n03*m32;
float r03 = n00*m03 + n01*m13 + n02*m23 + n03*m33;
float r10 = n10*m00 + n11*m10 + n12*m20 + n13*m30;
float r11 = n10*m01 + n11*m11 + n12*m21 + n13*m31;
float r12 = n10*m02 + n11*m12 + n12*m22 + n13*m32;
float r13 = n10*m03 + n11*m13 + n12*m23 + n13*m33;
float r20 = n20*m00 + n21*m10 + n22*m20 + n23*m30;
float r21 = n20*m01 + n21*m11 + n22*m21 + n23*m31;
float r22 = n20*m02 + n21*m12 + n22*m22 + n23*m32;
float r23 = n20*m03 + n21*m13 + n22*m23 + n23*m33;
float r30 = n30*m00 + n31*m10 + n32*m20 + n33*m30;
float r31 = n30*m01 + n31*m11 + n32*m21 + n33*m31;
float r32 = n30*m02 + n31*m12 + n32*m22 + n33*m32;
float r33 = n30*m03 + n31*m13 + n32*m23 + n33*m33;
m00 = r00; m01 = r01; m02 = r02; m03 = r03;
m10 = r10; m11 = r11; m12 = r12; m13 = r13;
m20 = r20; m21 = r21; m22 = r22; m23 = r23;
m30 = r30; m31 = r31; m32 = r32; m33 = r33;
}
public boolean invApply(PMatrix rhs) {
PMatrix copy = new PMatrix(rhs);
PMatrix inverse = copy.invert();
if (inverse == null) return false;
preApply(inverse);
return true;
}
public boolean invApply(float n00, float n01, float n02, float n03,
float n10, float n11, float n12, float n13,
float n20, float n21, float n22, float n23,
float n30, float n31, float n32, float n33) {
if (inverseCopy == null) {
inverseCopy = new PMatrix();
}
inverseCopy.set(n00, n01, n02, n03,
n10, n11, n12, n13,
n20, n21, n22, n23,
n30, n31, n32, n33);
PMatrix inverse = inverseCopy.invert();
if (inverse == null) return false;
preApply(inverse);
return true;
}
public void apply(PMatrix rhs) {
apply(rhs.m00, rhs.m01, rhs.m02, rhs.m03,
rhs.m10, rhs.m11, rhs.m12, rhs.m13,
rhs.m20, rhs.m21, rhs.m22, rhs.m23,
rhs.m30, rhs.m31, rhs.m32, rhs.m33);
}
public void apply(float n00, float n01, float n02, float n03,
float n10, float n11, float n12, float n13,
float n20, float n21, float n22, float n23,
float n30, float n31, float n32, float n33) {
float r00 = m00*n00 + m01*n10 + m02*n20 + m03*n30;
float r01 = m00*n01 + m01*n11 + m02*n21 + m03*n31;
float r02 = m00*n02 + m01*n12 + m02*n22 + m03*n32;
float r03 = m00*n03 + m01*n13 + m02*n23 + m03*n33;
float r10 = m10*n00 + m11*n10 + m12*n20 + m13*n30;
float r11 = m10*n01 + m11*n11 + m12*n21 + m13*n31;
float r12 = m10*n02 + m11*n12 + m12*n22 + m13*n32;
float r13 = m10*n03 + m11*n13 + m12*n23 + m13*n33;
float r20 = m20*n00 + m21*n10 + m22*n20 + m23*n30;
float r21 = m20*n01 + m21*n11 + m22*n21 + m23*n31;
float r22 = m20*n02 + m21*n12 + m22*n22 + m23*n32;
float r23 = m20*n03 + m21*n13 + m22*n23 + m23*n33;
float r30 = m30*n00 + m31*n10 + m32*n20 + m33*n30;
float r31 = m30*n01 + m31*n11 + m32*n21 + m33*n31;
float r32 = m30*n02 + m31*n12 + m32*n22 + m33*n32;
float r33 = m30*n03 + m31*n13 + m32*n23 + m33*n33;
m00 = r00; m01 = r01; m02 = r02; m03 = r03;
m10 = r10; m11 = r11; m12 = r12; m13 = r13;
m20 = r20; m21 = r21; m22 = r22; m23 = r23;
m30 = r30; m31 = r31; m32 = r32; m33 = r33;
}
public void mult3(float vec[], float out[]) {
// must use these temp vars because vec may be the same as out
float tmpx = m00*vec[0] + m01*vec[1] + m02*vec[2] + m03;
float tmpy = m10*vec[0] + m11*vec[1] + m12*vec[2] + m13;
float tmpz = m20*vec[0] + m21*vec[1] + m22*vec[2] + m23;
out[0] = tmpx;
out[1] = tmpy;
out[2] = tmpz;
}
public void mult(float vec[], float out[]) {
// must use these temp vars because vec may be the same as out
float tmpx = m00*vec[0] + m01*vec[1] + m02*vec[2] + m03*vec[3];
float tmpy = m10*vec[0] + m11*vec[1] + m12*vec[2] + m13*vec[3];
float tmpz = m20*vec[0] + m21*vec[1] + m22*vec[2] + m23*vec[3];
float tmpw = m30*vec[0] + m31*vec[1] + m32*vec[2] + m33*vec[3];
out[0] = tmpx;
out[1] = tmpy;
out[2] = tmpz;
out[3] = tmpw;
}
/**
* @return the determinant of the matrix
*/
public float determinant() {
float f =
m00
* ((m11 * m22 * m33 + m12 * m23 * m31 + m13 * m21 * m32)
- m13 * m22 * m31
- m11 * m23 * m32
- m12 * m21 * m33);
f -= m01
* ((m10 * m22 * m33 + m12 * m23 * m30 + m13 * m20 * m32)
- m13 * m22 * m30
- m10 * m23 * m32
- m12 * m20 * m33);
f += m02
* ((m10 * m21 * m33 + m11 * m23 * m30 + m13 * m20 * m31)
- m13 * m21 * m30
- m10 * m23 * m31
- m11 * m20 * m33);
f -= m03
* ((m10 * m21 * m32 + m11 * m22 * m30 + m12 * m20 * m31)
- m12 * m21 * m30
- m10 * m22 * m31
- m11 * m20 * m32);
return f;
}
/**
* Calculate the determinant of a 3x3 matrix
* @return result
*/
private float determinant3x3(float t00, float t01, float t02,
float t10, float t11, float t12,
float t20, float t21, float t22) {
return (t00 * (t11 * t22 - t12 * t21) +
t01 * (t12 * t20 - t10 * t22) +
t02 * (t10 * t21 - t11 * t20));
}
public PMatrix transpose() {
float temp;
temp = m01; m01 = m10; m10 = temp;
temp = m02; m02 = m20; m20 = temp;
temp = m03; m03 = m30; m30 = temp;
temp = m12; m12 = m21; m21 = temp;
temp = m13; m13 = m31; m31 = temp;
temp = m23; m23 = m32; m32 = temp;
return this;
}
/**
* Invert this matrix
* @return this if successful, null otherwise
*/
public PMatrix invert() {
float determinant = determinant();
if (determinant != 0) {
// m00 m01 m02 m03
// m10 m11 m12 m13
// m20 m21 m22 m23
// m30 m31 m32 m33
float determinant_inv = 1f / determinant;
// first row
float t00 = determinant3x3(m11, m12, m13, m21, m22, m23, m31, m32, m33);
float t01 = -determinant3x3(m10, m12, m13, m20, m22, m23, m30, m32, m33);
float t02 = determinant3x3(m10, m11, m13, m20, m21, m23, m30, m31, m33);
float t03 = -determinant3x3(m10, m11, m12, m20, m21, m22, m30, m31, m32);
// second row
float t10 = -determinant3x3(m01, m02, m03, m21, m22, m23, m31, m32, m33);
float t11 = determinant3x3(m00, m02, m03, m20, m22, m23, m30, m32, m33);
float t12 = -determinant3x3(m00, m01, m03, m20, m21, m23, m30, m31, m33);
float t13 = determinant3x3(m00, m01, m02, m20, m21, m22, m30, m31, m32);
// third row
float t20 = determinant3x3(m01, m02, m03, m11, m12, m13, m31, m32, m33);
float t21 = -determinant3x3(m00, m02, m03, m10, m12, m13, m30, m32, m33);
float t22 = determinant3x3(m00, m01, m03, m10, m11, m13, m30, m31, m33);
float t23 = -determinant3x3(m00, m01, m02, m10, m11, m12, m30, m31, m32);
// fourth row
float t30 = -determinant3x3(m01, m02, m03, m11, m12, m13, m21, m22, m23);
float t31 = determinant3x3(m00, m02, m03, m10, m12, m13, m20, m22, m23);
float t32 = -determinant3x3(m00, m01, m03, m10, m11, m13, m20, m21, m23);
float t33 = determinant3x3(m00, m01, m02, m10, m11, m12, m20, m21, m22);
// transpose and divide by the determinant
m00 = t00*determinant_inv;
m11 = t11*determinant_inv;
m22 = t22*determinant_inv;
m33 = t33*determinant_inv;
m01 = t10*determinant_inv;
m10 = t01*determinant_inv;
m20 = t02*determinant_inv;
m02 = t20*determinant_inv;
m12 = t21*determinant_inv;
m21 = t12*determinant_inv;
m03 = t30*determinant_inv;
m30 = t03*determinant_inv;
m13 = t31*determinant_inv;
m31 = t13*determinant_inv;
m32 = t23*determinant_inv;
m23 = t32*determinant_inv;
return this;
}
return null;
}
//////////////////////////////////////////////////////////////
public void print() {
int big = (int) Math.abs(max(max(max(max(abs(m00), abs(m01)),
max(abs(m02), abs(m03))),
max(max(abs(m10), abs(m11)),
max(abs(m12), abs(m13)))),
max(max(max(abs(m20), abs(m21)),
max(abs(m22), abs(m23))),
max(max(abs(m30), abs(m31)),
max(abs(m32), abs(m33))))));
// avoid infinite loop
if (Float.isNaN(big) || Float.isInfinite(big)) {
big = 1000000; // set to something arbitrary
}
int d = 1;
while ((big /= 10) != 0) d++; // cheap log()
System.out.println(PApplet.nfs(m00, d, 4) + " " +
PApplet.nfs(m01, d, 4) + " " +
PApplet.nfs(m02, d, 4) + " " +
PApplet.nfs(m03, d, 4));
System.out.println(PApplet.nfs(m10, d, 4) + " " +
PApplet.nfs(m11, d, 4) + " " +
PApplet.nfs(m12, d, 4) + " " +
PApplet.nfs(m13, d, 4));
System.out.println(PApplet.nfs(m20, d, 4) + " " +
PApplet.nfs(m21, d, 4) + " " +
PApplet.nfs(m22, d, 4) + " " +
PApplet.nfs(m23, d, 4));
System.out.println(PApplet.nfs(m30, d, 4) + " " +
PApplet.nfs(m31, d, 4) + " " +
PApplet.nfs(m32, d, 4) + " " +
PApplet.nfs(m33, d, 4));
System.out.println();
}
//////////////////////////////////////////////////////////////
private final float max(float a, float b) {
return (a > b) ? a : b;
}
private final float abs(float a) {
return (a < 0) ? -a : a;
}
private final float sin(float angle) {
return (float)Math.sin(angle);
}
private final float cos(float angle) {
return (float)Math.cos(angle);
}
}

772
core/PPolygon.java Normal file
View File

@ -0,0 +1,772 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2004-06 Ben Fry and Casey Reas
Copyright (c) 2001-04 Massachusetts Institute of Technology
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
*/
package processing.core;
/**
* zbuffer polygon rendering object for PGraphics.
* <P>
* Likely to be removed before 1.0 as it's no longer particularly used.
*/
public class PPolygon implements PConstants {
// identical to the constants from PGraphics
static final int X = 0; // transformed xyzw
static final int Y = 1; // formerly SX SY SZ
static final int Z = 2;
static final int R = 3; // actual rgb, after lighting
static final int G = 4; // fill stored here, transform in place
static final int B = 5;
static final int A = 6;
static final int U = 7; // texture
static final int V = 8;
//
static final int DEFAULT_SIZE = 64; // this is needed for spheres
float vertices[][] = new float[DEFAULT_SIZE][PGraphics.VERTEX_FIELD_COUNT];
int vertexCount;
// really this is "debug" but..
static final boolean FRY = false;
// after some fiddling, this seems to produce the best results
//static final int ZBUFFER_MIN_COVERAGE = 204;
float r[] = new float[DEFAULT_SIZE]; // storage used by incrementalize
float dr[] = new float[DEFAULT_SIZE];
float l[] = new float[DEFAULT_SIZE]; // more storage for incrementalize
float dl[] = new float[DEFAULT_SIZE];
float sp[] = new float[DEFAULT_SIZE]; // temporary storage for scanline
float sdp[] = new float[DEFAULT_SIZE];
// color and xyz are always interpolated
boolean interpX;
boolean interpZ;
boolean interpUV; // is this necessary? could just check timage != null
boolean interpARGB;
int rgba;
int r2, g2, b2, a2, a2orig;
boolean noDepthTest;
PGraphics parent;
int pixels[];
// the parent's width/height,
// or if smooth is enabled, parent's w/h scaled
// up by the smooth dimension
int width, height;
int width1, height1;
PImage timage;
int tpixels[];
int theight, twidth;
int theight1, twidth1;
int tformat;
// temp fix to behave like SMOOTH_IMAGES
boolean texture_smooth;
// for anti-aliasing
static final int SUBXRES = 8;
static final int SUBXRES1 = 7;
static final int SUBYRES = 8;
static final int SUBYRES1 = 7;
static final int MAX_COVERAGE = SUBXRES * SUBYRES;
boolean smooth;
int firstModY;
int lastModY;
int lastY;
int aaleft[] = new int[SUBYRES];
int aaright[] = new int[SUBYRES];
int aaleftmin, aarightmin;
int aaleftmax, aarightmax;
int aaleftfull, aarightfull;
final private int MODYRES(int y) {
return (y & SUBYRES1);
}
public PPolygon(PGraphics iparent) {
parent = iparent;
reset(0);
}
public void reset(int count) {
vertexCount = count;
interpX = true;
interpZ = true;
interpUV = false;
interpARGB = true;
timage = null;
}
public float[] nextVertex() {
if (vertexCount == vertices.length) {
//parent.message(CHATTER, "re-allocating for " +
// (vertexCount*2) + " vertices");
float temp[][] = new float[vertexCount<<1][PGraphics.VERTEX_FIELD_COUNT];
System.arraycopy(vertices, 0, temp, 0, vertexCount);
vertices = temp;
r = new float[vertices.length];
dr = new float[vertices.length];
l = new float[vertices.length];
dl = new float[vertices.length];
sp = new float[vertices.length];
sdp = new float[vertices.length];
}
return vertices[vertexCount++]; // returns v[0], sets vc to 1
}
/**
* Return true if this vertex is redundant. If so, will also
* decrement the vertex count.
*/
/*
public boolean redundantVertex(float x, float y, float z) {
// because vertexCount will be 2 when setting vertex[1]
if (vertexCount < 2) return false;
// vertexCount-1 is the current vertex that would be used
// vertexCount-2 would be the previous feller
if ((Math.abs(vertices[vertexCount-2][MX] - x) < EPSILON) &&
(Math.abs(vertices[vertexCount-2][MY] - y) < EPSILON) &&
(Math.abs(vertices[vertexCount-2][MZ] - z) < EPSILON)) {
vertexCount--;
return true;
}
return false;
}
*/
public void texture(PImage image) {
this.timage = image;
this.tpixels = image.pixels;
this.twidth = image.width;
this.theight = image.height;
this.tformat = image.format;
twidth1 = twidth - 1;
theight1 = theight - 1;
interpUV = true;
}
public void render() {
if (vertexCount < 3) return;
// these may have changed due to a resize()
// so they should be refreshed here
pixels = parent.pixels;
//zbuffer = parent.zbuffer;
noDepthTest = parent.hints[DISABLE_DEPTH_TEST];
smooth = parent.smooth;
// by default, text turns on smooth for the textures
// themselves. but this should be shut off if the hint
// for DISABLE_TEXT_SMOOTH is set.
texture_smooth = (//parent.drawing_text &&
!parent.hints[DISABLE_TEXT_SMOOTH]);
width = smooth ? parent.width*SUBXRES : parent.width;
height = smooth ? parent.height*SUBYRES : parent.height;
width1 = width - 1;
height1 = height - 1;
if (!interpARGB) {
r2 = (int) (vertices[0][R] * 255);
g2 = (int) (vertices[0][G] * 255);
b2 = (int) (vertices[0][B] * 255);
a2 = (int) (vertices[0][A] * 255);
a2orig = a2; // save an extra copy
rgba = 0xff000000 | (r2 << 16) | (g2 << 8) | b2;
}
for (int i = 0; i < vertexCount; i++) {
r[i] = 0; dr[i] = 0; l[i] = 0; dl[i] = 0;
}
// hack to not make polygons fly into the screen
if (parent.hints[NO_FLYING_POO]) {
float nwidth2 = -width * 2;
float nheight2 = -height * 2;
float width2 = width * 2;
float height2 = height * 2;
for (int i = 0; i < vertexCount; i++) {
if ((vertices[i][X] < nwidth2) ||
(vertices[i][X] > width2) ||
(vertices[i][Y] < nheight2) ||
(vertices[i][Y] > height2)) {
return; // this is a bad poly
}
}
}
if (smooth) {
for (int i = 0; i < vertexCount; i++) {
vertices[i][X] *= SUBXRES;
vertices[i][Y] *= SUBYRES;
}
firstModY = -1;
}
// find top vertex (y is zero at top, higher downwards)
int topi = 0;
float ymin = vertices[0][Y];
float ymax = vertices[0][Y]; // fry 031001
for (int i = 1; i < vertexCount; i++) {
if (vertices[i][Y] < ymin) {
ymin = vertices[i][Y];
topi = i;
}
if (vertices[i][Y] > ymax) ymax = vertices[i][Y];
}
// the last row is an exceptional case, because there won't
// necessarily be 8 rows of subpixel lines that will force
// the final line to render. so instead, the algo keeps track
// of the lastY (in subpixel resolution) that will be rendered
// and that will force a scanline to happen the same as
// every eighth in the other situations
//lastY = -1; // fry 031001
lastY = (int) (ymax - 0.5f); // global to class bc used by other fxns
int lefti = topi; // li, index of left vertex
int righti = topi; // ri, index of right vertex
int y = (int) (ymin + 0.5f); // current scan line
int lefty = y - 1; // lower end of left edge
int righty = y - 1; // lower end of right edge
interpX = true;
int remaining = vertexCount;
// scan in y, activating new edges on left & right
// as scan line passes over new vertices
while (remaining > 0) {
// advance left edge?
while ((lefty <= y) && (remaining > 0)) {
remaining--;
// step ccw down left side
int i = (lefti != 0) ? (lefti-1) : (vertexCount-1);
incrementalize_y(vertices[lefti], vertices[i], l, dl, y);
lefty = (int) (vertices[i][Y] + 0.5f);
lefti = i;
}
// advance right edge?
while ((righty <= y) && (remaining > 0)) {
remaining--;
// step cw down right edge
int i = (righti != vertexCount-1) ? (righti + 1) : 0;
incrementalize_y(vertices[righti], vertices[i], r, dr, y);
righty = (int) (vertices[i][Y] + 0.5f);
righti = i;
}
// do scanlines till end of l or r edge
while (y < lefty && y < righty) {
// this doesn't work because it's not always set here
//if (remaining == 0) {
//lastY = (lefty < righty) ? lefty-1 : righty-1;
//System.out.println("lastY is " + lastY);
//}
if ((y >= 0) && (y < height)) {
//try { // hopefully this bug is fixed
if (l[X] <= r[X]) scanline(y, l, r);
else scanline(y, r, l);
//} catch (ArrayIndexOutOfBoundsException e) {
//e.printStackTrace();
//}
}
y++;
// this increment probably needs to be different
// UV and RGB shouldn't be incremented until line is emitted
increment(l, dl);
increment(r, dr);
}
}
//if (smooth) {
//System.out.println("y/lasty/lastmody = " + y + " " + lastY + " " + lastModY);
//}
}
public void unexpand() {
if (smooth) {
for (int i = 0; i < vertexCount; i++) {
vertices[i][X] /= SUBXRES;
vertices[i][Y] /= SUBYRES;
}
}
}
private void scanline(int y, float l[], float r[]) {
//System.out.println("scanline " + y);
for (int i = 0; i < vertexCount; i++) { // should be moved later
sp[i] = 0; sdp[i] = 0;
}
// this rounding doesn't seem to be relevant with smooth
int lx = (int) (l[X] + 0.49999f); // ceil(l[X]-.5);
if (lx < 0) lx = 0;
int rx = (int) (r[X] - 0.5f);
if (rx > width1) rx = width1;
if (lx > rx) return;
if (smooth) {
int mody = MODYRES(y);
aaleft[mody] = lx;
aaright[mody] = rx;
if (firstModY == -1) {
firstModY = mody;
aaleftmin = lx; aaleftmax = lx;
aarightmin = rx; aarightmax = rx;
} else {
if (aaleftmin > aaleft[mody]) aaleftmin = aaleft[mody];
if (aaleftmax < aaleft[mody]) aaleftmax = aaleft[mody];
if (aarightmin > aaright[mody]) aarightmin = aaright[mody];
if (aarightmax < aaright[mody]) aarightmax = aaright[mody];
}
lastModY = mody; // moved up here (before the return) 031001
// not the eighth (or lastY) line, so not scanning this time
if ((mody != SUBYRES1) && (y != lastY)) return;
//lastModY = mody; // eeK! this was missing
//return;
//if (y == lastY) {
//System.out.println("y is lasty");
//}
//lastModY = mody;
aaleftfull = aaleftmax/SUBXRES + 1;
aarightfull = aarightmin/SUBXRES - 1;
}
// this is the setup, based on lx
incrementalize_x(l, r, sp, sdp, lx);
// scan in x, generating pixels
// using parent.width to get actual pixel index
// rather than scaled by smooth factor
int offset = smooth ? parent.width * (y / SUBYRES) : parent.width*y;
int truelx = 0, truerx = 0;
if (smooth) {
truelx = lx / SUBXRES;
truerx = (rx + SUBXRES1) / SUBXRES;
lx = aaleftmin / SUBXRES;
rx = (aarightmax + SUBXRES1) / SUBXRES;
if (lx < 0) lx = 0;
if (rx > parent.width1) rx = parent.width1;
}
interpX = false;
int tr, tg, tb, ta;
for (int x = lx; x <= rx; x++) {
// added == because things on same plane weren't replacing each other
// makes for strangeness in 3D, but totally necessary for 2D
//if (noDepthTest || (sp[Z] <= zbuffer[offset+x])) {
if (true) {
// map texture based on U, V coords in sp[U] and sp[V]
if (interpUV) {
int tu = (int)sp[U];
int tv = (int)sp[V];
if (tu > twidth1) tu = twidth1;
if (tv > theight1) tv = theight1;
if (tu < 0) tu = 0;
if (tv < 0) tv = 0;
int txy = tv*twidth + tu;
if (smooth || texture_smooth) {
//if (FRY) System.out.println("sp u v = " + sp[U] + " " + sp[V]);
//System.out.println("sp u v = " + sp[U] + " " + sp[V]);
// tuf1/tvf1 is the amount of coverage for the adjacent
// pixel, which is the decimal percentage.
int tuf1 = (int) (255f * (sp[U] - (float)tu));
int tvf1 = (int) (255f * (sp[V] - (float)tv));
// the closer sp[U or V] is to the decimal being zero
// the more coverage it should get of the original pixel
int tuf = 255 - tuf1;
int tvf = 255 - tvf1;
// this code sucks! filled with bugs and slow as hell!
int pixel00 = tpixels[txy];
int pixel01 = (tv < theight1) ?
tpixels[txy + twidth] : tpixels[txy];
int pixel10 = (tu < twidth1) ?
tpixels[txy + 1] : tpixels[txy];
int pixel11 = ((tv < theight1) && (tu < twidth1)) ?
tpixels[txy + twidth + 1] : tpixels[txy];
int p00, p01, p10, p11;
int px0, px1; //, pxy;
if (tformat == ALPHA) {
px0 = (pixel00*tuf + pixel10*tuf1) >> 8;
px1 = (pixel01*tuf + pixel11*tuf1) >> 8;
ta = (((px0*tvf + px1*tvf1) >> 8) *
(interpARGB ? ((int) (sp[A]*255)) : a2orig)) >> 8;
} else if (tformat == ARGB) {
p00 = (pixel00 >> 24) & 0xff;
p01 = (pixel01 >> 24) & 0xff;
p10 = (pixel10 >> 24) & 0xff;
p11 = (pixel11 >> 24) & 0xff;
px0 = (p00*tuf + p10*tuf1) >> 8;
px1 = (p01*tuf + p11*tuf1) >> 8;
ta = (((px0*tvf + px1*tvf1) >> 8) *
(interpARGB ? ((int) (sp[A]*255)) : a2orig)) >> 8;
} else { // RGB image, no alpha
ta = interpARGB ? ((int) (sp[A]*255)) : a2orig;
}
if ((tformat == RGB) || (tformat == ARGB)) {
p00 = (pixel00 >> 16) & 0xff; // red
p01 = (pixel01 >> 16) & 0xff;
p10 = (pixel10 >> 16) & 0xff;
p11 = (pixel11 >> 16) & 0xff;
px0 = (p00*tuf + p10*tuf1) >> 8;
px1 = (p01*tuf + p11*tuf1) >> 8;
tr = (((px0*tvf + px1*tvf1) >> 8) *
(interpARGB ? ((int) sp[R]*255) : r2)) >> 8;
p00 = (pixel00 >> 8) & 0xff; // green
p01 = (pixel01 >> 8) & 0xff;
p10 = (pixel10 >> 8) & 0xff;
p11 = (pixel11 >> 8) & 0xff;
px0 = (p00*tuf + p10*tuf1) >> 8;
px1 = (p01*tuf + p11*tuf1) >> 8;
tg = (((px0*tvf + px1*tvf1) >> 8) *
(interpARGB ? ((int) sp[G]*255) : g2)) >> 8;
p00 = pixel00 & 0xff; // blue
p01 = pixel01 & 0xff;
p10 = pixel10 & 0xff;
p11 = pixel11 & 0xff;
px0 = (p00*tuf + p10*tuf1) >> 8;
px1 = (p01*tuf + p11*tuf1) >> 8;
tb = (((px0*tvf + px1*tvf1) >> 8) *
(interpARGB ? ((int) sp[B]*255) : b2)) >> 8;
} else { // alpha image, only use current fill color
if (interpARGB) {
tr = (int) (sp[R] * 255);
tg = (int) (sp[G] * 255);
tb = (int) (sp[B] * 255);
} else {
tr = r2;
tg = g2;
tb = b2;
}
}
// get coverage for pixel if smooth
// checks smooth again here because of
// hints[SMOOTH_IMAGES] used up above
int weight = smooth ? coverage(x) : 255;
if (weight != 255) ta = ta*weight >> 8;
} else { // no smooth, just get the pixels
int tpixel = tpixels[txy];
// TODO i doubt splitting these guys really gets us
// all that much speed.. is it worth it?
if (tformat == ALPHA) {
ta = tpixel;
if (interpARGB) {
tr = (int) sp[R]*255;
tg = (int) sp[G]*255;
tb = (int) sp[B]*255;
if (sp[A] != 1) {
ta = (((int) sp[A]*255) * ta) >> 8;
}
} else {
tr = r2;
tg = g2;
tb = b2;
ta = (a2orig * ta) >> 8;
}
} else { // RGB or ARGB
ta = (tformat == RGB) ? 255 : (tpixel >> 24) & 0xff;
if (interpARGB) {
tr = (((int) sp[R]*255) * ((tpixel >> 16) & 0xff)) >> 8;
tg = (((int) sp[G]*255) * ((tpixel >> 8) & 0xff)) >> 8;
tb = (((int) sp[B]*255) * ((tpixel) & 0xff)) >> 8;
ta = (((int) sp[A]*255) * ta) >> 8;
} else {
tr = (r2 * ((tpixel >> 16) & 0xff)) >> 8;
tg = (g2 * ((tpixel >> 8) & 0xff)) >> 8;
tb = (b2 * ((tpixel) & 0xff)) >> 8;
ta = (a2orig * ta) >> 8;
}
}
}
if ((ta == 254) || (ta == 255)) { // if (ta & 0xf8) would be good
// no need to blend
pixels[offset+x] = 0xff000000 | (tr << 16) | (tg << 8) | tb;
//zbuffer[offset+x] = sp[Z];
} else {
// blend with pixel on screen
int a1 = 255-ta;
int r1 = (pixels[offset+x] >> 16) & 0xff;
int g1 = (pixels[offset+x] >> 8) & 0xff;
int b1 = (pixels[offset+x]) & 0xff;
pixels[offset+x] = 0xff000000 |
(((tr*ta + r1*a1) >> 8) << 16) |
((tg*ta + g1*a1) & 0xff00) |
((tb*ta + b1*a1) >> 8);
//if (ta > ZBUFFER_MIN_COVERAGE) zbuffer[offset+x] = sp[Z];
}
} else { // no image applied
int weight = smooth ? coverage(x) : 255;
if (interpARGB) {
r2 = (int) (sp[R] * 255);
g2 = (int) (sp[G] * 255);
b2 = (int) (sp[B] * 255);
if (sp[A] != 1) weight = (weight * ((int) (sp[A] * 255))) >> 8;
if (weight == 255) {
rgba = 0xff000000 | (r2 << 16) | (g2 << 8) | b2;
}
} else {
if (a2orig != 255) weight = (weight * a2orig) >> 8;
}
if (weight == 255) {
// no blend, no aa, just the rgba
pixels[offset+x] = rgba;
//zbuffer[offset+x] = sp[Z];
} else {
int r1 = (pixels[offset+x] >> 16) & 0xff;
int g1 = (pixels[offset+x] >> 8) & 0xff;
int b1 = (pixels[offset+x]) & 0xff;
a2 = weight;
int a1 = 255 - a2;
pixels[offset+x] = (0xff000000 |
((r1*a1 + r2*a2) >> 8) << 16 |
// use & instead of >> and << below
((g1*a1 + g2*a2) >> 8) << 8 |
((b1*a1 + b2*a2) >> 8));
//if (a2 > ZBUFFER_MIN_COVERAGE) zbuffer[offset+x] = sp[Z];
}
}
}
// if smooth enabled, don't increment values
// for the pixel in the stretch out version
// of the scanline used to get smooth edges.
if (!smooth || ((x >= truelx) && (x <= truerx))) {
increment(sp, sdp);
}
}
firstModY = -1;
interpX = true;
}
// x is in screen, not huge 8x coordinates
private int coverage(int x) {
if ((x >= aaleftfull) && (x <= aarightfull) &&
// important since not all SUBYRES lines may have been covered
(firstModY == 0) && (lastModY == SUBYRES1)) {
return 255;
}
int pixelLeft = x*SUBXRES; // huh?
int pixelRight = pixelLeft + 8;
int amt = 0;
for (int i = firstModY; i <= lastModY; i++) {
if ((aaleft[i] > pixelRight) || (aaright[i] < pixelLeft)) {
continue;
}
// does this need a +1 ?
amt += ((aaright[i] < pixelRight ? aaright[i] : pixelRight) -
(aaleft[i] > pixelLeft ? aaleft[i] : pixelLeft));
}
amt <<= 2;
return (amt == 256) ? 255 : amt;
}
private void incrementalize_y(float p1[], float p2[],
float p[], float dp[], int y) {
float delta = p2[Y] - p1[Y];
if (delta == 0) delta = 1;
float fraction = y + 0.5f - p1[Y];
if (interpX) {
dp[X] = (p2[X] - p1[X]) / delta;
p[X] = p1[X] + dp[X] * fraction;
}
if (interpZ) {
dp[Z] = (p2[Z] - p1[Z]) / delta;
p[Z] = p1[Z] + dp[Z] * fraction;
}
if (interpARGB) {
dp[R] = (p2[R] - p1[R]) / delta;
dp[G] = (p2[G] - p1[G]) / delta;
dp[B] = (p2[B] - p1[B]) / delta;
dp[A] = (p2[A] - p1[A]) / delta;
p[R] = p1[R] + dp[R] * fraction;
p[G] = p1[G] + dp[G] * fraction;
p[B] = p1[B] + dp[B] * fraction;
p[A] = p1[A] + dp[A] * fraction;
}
if (interpUV) {
dp[U] = (p2[U] - p1[U]) / delta;
dp[V] = (p2[V] - p1[V]) / delta;
//if (smooth) {
//p[U] = p1[U]; //+ dp[U] * fraction;
//p[V] = p1[V]; //+ dp[V] * fraction;
//} else {
p[U] = p1[U] + dp[U] * fraction;
p[V] = p1[V] + dp[V] * fraction;
//}
if (FRY) System.out.println("inc y p[U] p[V] = " + p[U] + " " + p[V]);
}
}
private void incrementalize_x(float p1[], float p2[],
float p[], float dp[], int x) {
float delta = p2[X] - p1[X];
if (delta == 0) delta = 1;
float fraction = x + 0.5f - p1[X];
if (smooth) {
delta /= SUBXRES;
fraction /= SUBXRES;
}
if (interpX) {
dp[X] = (p2[X] - p1[X]) / delta;
p[X] = p1[X] + dp[X] * fraction;
}
if (interpZ) {
dp[Z] = (p2[Z] - p1[Z]) / delta;
p[Z] = p1[Z] + dp[Z] * fraction;
}
if (interpARGB) {
dp[R] = (p2[R] - p1[R]) / delta;
dp[G] = (p2[G] - p1[G]) / delta;
dp[B] = (p2[B] - p1[B]) / delta;
dp[A] = (p2[A] - p1[A]) / delta;
p[R] = p1[R] + dp[R] * fraction;
p[G] = p1[G] + dp[G] * fraction;
p[B] = p1[B] + dp[B] * fraction;
p[A] = p1[A] + dp[A] * fraction;
}
if (interpUV) {
if (FRY) System.out.println("delta, frac = " + delta + ", " + fraction);
dp[U] = (p2[U] - p1[U]) / delta;
dp[V] = (p2[V] - p1[V]) / delta;
//if (smooth) {
//p[U] = p1[U];
// offset for the damage that will be done by the
// 8 consecutive calls to scanline
// agh.. this won't work b/c not always 8 calls before render
// maybe lastModY - firstModY + 1 instead?
if (FRY) System.out.println("before inc x p[V] = " + p[V] + " " + p1[V] + " " + p2[V]);
//p[V] = p1[V] - SUBXRES1 * fraction;
//} else {
p[U] = p1[U] + dp[U] * fraction;
p[V] = p1[V] + dp[V] * fraction;
//}
}
}
private void increment(float p[], float dp[]) {
if (interpX) p[X] += dp[X];
if (interpZ) p[Z] += dp[Z];
if (interpARGB) {
p[R] += dp[R];
p[G] += dp[G];
p[B] += dp[B];
p[A] += dp[A];
}
if (interpUV) {
if (FRY) System.out.println("increment() " + p[V] + " " + dp[V]);
p[U] += dp[U];
p[V] += dp[V];
}
}
}

289
core/PShape.java Normal file
View File

@ -0,0 +1,289 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2006 Ben Fry and Casey Reas
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
*/
package processing.core;
// take a look at the obj loader to see how this fits with things
// PShape.line() PShape.ellipse()?
// PShape s = beginShape()
// line()
// endShape(s)
public class PShape {
int kind;
PMatrix matrix;
int[] opcode;
int opcodeCount;
// need to reorder vertex fields to make a VERTEX_SHORT_COUNT
// that puts all the non-rendering fields into later indices
float[][] data; // second param is the VERTEX_FIELD_COUNT
// should this be called vertices (consistent with PGraphics internals)
// or does that hurt flexibility?
int childCount;
PShape[] children;
// POINTS, LINES, xLINE_STRIP, xLINE_LOOP
// TRIANGLES, TRIANGLE_STRIP, TRIANGLE_FAN
// QUADS, QUAD_STRIP
// xPOLYGON
static final int PATH = 1; // POLYGON, LINE_LOOP, LINE_STRIP
static final int GROUP = 2;
// how to handle rectmode/ellipsemode?
// are they bitshifted into the constant?
// CORNER, CORNERS, CENTER, (CENTER_RADIUS?)
static final int RECT = 3; // could just be QUAD, but would be x1/y1/x2/y2
static final int ELLIPSE = 4;
static final int VERTEX = 7;
static final int CURVE = 5;
static final int BEZIER = 6;
// fill and stroke functions will need a pointer to the parent
// PGraphics object.. may need some kind of createShape() fxn
// or maybe the values are stored until draw() is called?
// attaching images is very tricky.. it's a different type of data
// material parameters will be thrown out,
// except those currently supported (kinds of lights)
// setAxis -> .x and .y to move x and y coords of origin
public float x;
public float y;
// pivot point for transformations
public float px;
public float py;
public PShape() {
}
public PShape(float x, float y) {
this.x = x;
this.y = y;
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
/**
* Called by the following (the shape() command adds the g)
* PShape s = loadShapes("blah.svg");
* shape(s);
*/
public void draw(PGraphics g) {
boolean flat = g instanceof PGraphics3D;
if (matrix != null) {
g.pushMatrix();
if (flat) {
g.applyMatrix(matrix.m00, matrix.m01, matrix.m02,
matrix.m10, matrix.m11, matrix.m12);
} else {
g.applyMatrix(matrix.m00, matrix.m01, matrix.m02, matrix.m03,
matrix.m10, matrix.m11, matrix.m12, matrix.m13,
matrix.m20, matrix.m21, matrix.m22, matrix.m23,
matrix.m30, matrix.m31, matrix.m32, matrix.m33);
}
}
// if g subclasses PGraphics2, ignore all lighting stuff and z coords
// otherwise if PGraphics3, need to call diffuse() etc
// unfortunately, also a problem with no way to encode stroke/fill
// being enabled/disabled.. this quickly gets into just having opcodes
// for the entire api, to deal with things like textures and images
switch (kind) {
case PATH:
for (int i = 0; i < opcodeCount; i++) {
switch (opcode[i]) {
case VERTEX:
break;
}
}
break;
case GROUP:
break;
case RECT:
break;
}
if (matrix != null) {
g.popMatrix();
}
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
// can't be 'add' because that suggests additive geometry
public void addChild(PShape who) {
}
public PShape createGroup() {
PShape group = new PShape();
group.kind = GROUP;
addChild(group);
return group;
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
// translate, rotate, scale, apply (no push/pop)
// these each call matrix.translate, etc
// if matrix is null when one is called,
// it is created and set to identity
public void translate(float tx, float ty) {
translate(tx, ty, 0);
}
public void translate(float tx, float ty, float tz) {
checkMatrix();
matrix.translate(tx, ty, 0);
}
//
public void rotateX(float angle) {
rotate(angle, 1, 0, 0);
}
public void rotateY(float angle) {
rotate(angle, 0, 1, 0);
}
public void rotateZ(float angle) {
rotate(angle, 0, 0, 1);
}
public void rotate(float angle) {
rotateZ(angle);
}
public void rotate(float angle, float v0, float v1, float v2) {
checkMatrix();
matrix.rotate(angle, v0, v1, v2);
}
//
public void scale(float s) {
scale(s, s, s);
}
public void scale(float sx, float sy) {
scale(sx, sy, 1);
}
public void scale(float x, float y, float z) {
checkMatrix();
matrix.scale(x, y, z);
}
//
public void applyMatrix(float n00, float n01, float n02,
float n10, float n11, float n12) {
checkMatrix();
matrix.apply(n00, n01, n02, 0,
n10, n11, n12, 0,
0, 0, 1, 0,
0, 0, 0, 1);
}
public void applyMatrix(float n00, float n01, float n02, float n03,
float n10, float n11, float n12, float n13,
float n20, float n21, float n22, float n23,
float n30, float n31, float n32, float n33) {
checkMatrix();
matrix.apply(n00, n01, n02, n03,
n10, n11, n12, n13,
n20, n21, n22, n23,
n30, n31, n32, n33);
}
//
protected void checkMatrix() {
if (matrix == null) {
matrix = new PMatrix();
}
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
/**
* Center the shape based on its bounding box. Can't assume
* that the bounding box is 0, 0, width, height. Common case will be
* opening a letter size document in Illustrator, and drawing something
* in the middle, then reading it in as an svg file.
* This will also need to flip the y axis (scale(1, -1)) in cases
* like Adobe Illustrator where the coordinates start at the bottom.
*/
public void center() {
}
/**
* Set the pivot point for all transformations.
*/
public void pivot(float x, float y) {
px = x;
py = y;
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
}

3827
core/PTriangle.java Normal file

File diff suppressed because it is too large Load Diff