mirror of
https://github.com/esp8266/Arduino.git
synced 2025-06-19 09:42:11 +03:00
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:
533
app/Base.java
533
app/Base.java
@ -42,6 +42,7 @@ import javax.swing.undo.*;
|
||||
import com.apple.mrj.*;
|
||||
import com.ice.jni.registry.*;
|
||||
|
||||
import processing.core.*;
|
||||
|
||||
|
||||
/**
|
||||
@ -52,22 +53,9 @@ 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,
|
||||
* or via the MRJ open document handler.
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
413
app/Editor.java
413
app/Editor.java
@ -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);
|
||||
|
||||
@ -2022,12 +2126,56 @@ public class Editor extends JFrame
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
257
app/Sketch.java
257
app/Sketch.java
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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++) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 if (paren != 0) {
|
||||
// warn user if there are too many parens in either direction
|
||||
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("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);
|
||||
|
||||
// warn user if there are too many parens in either direction
|
||||
if (paren != 0) {
|
||||
editor.error("Warning: Too many " +
|
||||
((paren < 0) ? "right" : "left") +
|
||||
" parentheses.");
|
||||
|
||||
} else if (c_level != 0) { // check braces only if parens are ok
|
||||
editor.error("Warning: Too many " +
|
||||
((c_level < 0) ? "right" : "left") +
|
||||
" curly braces.");
|
||||
} else {
|
||||
// mark as finished
|
||||
editor.message("Auto Format finished.");
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
editor.error(e);
|
||||
|
313
app/tools/DiscourseFormat.java
Normal file
313
app/tools/DiscourseFormat.java
Normal 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<6E>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;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
@ -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;
|
||||
|
@ -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
BIN
build/macosx/dist/libquaqua.jnilib
vendored
Executable file
Binary file not shown.
BIN
build/macosx/dist/quaqua.jar
vendored
Executable file
BIN
build/macosx/dist/quaqua.jar
vendored
Executable file
Binary file not shown.
@ -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);
|
||||
}
|
||||
}
|
||||
|
BIN
build/windows/dist/avr_tools.zip
vendored
BIN
build/windows/dist/avr_tools.zip
vendored
Binary file not shown.
@ -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
8334
core/PApplet.java
Normal file
File diff suppressed because it is too large
Load Diff
322
core/PConstants.java
Normal file
322
core/PConstants.java
Normal 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
1019
core/PFont.java
Normal file
File diff suppressed because it is too large
Load Diff
4308
core/PGraphics.java
Normal file
4308
core/PGraphics.java
Normal file
File diff suppressed because it is too large
Load Diff
1672
core/PGraphics2D.java
Normal file
1672
core/PGraphics2D.java
Normal file
File diff suppressed because it is too large
Load Diff
3943
core/PGraphics3D.java
Normal file
3943
core/PGraphics3D.java
Normal file
File diff suppressed because it is too large
Load Diff
1381
core/PGraphicsJava2D.java
Normal file
1381
core/PGraphicsJava2D.java
Normal file
File diff suppressed because it is too large
Load Diff
2598
core/PImage.java
Normal file
2598
core/PImage.java
Normal file
File diff suppressed because it is too large
Load Diff
1295
core/PLine.java
Normal file
1295
core/PLine.java
Normal file
File diff suppressed because it is too large
Load Diff
640
core/PMatrix.java
Normal file
640
core/PMatrix.java
Normal 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
772
core/PPolygon.java
Normal 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
289
core/PShape.java
Normal 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
3827
core/PTriangle.java
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user