use of processing.app.Sketch in project processing by processing.
the class JavaInputHandler method handlePressed.
/**
* Intercepts key pressed events for JEditTextArea.
* <p/>
* Called by JEditTextArea inside processKeyEvent(). Note that this
* won't intercept actual characters, because those are fired on
* keyTyped().
* @return true if the event has been handled (to remove it from the queue)
*/
public boolean handlePressed(KeyEvent event) {
char c = event.getKeyChar();
int code = event.getKeyCode();
Sketch sketch = editor.getSketch();
JEditTextArea textarea = editor.getTextArea();
if ((event.getModifiers() & InputEvent.META_MASK) != 0) {
//event.consume(); // does nothing
return false;
}
if ((code == KeyEvent.VK_BACK_SPACE) || (code == KeyEvent.VK_TAB) || (code == KeyEvent.VK_ENTER) || ((c >= 32) && (c < 128))) {
sketch.setModified(true);
}
if ((code == KeyEvent.VK_UP) && ((event.getModifiers() & InputEvent.CTRL_MASK) != 0)) {
// back up to the last empty line
char[] contents = textarea.getText().toCharArray();
//int origIndex = textarea.getCaretPosition() - 1;
int caretIndex = textarea.getCaretPosition();
int index = calcLineStart(caretIndex - 1, contents);
//System.out.println("line start " + (int) contents[index]);
// step over the newline
index -= 2;
//System.out.println((int) contents[index]);
boolean onlySpaces = true;
while (index > 0) {
if (contents[index] == 10) {
if (onlySpaces) {
index++;
break;
} else {
// reset
onlySpaces = true;
}
} else if (contents[index] != ' ') {
onlySpaces = false;
}
index--;
}
// if the first char, index will be -2
if (index < 0)
index = 0;
if ((event.getModifiers() & InputEvent.SHIFT_MASK) != 0) {
textarea.setSelectionStart(caretIndex);
textarea.setSelectionEnd(index);
} else {
textarea.setCaretPosition(index);
}
event.consume();
// return true;
} else if ((code == KeyEvent.VK_DOWN) && ((event.getModifiers() & InputEvent.CTRL_MASK) != 0)) {
char[] contents = textarea.getText().toCharArray();
int caretIndex = textarea.getCaretPosition();
int index = caretIndex;
int lineStart = 0;
// don't count this line
boolean onlySpaces = false;
while (index < contents.length) {
if (contents[index] == 10) {
if (onlySpaces) {
// this is it
index = lineStart;
break;
} else {
lineStart = index + 1;
// reset
onlySpaces = true;
}
} else if (contents[index] != ' ') {
onlySpaces = false;
}
index++;
}
if ((event.getModifiers() & InputEvent.SHIFT_MASK) != 0) {
textarea.setSelectionStart(caretIndex);
textarea.setSelectionEnd(index);
} else {
textarea.setCaretPosition(index);
}
event.consume();
// return true;
} else if (c == 9) {
if ((event.getModifiers() & InputEvent.SHIFT_MASK) != 0) {
// if shift is down, the user always expects an outdent
// http://code.google.com/p/processing/issues/detail?id=458
editor.handleOutdent();
} else if (textarea.isSelectionActive()) {
editor.handleIndent();
} else if (Preferences.getBoolean("editor.tabs.expand")) {
int tabSize = Preferences.getInteger("editor.tabs.size");
textarea.setSelectedText(spaces(tabSize));
event.consume();
} else {
// !Preferences.getBoolean("editor.tabs.expand")
textarea.setSelectedText("\t");
event.consume();
}
} else if (code == 10 || code == 13) {
// auto-indent
if (Preferences.getBoolean("editor.indent")) {
char[] contents = textarea.getText().toCharArray();
int tabSize = Preferences.getInteger("editor.tabs.size");
// this is the previous character
// (i.e. when you hit return, it'll be the last character
// just before where the newline will be inserted)
int origIndex = textarea.getCaretPosition() - 1;
// 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);
// 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;
}
}
// now before inserting this many spaces, walk forward from
// 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) && (contents[index] == ' ')) {
//spaceCount--;
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 0099, was ignoring the case, but this is
// annoying, so in 0122 we're trying to fix that.
spaceCount -= extraCount;
if (spaceCount < 0) {
// for rev 0122, actually delete extra space
//textarea.setSelectionStart(origIndex + 1);
textarea.setSelectionEnd(textarea.getSelectionStop() - spaceCount);
textarea.setSelectedText("\n");
textarea.setCaretPosition(textarea.getCaretPosition() + extraCount + spaceCount);
} else {
String insertion = "\n" + spaces(spaceCount);
textarea.setSelectedText(insertion);
textarea.setCaretPosition(textarea.getCaretPosition() + extraCount);
}
// not gonna bother handling more than one brace
if (braceCount > 0) {
int sel = textarea.getSelectionStart();
// http://dev.processing.org/bugs/show_bug.cgi?id=484
if (sel - tabSize >= 0) {
textarea.select(sel - tabSize, sel);
String s = spaces(tabSize);
// if these are spaces that we can delete
if (textarea.getSelectedText().equals(s)) {
textarea.setSelectedText("");
} else {
textarea.select(sel, sel);
}
}
}
} else {
// Enter/Return was being consumed by somehow even if false
// was returned, so this is a band-aid to simply fire the event again.
// http://dev.processing.org/bugs/show_bug.cgi?id=1073
textarea.setSelectedText(String.valueOf(c));
}
// mark this event as already handled (all but ignored)
event.consume();
// return true;
} else if (c == '}') {
if (Preferences.getBoolean("editor.indent")) {
// spaces for the auto-indent
if (textarea.getSelectionStart() != textarea.getSelectionStop()) {
textarea.setSelectedText("");
}
// if this brace is the only thing on the line, outdent
char[] contents = textarea.getText().toCharArray();
// index to the character to the left of the caret
int prevCharIndex = textarea.getCaretPosition() - 1;
// backup from the current caret position to the last newline,
// checking for anything besides whitespace along the way.
// if there's something besides whitespace, exit without
// messing any sort of indenting.
int index = prevCharIndex;
boolean finished = false;
while ((index != -1) && (!finished)) {
if (contents[index] == 10) {
finished = true;
index++;
} else if (contents[index] != ' ') {
// don't do anything, this line has other stuff on it
return false;
} else {
index--;
}
}
// brace with no start
if (!finished)
return false;
int lineStartIndex = index;
//, 1);
int pairedSpaceCount = calcBraceIndent(prevCharIndex, contents);
if (pairedSpaceCount == -1)
return false;
textarea.setSelectionStart(lineStartIndex);
textarea.setSelectedText(spaces(pairedSpaceCount));
// mark this event as already handled
event.consume();
return true;
}
}
return false;
}
use of processing.app.Sketch in project processing by processing.
the class Debugger method javaToSketchLine.
/**
* Translate a line (index) from java space to sketch space.
* @param javaLine the java line id
* @return the corresponding sketch line id or null if failed to translate
*/
public LineID javaToSketchLine(LineID javaLine) {
Sketch sketch = editor.getSketch();
// it may belong to a pure java file created in the sketch
// try to find an exact filename match and check the extension
SketchCode tab = editor.getTab(javaLine.fileName());
if (tab != null && tab.isExtension("java")) {
// can translate 1:1
return originalToRuntimeLine(javaLine);
}
// java file name needs to match the sketches filename
if (!javaLine.fileName().equals(sketch.getName() + ".java")) {
return null;
}
// get the last tab that has an offset not greater than the java line number
for (int i = sketch.getCodeCount() - 1; i >= 0; i--) {
tab = sketch.getCode(i);
// the tab's offset must not be greater than the java line number
if (tab.isExtension("pde") && tab.getPreprocOffset() <= javaLine.lineIdx()) {
final int index = javaLine.lineIdx() - tab.getPreprocOffset();
return originalToRuntimeLine(new LineID(tab.getFileName(), index));
}
}
return null;
}
use of processing.app.Sketch in project processing by processing.
the class ChangeDetector method checkFiles.
// Synchronize, we are running async and touching fields
private synchronized void checkFiles() {
List<String> filenames = new ArrayList<>();
sketch.getSketchCodeFiles(filenames, null);
SketchCode[] codes = sketch.getCode();
// Separate codes with and without files
Map<Boolean, List<SketchCode>> existsMap = Arrays.stream(codes).collect(Collectors.groupingBy(code -> filenames.contains(code.getFileName())));
// ADDED FILES
List<String> codeFilenames = Arrays.stream(codes).map(SketchCode::getFileName).collect(Collectors.toList());
// Get filenames which are in filesystem but don't have code
List<String> addedFilenames = filenames.stream().filter(f -> !codeFilenames.contains(f)).collect(Collectors.toList());
// Show prompt if there are any added files which were not previously ignored
boolean added = addedFilenames.stream().anyMatch(f -> !ignoredAdditions.contains(f));
// REMOVED FILES
// Get codes which don't have file
List<SketchCode> removedCodes = Optional.ofNullable(existsMap.get(Boolean.FALSE)).orElse(Collections.emptyList());
// Show prompt if there are any removed codes which were not previously ignored
boolean removed = removedCodes.stream().anyMatch(code -> !ignoredRemovals.contains(code));
/// MODIFIED FILES
// Get codes which have file with different modification time
List<SketchCode> modifiedCodes = Optional.ofNullable(existsMap.get(Boolean.TRUE)).orElse(Collections.emptyList()).stream().filter(code -> {
long fileLastModified = code.getFile().lastModified();
long codeLastModified = code.getLastModified();
long diff = fileLastModified - codeLastModified;
return fileLastModified == 0L || diff > MODIFICATION_WINDOW_MILLIS;
}).collect(Collectors.toList());
// Show prompt if any open codes were modified
boolean modified = !modifiedCodes.isEmpty();
boolean ask = added || removed || modified;
if (DEBUG) {
System.out.println("ask: " + ask + "\n" + "added filenames: " + addedFilenames + ",\n" + "ignored added: " + ignoredAdditions + ",\n" + "removed codes: " + removedCodes + ",\n" + "ignored removed: " + ignoredRemovals + ",\n" + "modified codes: " + modifiedCodes);
}
// dismissing the prompt and we get another prompt before we even finished.
try {
// Wait for EDT to finish its business
// We need to stay in synchronized scope because of ignore lists
EventQueue.invokeAndWait(() -> {
// Show prompt if something interesting happened
if (ask && showReloadPrompt()) {
// She said yes!!!
if (sketch.getMainFile().exists()) {
sketch.reload();
editor.rebuildHeader();
} else {
// Mark everything as modified so that it saves properly
for (SketchCode code : codes) {
code.setModified(true);
}
try {
sketch.save();
} catch (Exception e) {
//if that didn't work, tell them it's un-recoverable
Messages.showError("Reload Failed", "The main file for this sketch was deleted\n" + "and could not be rewritten.", e);
}
}
// Sketch was reloaded, clear ignore lists
ignoredAdditions.clear();
ignoredRemovals.clear();
return;
}
// Update ignore lists to get rid of old stuff
ignoredAdditions = addedFilenames;
ignoredRemovals = removedCodes;
// If something changed, set modified flags and modification times
if (!removedCodes.isEmpty() || !modifiedCodes.isEmpty()) {
Stream.concat(removedCodes.stream(), modifiedCodes.stream()).forEach(code -> {
code.setModified(true);
code.setLastModified();
});
// Not sure if this is needed
editor.rebuildHeader();
}
});
} catch (InterruptedException ignore) {
} catch (InvocationTargetException e) {
Messages.loge("exception in ChangeDetector", e);
}
}
use of processing.app.Sketch in project processing by processing.
the class EditorHeader method paintComponent.
public void paintComponent(Graphics screen) {
if (screen == null)
return;
Sketch sketch = editor.getSketch();
// possible?
if (sketch == null)
return;
Dimension size = getSize();
if ((size.width != sizeW) || (size.height != sizeH)) {
if ((size.width > imageW) || (size.height > imageH)) {
// nix the image and recreate, it's too small
offscreen = null;
} else {
// if the image is larger than necessary, no need to change
sizeW = size.width;
sizeH = size.height;
}
}
if (offscreen == null) {
sizeW = size.width;
sizeH = size.height;
imageW = sizeW;
imageH = sizeH;
offscreen = Toolkit.offscreenGraphics(this, imageW, imageH);
}
Graphics g = offscreen.getGraphics();
// need to set this each time through
g.setFont(font);
if (fontAscent == 0) {
fontAscent = (int) Toolkit.getAscent(g);
}
Graphics2D g2 = Toolkit.prepareGraphics(g);
// Toolkit.dpiStroke(g2);
g.drawImage(gradient, 0, 0, imageW, imageH, this);
if (tabs.length != sketch.getCodeCount()) {
tabs = new Tab[sketch.getCodeCount()];
for (int i = 0; i < tabs.length; i++) {
tabs[i] = new Tab(i);
}
visitOrder = new Tab[sketch.getCodeCount() - 1];
}
int leftover = TAB_BETWEEN + ARROW_TAB_WIDTH;
int tabMax = getWidth() - leftover;
// reset all tab positions
for (Tab tab : tabs) {
SketchCode code = sketch.getCode(tab.index);
tab.textVisible = true;
tab.lastVisited = code.lastVisited();
// hide extensions for .pde files
boolean hide = editor.getMode().hideExtension(code.getExtension());
tab.text = hide ? code.getPrettyName() : code.getFileName();
// if modified, add the li'l glyph next to the name
// if (code.isModified()) {
// tab.text += " ยง";
// }
tab.textWidth = (int) font.getStringBounds(tab.text, g2.getFontRenderContext()).getWidth();
}
// try to make everything fit
if (!placeTabs(Editor.LEFT_GUTTER, tabMax, null)) {
// always show the tab with the sketch's name
int index = 0;
// stock the array backwards so the rightmost tabs are closed by default
for (int i = tabs.length - 1; i > 0; --i) {
visitOrder[index++] = tabs[i];
}
// sort on when visited
Arrays.sort(visitOrder);
// Keep shrinking the tabs one-by-one until things fit properly
for (int i = 0; i < visitOrder.length; i++) {
tabs[visitOrder[i].index].textVisible = false;
if (placeTabs(Editor.LEFT_GUTTER, tabMax, null)) {
break;
}
}
}
// now actually draw the tabs
if (!placeTabs(Editor.LEFT_GUTTER, tabMax - ARROW_TAB_WIDTH, g2)) {
// draw the dropdown menu target at the right of the window
menuRight = tabMax;
menuLeft = menuRight - ARROW_TAB_WIDTH;
} else {
// draw the dropdown menu target next to the tabs
menuLeft = tabs[tabs.length - 1].right + TAB_BETWEEN;
menuRight = menuLeft + ARROW_TAB_WIDTH;
}
// draw the two pixel line that extends left/right below the tabs
g.setColor(tabColor[SELECTED]);
// can't be done with lines, b/c retina leaves tiny hairlines
g.fillRect(Editor.LEFT_GUTTER, TAB_BOTTOM, editor.getTextArea().getWidth() - Editor.LEFT_GUTTER, Toolkit.zoom(2));
// draw the tab for the menu
g.setColor(tabColor[UNSELECTED]);
drawTab(g, menuLeft, menuRight, false, true);
// draw the arrow on the menu tab
g.setColor(arrowColor);
GeneralPath trianglePath = new GeneralPath();
float x1 = menuLeft + (ARROW_TAB_WIDTH - ARROW_WIDTH) / 2f;
float x2 = menuLeft + (ARROW_TAB_WIDTH + ARROW_WIDTH) / 2f;
trianglePath.moveTo(x1, ARROW_TOP);
trianglePath.lineTo(x2, ARROW_TOP);
trianglePath.lineTo((x1 + x2) / 2, ARROW_BOTTOM);
trianglePath.closePath();
g2.fill(trianglePath);
screen.drawImage(offscreen, 0, 0, imageW, imageH, null);
}
use of processing.app.Sketch in project processing by processing.
the class MarkerColumn method recalculateMarkerPositions.
private void recalculateMarkerPositions() {
if (errorPoints != null && errorPoints.size() > 0) {
Sketch sketch = editor.getSketch();
SketchCode code = sketch.getCurrentCode();
int currentTab = sketch.getCurrentCodeIndex();
// do not divide by zero
int totalLines = PApplet.max(1, code.getLineCount());
int visibleLines = editor.getTextArea().getVisibleLines();
totalLines = PApplet.max(totalLines, visibleLines);
// top scroll button
int topMargin = 20;
// bottom scroll button and horizontal scrollbar
int bottomMargin = 40;
int height = getHeight() - topMargin - bottomMargin;
for (LineMarker m : errorPoints) {
Problem problem = m.problem;
if (problem.getTabIndex() != currentTab)
continue;
// Ratio of error line to total lines
float ratio = (problem.getLineNumber() + 1) / ((float) totalLines);
// Ratio multiplied by height of the error bar
float y = topMargin + ratio * height;
m.y = (int) y;
}
}
}
Aggregations