Search in sources :

Example 6 with Sketch

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;
}
Also used : Sketch(processing.app.Sketch)

Example 7 with Sketch

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;
}
Also used : SketchCode(processing.app.SketchCode) Sketch(processing.app.Sketch)

Example 8 with Sketch

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);
    }
}
Also used : EventQueue(java.awt.EventQueue) Arrays(java.util.Arrays) Messages(processing.app.Messages) Sketch(processing.app.Sketch) WindowFocusListener(java.awt.event.WindowFocusListener) JOptionPane(javax.swing.JOptionPane) Collectors(java.util.stream.Collectors) WindowEvent(java.awt.event.WindowEvent) InvocationTargetException(java.lang.reflect.InvocationTargetException) ArrayList(java.util.ArrayList) List(java.util.List) Stream(java.util.stream.Stream) ForkJoinPool(java.util.concurrent.ForkJoinPool) Map(java.util.Map) Optional(java.util.Optional) Preferences(processing.app.Preferences) Collections(java.util.Collections) SketchCode(processing.app.SketchCode) SketchCode(processing.app.SketchCode) ArrayList(java.util.ArrayList) InvocationTargetException(java.lang.reflect.InvocationTargetException) InvocationTargetException(java.lang.reflect.InvocationTargetException) ArrayList(java.util.ArrayList) List(java.util.List)

Example 9 with Sketch

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);
}
Also used : SketchCode(processing.app.SketchCode) GeneralPath(java.awt.geom.GeneralPath) Sketch(processing.app.Sketch)

Example 10 with Sketch

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;
        }
    }
}
Also used : SketchCode(processing.app.SketchCode) Sketch(processing.app.Sketch) Problem(processing.app.Problem)

Aggregations

Sketch (processing.app.Sketch)11 SketchCode (processing.app.SketchCode)7 ArrayList (java.util.ArrayList)2 Arrays (java.util.Arrays)2 Collections (java.util.Collections)2 List (java.util.List)2 Map (java.util.Map)2 Collectors (java.util.stream.Collectors)2 BadLocationException (javax.swing.text.BadLocationException)2 Messages (processing.app.Messages)2 ClassPathFactory (com.google.classpath.ClassPathFactory)1 EventQueue (java.awt.EventQueue)1 Point (java.awt.Point)1 WindowEvent (java.awt.event.WindowEvent)1 WindowFocusListener (java.awt.event.WindowFocusListener)1 GeneralPath (java.awt.geom.GeneralPath)1 java.awt.print (java.awt.print)1 File (java.io.File)1 InvocationTargetException (java.lang.reflect.InvocationTargetException)1 MalformedURLException (java.net.MalformedURLException)1