From 1a4c0feaaf0997bd3a01b0dd3352986b5db75abf Mon Sep 17 00:00:00 2001 From: Gal Sasson Date: Tue, 24 Jun 2014 00:19:54 -0400 Subject: [PATCH] integrate tweak-mode into experimental mode in this commit tweakmode is working inside experimental mode and is activated by default when running a sketch. --- .../galsasson/mode/tweak/ColorControlBox.java | 111 ++-- .../galsasson/mode/tweak/ColorSelector.java | 100 ++-- pdex/src/galsasson/mode/tweak/Handle.java | 87 +-- .../galsasson/mode/tweak/SketchParser.java | 155 +++--- .../mode/experimental/DebugEditor.java | 511 +++++++++++++++--- .../mode/experimental/ExperimentalMode.java | 157 +++++- .../mode/experimental/TextArea.java | 181 +++++-- .../mode/experimental/TextAreaPainter.java | 382 ++++++++++++- 8 files changed, 1314 insertions(+), 370 deletions(-) diff --git a/pdex/src/galsasson/mode/tweak/ColorControlBox.java b/pdex/src/galsasson/mode/tweak/ColorControlBox.java index c1cd5d454..34eac43a6 100644 --- a/pdex/src/galsasson/mode/tweak/ColorControlBox.java +++ b/pdex/src/galsasson/mode/tweak/ColorControlBox.java @@ -6,61 +6,64 @@ import java.awt.Graphics2D; import java.awt.geom.AffineTransform; import java.util.ArrayList; +import processing.mode.experimental.TextAreaPainter; + public class ColorControlBox { - + + public boolean visible; + ArrayList handles; ColorMode colorMode; Color color; boolean ilegalColor = false; boolean isBW; boolean isHex; - + String drawContext; - + // interface int x, y, width, height; - TweakTextAreaPainter painter; - boolean visible; - + TextAreaPainter painter; + public ColorControlBox(String context, ColorMode mode, ArrayList handles) { this.drawContext = context; this.colorMode = mode; this.handles = handles; - + // add this box to the handles so they can update this color on change for (Handle h : handles) { h.setColorBox(this); } - + isBW = isGrayScale(); isHex = isHexColor(); color = getCurrentColor(); - + visible = Settings.alwaysShowColorBoxes; } - - public void initInterface(TweakTextAreaPainter painter, int x, int y, int w, int h) + + public void initInterface(TextAreaPainter textAreaPainter, int x, int y, int w, int h) { - this.painter = painter; + this.painter = textAreaPainter; this.x = x; this.y = y; this.width = w; this.height = h; } - + public void setPos(int x, int y) { this.x = x; this.y = y; } - + public void draw(Graphics2D g2d) { if (!visible) { return; } - + AffineTransform trans = g2d.getTransform(); g2d.translate(x, y); @@ -72,16 +75,16 @@ public class ColorControlBox { g2d.setStroke(new BasicStroke(1)); g2d.setColor(Color.BLACK); g2d.drawRoundRect(0, 0, width, height, 5, 5); - + if (ilegalColor) { g2d.setColor(Color.RED); g2d.setStroke(new BasicStroke(2)); g2d.drawLine(width-3, 3, 3, height-3); } - + g2d.setTransform(trans); } - + public boolean isGrayScale() { if (handles.size() <= 2) { @@ -90,10 +93,10 @@ public class ColorControlBox { return true; } } - + return false; } - + /** * Check if color is hex or webcolor * @return @@ -107,10 +110,10 @@ public class ColorControlBox { return true; } } - + return false; } - + public Color getCurrentColor() { try { @@ -119,7 +122,7 @@ public class ColorControlBox { if (isBW) { // treat as color(gray) float gray = handles.get(0).newValue.floatValue(); - return verifiedGrayColor(gray); + return verifiedGrayColor(gray); } else { // treat as color(argb) @@ -132,13 +135,13 @@ public class ColorControlBox { if (isBW) { // color(gray, alpha) float gray = handles.get(0).newValue.floatValue(); - return verifiedGrayColor(gray); + return verifiedGrayColor(gray); } else { // treat as color(argb, a) int argb = handles.get(0).newValue.intValue(); float a = handles.get(1).newValue.floatValue(); - return verifiedHexColor(argb, a); + return verifiedHexColor(argb, a); } } else if (handles.size() == 3) @@ -173,36 +176,36 @@ public class ColorControlBox { } catch (Exception e) { System.out.println("error parsing color value: " + e.toString()); - ilegalColor = true; + ilegalColor = true; return Color.WHITE; } - + // couldn't figure out this color, return WHITE color ilegalColor = true; return Color.WHITE; } - + private Color verifiedGrayColor(float gray) { if (gray < 0 || gray > colorMode.v1Max) { return colorError(); } - + ilegalColor = false; gray = gray/colorMode.v1Max * 255; return new Color((int)gray, (int)gray, (int)gray, 255); } - + private Color verifiedHexColor(int argb) { int r = (argb>>16)&0xff; int g = (argb>>8)&0xff; int b = (argb&0xff); - + ilegalColor = false; - return new Color(r, g, b, 255); + return new Color(r, g, b, 255); } - + private Color verifiedHexColor(int argb, float alpha) { int r = (argb>>16)&0xff; @@ -212,10 +215,10 @@ public class ColorControlBox { ilegalColor = false; return new Color(r, g, b, 255); } - + public Color verifiedRGBColor(float r, float g, float b, float a) { - if (r < 0 || r > colorMode.v1Max || + if (r < 0 || r > colorMode.v1Max || g < 0 || g > colorMode.v2Max || b < 0 || b > colorMode.v3Max) { return colorError(); @@ -230,7 +233,7 @@ public class ColorControlBox { public Color verifiedHSBColor(float h, float s, float b, float a) { - if (h < 0 || h > colorMode.v1Max || + if (h < 0 || h > colorMode.v1Max || s < 0 || s > colorMode.v2Max || b < 0 || b > colorMode.v3Max) { return colorError(); @@ -240,7 +243,7 @@ public class ColorControlBox { Color c = Color.getHSBColor(h/colorMode.v1Max, s/colorMode.v2Max, b/colorMode.v3Max); return new Color(c.getRed(), c.getGreen(), c.getBlue(), 255); } - + private Color colorError() { ilegalColor = true; @@ -251,17 +254,17 @@ public class ColorControlBox { { color = getCurrentColor(); } - + public int getTabIndex() { return handles.get(0).tabIndex; } - + public int getLine() { return handles.get(0).line; } - + public int getCharIndex() { int lastHandle = handles.size()-1; @@ -269,29 +272,29 @@ public class ColorControlBox { } /* Check if the point is in the box - * + * */ public boolean pick(int mx, int my) { if (!visible) { return false; } - + if (mx>x && mx < x+width && my>y && myy && my 255 || mouseY < 0 || mouseY > 255) { return; } - + lastX = mouseX; lastY = mouseY; updateColor(); } - + public void mouseDragged() { if (mouseX < 0 || mouseX > 255 || mouseY < 0 || mouseY > 255) { @@ -204,12 +204,12 @@ public class ColorSelector { lastY = mouseY; updateColor(); } - + public void updateColor() { saturation = lastX; brightness = 255 - lastY; - + satBrightChanged(); colorBox.selectorChanged(hue, saturation, brightness); } @@ -231,7 +231,7 @@ public class ColorSelector { { PImage backImg; int lastY; - + public void setup() { size(30, 255); @@ -243,11 +243,11 @@ public class ColorSelector { if (!colorBox.ilegalColor) { setToColor(colorBox.color); } - + // draw the slider background renderBack(); } - + public void draw() { image(backImg, 0, 0); @@ -257,7 +257,7 @@ public class ColorSelector { else { stroke(0); } - + pushMatrix(); translate(0, lastY); // draw left bracket @@ -267,7 +267,7 @@ public class ColorSelector { vertex(1, 2); vertex(5, 2); endShape(); - + // draw middle lines line(13, 0, 17, 0); line(15, -2, 15, 2); @@ -280,7 +280,7 @@ public class ColorSelector { vertex(24, 2); endShape(); popMatrix(); - + if (colorBox.isBW) { stroke(255); rect(0, 0, 29, 254); @@ -291,7 +291,7 @@ public class ColorSelector { line(29, 0, 29, 255); } } - + public void renderBack() { PGraphics buf = createGraphics(30, 255); @@ -313,9 +313,9 @@ public class ColorSelector { backImg = buf.get(); } - + public void setToColor(Color c) - { + { // set slider position if (colorBox.isBW) { hue = c.getRed(); @@ -333,11 +333,11 @@ public class ColorSelector { mouseY < 0 || mouseY > 255) { return; } - + lastY = mouseY; updateColor(); } - + public void mouseDragged() { if (mouseX < 0 || mouseX > 30 || @@ -352,7 +352,7 @@ public class ColorSelector { public void updateColor() { hue = 255 - lastY; - + hueChanged(); colorBox.selectorChanged(hue, saturation, brightness); } @@ -369,30 +369,30 @@ public class ColorSelector { return new Dimension(30, 255); } } - + public class SelectorTopBar extends PApplet { int barWidth; int barHeight; - + public SelectorTopBar(int w) { super(); barWidth = w; barHeight = 16; } - + public void setup() { size(barWidth, barHeight); noLoop(); } - + public void draw() { background(128); } - + public Dimension getPreferredSize() { return new Dimension(barWidth, barHeight); } diff --git a/pdex/src/galsasson/mode/tweak/Handle.java b/pdex/src/galsasson/mode/tweak/Handle.java index ee6f8042e..73731a44d 100644 --- a/pdex/src/galsasson/mode/tweak/Handle.java +++ b/pdex/src/galsasson/mode/tweak/Handle.java @@ -17,18 +17,21 @@ public class Handle { public String strValue; public String strNewValue; public int varIndex; + public int startChar; + public int endChar; + public int newStartChar; + public int newEndChar; + public int line; int tabIndex; - int startChar, endChar, line; - int newStartChar, newEndChar; int decimalPlaces; // number of digits after the decimal point float incValue; - + java.lang.Number value, newValue; String strDiff; - + // connect with color control box ColorControlBox colorBox; - + // interface int x, y, width, height; int xCenter, xCurrent, xLast; @@ -36,7 +39,7 @@ public class Handle { String textFormat; int oscPort; - + public Handle(String t, String n, int vi, String v, int ti, int l, int sc, int ec, int dp) { type = t; @@ -48,7 +51,7 @@ public class Handle { startChar = sc; endChar = ec; decimalPlaces = dp; - + incValue = (float)(1/Math.pow(10, decimalPlaces)); if (type == "int") { @@ -74,46 +77,46 @@ public class Handle { strNewValue = strValue; textFormat = "%.0" + decimalPlaces + "f"; } - + newStartChar = startChar; newEndChar = endChar; } - + public void initInterface(int x, int y, int width, int height) { this.x = x; this.y = y; this.width = width; this.height = height; - + // create drag ball progBar = new HProgressBar(height, width); } - + public void setCenterX(int mx) { xLast = xCurrent = xCenter = mx; } - + public void setCurrentX(int mx) { xLast = xCurrent; xCurrent = mx; - + progBar.setPos(xCurrent - xCenter); - + updateValue(); } - + public void resetProgress() { progBar.setPos(0); } - + public void updateValue() { float change = getChange(); - + if (type == "int") { if (newValue.intValue() + (int)change > Integer.MAX_VALUE || newValue.intValue() + (int)change < Integer.MIN_VALUE) { @@ -134,7 +137,7 @@ public class Handle { updateColorBox(); } - + public void setValue(Number value) { if (type == "int") { @@ -155,73 +158,73 @@ public class Handle { BigDecimal bd = new BigDecimal(value.floatValue()); bd = bd.setScale(decimalPlaces, BigDecimal.ROUND_HALF_UP); newValue = bd.floatValue(); - strNewValue = String.format(Locale.US,textFormat, newValue.floatValue()); + strNewValue = String.format(Locale.US,textFormat, newValue.floatValue()); } - + // send new data to the server in the sketch oscSendNewValue(); } - + public void updateColorBox() { if (colorBox != null) { colorBox.colorChanged(); - } + } } - + private float getChange() { int pixels = xCurrent - xLast; return (float)pixels*incValue; } - + public void setPos(int nx, int ny) { x = nx; y = ny; } - + public void setWidth(int w) { width = w; - + progBar.setWidth(w); } - + public void draw(Graphics2D g2d, boolean hasFocus) { AffineTransform prevTrans = g2d.getTransform(); g2d.translate(x, y); - + // draw underline on the number g2d.setColor(ColorScheme.getInstance().progressFillColor); g2d.drawLine(0, 0, width, 0); - + if (hasFocus) { if (progBar != null) { g2d.translate(width/2, 2); progBar.draw(g2d); } } - + g2d.setTransform(prevTrans); } - + public boolean pick(int mx, int my) { return pickText(mx, my); } - + public boolean pickText(int mx, int my) { if (mx>x-2 && mxy-height && my { public int compare(Handle handle1, Handle handle2) { diff --git a/pdex/src/galsasson/mode/tweak/SketchParser.java b/pdex/src/galsasson/mode/tweak/SketchParser.java index adcd8cb9a..affa86e97 100644 --- a/pdex/src/galsasson/mode/tweak/SketchParser.java +++ b/pdex/src/galsasson/mode/tweak/SketchParser.java @@ -10,38 +10,39 @@ import java.util.regex.Pattern; import processing.app.Sketch; -public class SketchParser +public class SketchParser { + public ArrayList colorBoxes[]; + public ArrayList allHandles[]; + int intVarCount; int floatVarCount; final String varPrefix = "tweakmode"; - + String[] codeTabs; boolean requiresComment; - ArrayList allHandles[]; ArrayList colorModes; - ArrayList colorBoxes[]; - + ArrayList scientificNotations[]; - + public SketchParser(String[] codeTabs, boolean requiresComment) { this.codeTabs = codeTabs; this.requiresComment = requiresComment; intVarCount=0; floatVarCount=0; - + scientificNotations = getAllScientificNotations(); - + // find, add, and sort all tweakable numbers in the sketch addAllNumbers(); - + // handle colors colorModes = findAllColorModes(); colorBoxes = new ArrayList[codeTabs.length]; createColorBoxes(); createColorBoxesForLights(); - + /* If there is more than one color mode per context, * allow only hex and webcolors in this context. * Currently there is no notion of order of execution so we @@ -49,7 +50,7 @@ public class SketchParser */ handleMultipleColorModes(); } - + public void addAllNumbers() { allHandles = new ArrayList[codeTabs.length]; @@ -58,9 +59,9 @@ public class SketchParser addAllWebColorNumbers(); for (int i=0; i findAllColorModes() { ArrayList modes = new ArrayList(); - + for (String tab : codeTabs) { int index = -1; // search for a call to colorMode function while ((index = tab.indexOf("colorMode", index+1)) > -1) { // found colorMode at index - + if (isInComment(index, tab)) { // ignore comments continue; @@ -292,22 +293,22 @@ public class SketchParser if (parOpen < 0) { continue; } - + int parClose = tab.indexOf(')', parOpen+1); if (parClose < 0) { continue; } - + // add this mode String modeDesc = tab.substring(parOpen+1, parClose); String context = getObject(index-9, tab); modes.add(ColorMode.fromString(context, modeDesc)); } } - + return modes; } - + private void createColorBoxes() { // search tab for the functions: 'color', 'fill', 'stroke', 'background', 'tint' @@ -317,11 +318,11 @@ public class SketchParser colorBoxes[i] = new ArrayList(); String tab = codeTabs[i]; Matcher m = p.matcher(tab); - + while (m.find()) { ArrayList colorHandles = new ArrayList(); - + // look for the '(' and ')' positions int openPar = tab.indexOf("(", m.start()); int closePar = tab.indexOf(")", m.end()); @@ -329,7 +330,7 @@ public class SketchParser // ignore this color continue; } - + if (isInComment(m.start(), tab)) { // ignore colors in a comment continue; @@ -344,7 +345,7 @@ public class SketchParser colorHandles.add(handle); } } - + if (colorHandles.size() > 0) { /* make sure there is no other stuff between '()' like variables. * substract all handle values from string inside parenthesis and @@ -364,16 +365,16 @@ public class SketchParser garbage = true; } } - + // create a new color box if (!garbage) { // find the context of the color (e.g. this.fill() or .fill()) String context = getObject(m.start(), tab); ColorMode cmode = getColorModeForContext(context); - + // not adding color operations for modes we couldn't understand ColorControlBox newCCB = new ColorControlBox(context, cmode, colorHandles); - + if (cmode.unrecognizedMode) { // the color mode is unrecognizable add only if is a hex or webcolor if (newCCB.isHex) { @@ -388,7 +389,7 @@ public class SketchParser } } } - + private void createColorBoxesForLights() { // search code for light color and material color functions. @@ -399,11 +400,11 @@ public class SketchParser { String tab = codeTabs[i]; Matcher m = p.matcher(tab); - + while (m.find()) { ArrayList colorHandles = new ArrayList(); - + // look for the '(' and ')' positions int openPar = tab.indexOf("(", m.start()); int closePar = tab.indexOf(")", m.end()); @@ -411,7 +412,7 @@ public class SketchParser // ignore this color continue; } - + if (isInComment(m.start(), tab)) { // ignore colors in a comment continue; @@ -428,7 +429,7 @@ public class SketchParser break; } } - + for (Handle handle : allHandles[i]) { if (handle.startChar > openPar && @@ -437,7 +438,7 @@ public class SketchParser colorHandles.add(handle); } } - + if (colorHandles.size() > 0) { /* make sure there is no other stuff between '()' like variables. * substract all handle values from string inside parenthesis and @@ -457,16 +458,16 @@ public class SketchParser garbage = true; } } - + // create a new color box if (!garbage) { // find the context of the color (e.g. this.fill() or .fill()) String context = getObject(m.start(), tab); ColorMode cmode = getColorModeForContext(context); - + // not adding color operations for modes we couldn't understand ColorControlBox newCCB = new ColorControlBox(context, cmode, colorHandles); - + if (cmode.unrecognizedMode) { // the color mode is unrecognizable add only if is a hex or webcolor if (newCCB.isHex) { @@ -489,11 +490,11 @@ public class SketchParser return cm; } } - + // if non found, create the default color mode for this context and return it ColorMode newCM = new ColorMode(context); colorModes.add(newCM); - + return newCM; } @@ -536,11 +537,11 @@ public class SketchParser colorBoxes[i].removeAll(toDelete); } } - + public ArrayList[] getAllScientificNotations() { ArrayList notations[] = new ArrayList[codeTabs.length]; - + Pattern p = Pattern.compile("[+\\-]?(?:0|[1-9]\\d*)(?:\\.\\d*)?[eE][+\\-]?\\d+"); for (int i=0; i:&|^!~ @@ -613,12 +614,12 @@ public class SketchParser return false; } - + private int getNumDigitsAfterPoint(String number) { Pattern p = Pattern.compile("\\.[0-9]+"); Matcher m = p.matcher(number); - + if (m.find()) { return m.end() - m.start() - 1; } @@ -711,7 +712,7 @@ public class SketchParser return false; }; - + private boolean isInComment(int pos, String code) { // look for one line comment @@ -722,17 +723,17 @@ public class SketchParser if (code.substring(lineStart, pos).indexOf("//") != -1) { return true; } - + // TODO: look for block comments - + return false; } - + public static int getEndOfLine(int pos, String code) { return code.indexOf("\n", pos); } - + public static int getStartOfLine(int pos, String code) { while (pos >= 0) { @@ -741,12 +742,12 @@ public class SketchParser } pos--; } - + return 0; } - + /** returns the object of the function starting at 'pos' - * + * * @param pos * @param code * @return @@ -755,7 +756,7 @@ public class SketchParser { boolean readObject = false; String obj = "this"; - + while (pos-- >= 0) { if (code.charAt(pos) == '.') { if (!readObject) { @@ -773,44 +774,44 @@ public class SketchParser obj = code.charAt(pos) + obj; } } - + return obj; } - + public static int getSetupStart(String code) { Pattern p = Pattern.compile("void[\\s\\t\\r\\n]*setup[\\s\\t]*\\(\\)[\\s\\t\\r\\n]*\\{"); Matcher m = p.matcher(code); - + if (m.find()) { return m.end(); } - + return -1; } - + private String replaceString(String str, int start, int end, String put) { return str.substring(0, start) + put + str.substring(end, str.length()); } - + class Range { int start; int end; - + public Range(int s, int e) { start = s; end = e; } - + public boolean contains(int v) { if (v>=start && v * @author Manindra Moharana <me@mkmoharana.com> - * - * + * + * */ public class DebugEditor extends JavaEditor implements ActionListener { // important fields from superclass @@ -131,7 +136,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { protected VariableInspector vi; // the variable inspector frame protected TextArea ta; // the text area - + protected ErrorBar errorBar; /** * Show Console button @@ -153,46 +158,46 @@ public class DebugEditor extends JavaEditor implements ActionListener { * panes */ protected JPanel consoleProblemsPane; - + protected XQErrorTable errorTable; - + /** * Enable/Disable compilation checking */ protected boolean compilationCheckEnabled = true; - + /** * Show warnings menu item */ protected JCheckBoxMenuItem showWarnings; - + /** * Check box menu item for show/hide Problem Window */ public JCheckBoxMenuItem problemWindowMenuCB; - + /** * Enable/Disable debug ouput */ protected JCheckBoxMenuItem debugMessagesEnabled; - + /** * Show outline view */ protected JMenuItem showOutline; - + /** * Enable/Disable error logging */ protected JCheckBoxMenuItem writeErrorLog; - + /** * Enable/Disable code completion */ protected JCheckBoxMenuItem completionsEnabled; - + protected AutoSaveUtil autosaver; - + public DebugEditor(Base base, String path, EditorState state, Mode mode) { super(base, path, state, mode); @@ -207,7 +212,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { // access to customized (i.e. subclassed) text area ta = (TextArea) textarea; - + // Add show usage option JMenuItem showUsageItem = new JMenuItem("Show Usage.."); showUsageItem.addActionListener(new ActionListener() { @@ -216,15 +221,15 @@ public class DebugEditor extends JavaEditor implements ActionListener { } }); ta.getRightClickPopup().add(showUsageItem); - + // add refactor option JMenuItem renameItem = new JMenuItem("Rename.."); renameItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { handleRefactor(); } - }); - + }); + // TODO: Add support for word select on right click and rename. // ta.customPainter.addMouseListener(new MouseAdapter() { // public void mouseClicked(MouseEvent evt) { @@ -253,17 +258,22 @@ public class DebugEditor extends JavaEditor implements ActionListener { dbg.setBreakpoint(lineID); } getSketch().setModified(false); // setting breakpoints will flag sketch as modified, so override this here - + checkForJavaTabs(); initializeErrorChecker(); ta.setECSandThemeforTextArea(errorCheckerService, dmode); - addXQModeUI(); + addXQModeUI(); debugToolbarEnabled = new AtomicBoolean(false); //log("Sketch Path: " + path); + + // TweakMode code + + // random port for OSC (0xff0 - 0xfff0) + oscPort = (int)(Math.random()*0xf000) + 0xff0; } - + private void addXQModeUI(){ - + // Adding ErrorBar JPanel textAndError = new JPanel(); Box box = (Box) textarea.getParent(); @@ -274,7 +284,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { textarea.setBounds(0, 0, errorBar.getX() - 1, textarea.getHeight()); textAndError.add(textarea); box.add(textAndError); - + // Adding Error Table in a scroll pane errorTableScrollPane = new JScrollPane(); errorTable = new XQErrorTable(errorCheckerService); @@ -312,14 +322,14 @@ public class DebugEditor extends JavaEditor implements ActionListener { consoleProblemsPane.add(errorTableScrollPane, XQConsoleToggle.ERRORSLIST); consoleProblemsPane.add(console, XQConsoleToggle.CONSOLE); consolePanel.add(consoleProblemsPane, BorderLayout.CENTER); - + // ensure completion gets hidden on editor losing focus - addWindowFocusListener(new WindowFocusListener() { + addWindowFocusListener(new WindowFocusListener() { public void windowLostFocus(WindowEvent e) { ta.hideSuggestion(); - } + } public void windowGainedFocus(WindowEvent e) { - + } }); } @@ -345,16 +355,16 @@ public class DebugEditor extends JavaEditor implements ActionListener { public void dispose() { //System.out.println("window dispose"); // quit running debug session - dbg.stopDebug(); + dbg.stopDebug(); // remove var.inspector vi.dispose(); errorCheckerService.stopThread(); // original dispose super.dispose(); } - + // Added temporarily to dump error log. TODO: Remove this later - public void internalCloseRunner(){ + public void internalCloseRunner(){ if(ExperimentalMode.errorLogsEnabled) writeErrorsToFile(); // if(autosaver != null && !viewingAutosaveBackup) { // log("stopping autosaver in internalCloseRunner"); @@ -362,7 +372,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { // } super.internalCloseRunner(); } - + /** * Writes all error messages to a csv file. * For analytics purposes only. @@ -437,14 +447,14 @@ public class DebugEditor extends JavaEditor implements ActionListener { }); return buildSketchMenu(new JMenuItem[]{runItem, presentItem, stopItem}); }*/ - + /** * Whether debug toolbar is enabled */ AtomicBoolean debugToolbarEnabled; - + protected EditorToolbar javaToolbar, debugToolbar; - + /** * Toggles between java mode and debug mode toolbar */ @@ -466,16 +476,16 @@ public class DebugEditor extends JavaEditor implements ActionListener { debugToolbarEnabled.set(true); log("Switching to Debugger Toolbar"); } - + SwingUtilities.invokeLater(new Runnable() { public void run() { - Box upper = (Box)splitPane.getComponent(0); + Box upper = (Box)splitPane.getComponent(0); upper.remove(0); upper.add(nextToolbar, 0); upper.validate(); nextToolbar.repaint(); toolbar = nextToolbar; - // The toolbar responds to shift down/up events + // The toolbar responds to shift down/up events // in order to show the alt version of toolbar buttons. // With toolbar switch, KeyListener has to be changed as well for (KeyListener kl : textarea.getKeyListeners()) { @@ -503,7 +513,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { JCheckBoxMenuItem toggleDebugger = new JCheckBoxMenuItem("Show Debug Toolbar"); toggleDebugger.setSelected(false); - toggleDebugger.addActionListener(new ActionListener() { + toggleDebugger.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { switchToolbars(); } @@ -561,9 +571,9 @@ public class DebugEditor extends JavaEditor implements ActionListener { debugMenu.addSeparator(); debugMenu.add(toggleVariableInspectorMenuItem); debugMenu.addSeparator(); - + // XQMode menu items - /* + /* JCheckBoxMenuItem item; item = new JCheckBoxMenuItem("Error Checker Enabled"); item.setSelected(ExperimentalMode.errorCheckEnabled); @@ -609,7 +619,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { } }); debugMenu.add(showWarnings); - + completionsEnabled = new JCheckBoxMenuItem("Code Completion Enabled"); completionsEnabled.setSelected(ExperimentalMode.codeCompletionsEnabled); completionsEnabled.addActionListener(new ActionListener() { @@ -621,7 +631,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { } }); debugMenu.add(completionsEnabled); - + debugMessagesEnabled = new JCheckBoxMenuItem("Show Debug Messages"); debugMessagesEnabled.setSelected(ExperimentalMode.DEBUG); debugMessagesEnabled.addActionListener(new ActionListener() { @@ -632,12 +642,12 @@ public class DebugEditor extends JavaEditor implements ActionListener { dmode.savePreferences(); } }); - debugMenu.add(debugMessagesEnabled); - + debugMenu.add(debugMessagesEnabled); + showOutline = Toolkit.newJMenuItem("Show Outline", KeyEvent.VK_L); showOutline.addActionListener(this); debugMenu.add(showOutline); - + writeErrorLog = new JCheckBoxMenuItem("Write Errors to Log"); writeErrorLog.setSelected(ExperimentalMode.errorLogsEnabled); writeErrorLog.addActionListener(new ActionListener() { @@ -649,7 +659,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { } }); debugMenu.add(writeErrorLog); - + debugMenu.addSeparator(); JMenuItem jitem = new JMenuItem("PDE X on GitHub"); jitem.addActionListener(new ActionListener() { @@ -662,7 +672,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { */ return debugMenu; } - + @Override public JMenu buildModeMenu() { return buildDebugMenu(); @@ -846,10 +856,10 @@ public class DebugEditor extends JavaEditor implements ActionListener { @Override public boolean handleSave(boolean immediately) { //System.out.println("handleSave " + immediately); - + log("handleSave, viewing autosave? " + viewingAutosaveBackup); /* If user wants to save a backup, the backup sketch should get - * copied to the main sketch directory, simply reload the main sketch. + * copied to the main sketch directory, simply reload the main sketch. */ if(viewingAutosaveBackup){ /* @@ -877,7 +887,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { //viewingAutosaveBackup = false; */ } - + // note modified tabs final List modified = new ArrayList(); for (int i = 0; i < getSketch().getCodeCount(); i++) { @@ -938,9 +948,9 @@ public class DebugEditor extends JavaEditor implements ActionListener { // autosaver.reloadAutosaveDir(); return saved; } - + private boolean viewingAutosaveBackup; - + /** * Loads and starts the auto save service * Also handles the case where an auto save backup is found. @@ -948,7 +958,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { */ private void loadAutoSaver(){ log("Load Auto Saver()"); - autosaver = new AutoSaveUtil(this, ExperimentalMode.autoSaveInterval); + autosaver = new AutoSaveUtil(this, ExperimentalMode.autoSaveInterval); if(!autosaver.checkForPastSave()) { autosaver.init(); return; @@ -963,7 +973,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { "was closed unexpectedly last time.", "Select YES to view it or NO to delete the backup."); if(response == JOptionPane.YES_OPTION){ - handleOpenInternal(pastSave.getAbsolutePath()); + handleOpenInternal(pastSave.getAbsolutePath()); // Base.showMessage("Save it..", "Remember to save the backup sketch to a specific location if you want to."); //log(getSketch().getMainFilePath()); log("loadAutoSaver, viewing autosave? " + viewingAutosaveBackup); @@ -1085,7 +1095,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { return ta; } - + /** * Grab current contents of the sketch window, advance the console, stop any * other running sketches, auto-save the user's code... not in that order. @@ -1196,8 +1206,8 @@ public class DebugEditor extends JavaEditor implements ActionListener { statusError(e); } - } - + } + /** * Access variable inspector window. * @@ -1503,7 +1513,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { public void statusHalted() { statusNotice("Debugger halted."); } - + public static final int STATUS_EMPTY = 100, STATUS_COMPILER_ERR = 200, STATUS_WARNING = 300, STATUS_INFO = 400, STATUS_ERR = 500; public int statusMessageType = STATUS_EMPTY; @@ -1523,13 +1533,13 @@ public class DebugEditor extends JavaEditor implements ActionListener { super.statusError(what); break; case STATUS_INFO: - case STATUS_WARNING: - statusNotice(what); + case STATUS_WARNING: + statusNotice(what); break; } // Don't need to clear compiler error messages if(type == STATUS_COMPILER_ERR) return; - + // Clear the message after a delay SwingWorker s = new SwingWorker() { @Override @@ -1545,15 +1555,15 @@ public class DebugEditor extends JavaEditor implements ActionListener { }; s.execute(); } - + public void statusEmpty(){ statusMessage = null; statusMessageType = STATUS_EMPTY; super.statusEmpty(); } - + ErrorCheckerService errorCheckerService; - + /** * Initializes and starts Error Checker Service */ @@ -1575,7 +1585,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { } } - + /** * Updates the error bar * @param problems @@ -1586,7 +1596,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { /** * Toggle between Console and Errors List - * + * * @param buttonName * - Button Label */ @@ -1594,7 +1604,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { CardLayout cl = (CardLayout) consoleProblemsPane.getLayout(); cl.show(consoleProblemsPane, buttonName); } - + /** * Updates the error table * @param tableModel @@ -1603,7 +1613,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { synchronized public boolean updateTable(final TableModel tableModel) { return errorTable.updateTable(tableModel); } - + /** * Handle whether the tiny red error indicator is shown near the error button * at the bottom of the PDE @@ -1612,7 +1622,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { btnShowErrors.updateMarker(ExperimentalMode.errorCheckEnabled && errorCheckerService.hasErrors(), errorBar.errorColor); } - + /** * Handle refactor operation */ @@ -1621,7 +1631,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { log(ta.getLineText(ta.getCaretLine())); errorCheckerService.getASTGenerator().handleRefactor(); } - + /** * Handle show usage operation */ @@ -1630,7 +1640,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { log(ta.getLineText(ta.getCaretLine())); errorCheckerService.getASTGenerator().handleShowUsage(); } - + /** * Checks if the sketch contains java tabs. If it does, XQMode ain't built * for it, yet. Also, user should really start looking at Eclipse. Disable @@ -1649,7 +1659,7 @@ public class DebugEditor extends JavaEditor implements ActionListener { } } } - + protected void applyPreferences() { super.applyPreferences(); if (dmode != null) { @@ -1659,4 +1669,363 @@ public class DebugEditor extends JavaEditor implements ActionListener { errorCheckerService.runManualErrorCheck(); } } + + // TweakMode code + String[] baseCode; + + final static int SPACE_AMOUNT = 0; + + int oscPort; + + public void startInteractiveMode() + { + ta.startInteractiveMode(); + } + + public void stopInteractiveMode(ArrayList handles[]) + { + ta.stopInteractiveMode(); + + // remove space from the code (before and after) + removeSpacesFromCode(); + + // check which tabs were modified + boolean modified = false; + boolean[] modifiedTabs = getModifiedTabs(handles); + for (boolean mod : modifiedTabs) { + if (mod) { + modified = true; + break; + } + } + + if (modified) { + // ask to keep the values + int ret = Base.showYesNoQuestion(this, "Tweak Mode", + "Keep the changes?", + "You changed some values in your sketch. Would you like to keep the changes?"); + if (ret == 1) { + // NO! don't keep changes + loadSavedCode(); + // update the painter to draw the saved (old) code + ta.invalidate(); + } + else { + // YES! keep changes + // the new values are already present, just make sure the user can save the modified tabs + for (int i=0; i handles[], ArrayList colorBoxes[]) + { + // set OSC port of handles + for (int i=0; i handles[]) + { + boolean[] modifiedTabs = new boolean[handles.length]; + + for (int i=0; i handles[], boolean withSpaces) + { + SketchCode[] sketchCode = sketch.getCode(); + for (int tab=0; tab handles[]) + { + SketchCode[] code = sketch.getCode(); + + if (code.length<1) + return false; + + if (handles.length == 0) + return false; + + int setupStartPos = SketchParser.getSetupStart(baseCode[0]); + if (setupStartPos < 0) { + return false; + } + + // Copy current program to interactive program + + /* modify the code below, replace all numbers with their variable names */ + // loop through all tabs in the current sketch + for (int tab=0; tab 0) { + header += "int[] tweakmode_int = new int["+numOfInts+"];\n"; + } + if (numOfFloats > 0) { + header += "float[] tweakmode_float = new float["+numOfFloats+"];\n\n"; + } + + /* add the class for the OSC event handler that will respond to our messages */ + header += "public class TweakMode_OscHandler {\n" + + " public void oscEvent(OscMessage msg) {\n" + + " String type = msg.addrPattern();\n"; + if (numOfInts > 0) { + header += " if (type.contains(\"/tm_change_int\")) {\n" + + " int index = msg.get(0).intValue();\n" + + " int value = msg.get(1).intValue();\n" + + " tweakmode_int[index] = value;\n" + + " }\n"; + if (numOfFloats > 0) { + header += " else "; + } + } + if (numOfFloats > 0) { + header += "if (type.contains(\"/tm_change_float\")) {\n" + + " int index = msg.get(0).intValue();\n" + + " float value = msg.get(1).floatValue();\n" + + " tweakmode_float[index] = value;\n" + + " }\n"; + } + header += " }\n" + + "}\n"; + header += "TweakMode_OscHandler tweakmode_oscHandler = new TweakMode_OscHandler();\n"; + + header += "void tweakmode_initAllVars() {\n"; + for (int i=0; i handles[]) + { + int count = 0; + for (int i=0; i handles[]) + { + int count = 0; + for (int i=0; i Import Library --> Add Library ...\" and choose 'ocsP5'", null); + + return false; + } + + private boolean isSketchModified(Sketch sketch) + { + for (SketchCode sc : sketch.getCode()) { + if (sc.isModified()) { + return true; + } + } + return false; + } + } diff --git a/pdex/src/processing/mode/experimental/TextArea.java b/pdex/src/processing/mode/experimental/TextArea.java index cebf9446c..691cf9f7a 100644 --- a/pdex/src/processing/mode/experimental/TextArea.java +++ b/pdex/src/processing/mode/experimental/TextArea.java @@ -18,6 +18,8 @@ package processing.mode.experimental; import static processing.mode.experimental.ExperimentalMode.log; import static processing.mode.experimental.ExperimentalMode.log2; +import galsasson.mode.tweak.ColorControlBox; +import galsasson.mode.tweak.Handle; import java.awt.Color; import java.awt.Cursor; @@ -29,6 +31,7 @@ import java.awt.event.KeyListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -41,7 +44,7 @@ import processing.app.syntax.JEditTextArea; import processing.app.syntax.TextAreaDefaults; /** * Customized text area. Adds support for line background colors. - * + * * @author Martin Leopold */ public class TextArea extends JEditTextArea { @@ -114,11 +117,25 @@ public class TextArea extends JEditTextArea { breakpointMarker); currentLineMarker = theme.loadThemeString("currentline.marker", currentLineMarker); + + // TweakMode code + + prevCompListeners = painter + .getComponentListeners(); + prevMouseListeners = painter.getMouseListeners(); + prevMMotionListeners = painter + .getMouseMotionListeners(); + prevKeyListeners = editor.getKeyListeners(); + + + interactiveMode = false; + addPrevListeners(); + } /** * Sets ErrorCheckerService and loads theme for TextArea(XQMode) - * + * * @param ecs * @param mode */ @@ -133,7 +150,7 @@ public class TextArea extends JEditTextArea { * Code completion begins from here. */ public void processKeyEvent(KeyEvent evt) { - + if(evt.getKeyCode() == KeyEvent.VK_ESCAPE){ if(suggestion != null){ if(suggestion.isVisible()){ @@ -148,15 +165,15 @@ public class TextArea extends JEditTextArea { if (suggestion != null) { if (suggestion.isVisible()) { if (suggestion.insertSelection()) { - hideSuggestion(); // Kill it! + hideSuggestion(); // Kill it! evt.consume(); return; } } } } - - + + if (evt.getID() == KeyEvent.KEY_PRESSED) { switch (evt.getKeyCode()) { case KeyEvent.VK_DOWN: @@ -192,7 +209,7 @@ public class TextArea extends JEditTextArea { super.processKeyEvent(evt); if (evt.getID() == KeyEvent.KEY_TYPED) { - + char keyChar = evt.getKeyChar(); if (keyChar == KeyEvent.VK_ENTER || keyChar == KeyEvent.VK_ESCAPE) { return; @@ -223,7 +240,7 @@ public class TextArea extends JEditTextArea { } return; } - + SwingWorker worker = new SwingWorker() { protected Object doInBackground() throws Exception { // errorCheckerService.runManualErrorCheck(); @@ -242,12 +259,12 @@ public class TextArea extends JEditTextArea { worker.execute(); } - + } - + /** * Retrieves the word on which the mouse pointer is present - * @param evt - the MouseEvent which triggered this method + * @param evt - the MouseEvent which triggered this method * @return */ private String fetchPhrase(MouseEvent evt) { @@ -310,16 +327,16 @@ public class TextArea extends JEditTextArea { return word.trim(); } } - + /** * Retrieves the current word typed just before the caret. * Then triggers code completion for that word. - * - * @param evt - the KeyEvent which triggered this method + * + * @param evt - the KeyEvent which triggered this method * @return */ private String fetchPhrase(KeyEvent evt) { - + int off = getCaretPosition(); log2("off " + off); if (off < 0) @@ -339,7 +356,7 @@ public class TextArea extends JEditTextArea { if(x >= s.length() || x < 0) return null; //TODO: Does this check cause problems? Verify. log2(" x char: " + s.charAt(x)); - //int xLS = off - getLineStartNonWhiteSpaceOffset(line); + //int xLS = off - getLineStartNonWhiteSpaceOffset(line); String word = (x < s.length() ? s.charAt(x) : "") + ""; if (s.trim().length() == 1) { @@ -349,7 +366,7 @@ public class TextArea extends JEditTextArea { word = word.trim(); if (word.endsWith(".")) word = word.substring(0, word.length() - 1); - + errorCheckerService.getASTGenerator().preparePredictions(word, line + errorCheckerService.mainClassOffset,0); return word; @@ -427,7 +444,7 @@ public class TextArea extends JEditTextArea { /** * Retrieve the total width of the gutter area. - * + * * @return gutter width in pixels */ protected int getGutterWidth() { @@ -447,7 +464,7 @@ public class TextArea extends JEditTextArea { /** * Retrieve the width of margins applied to the left and right of the gutter * text. - * + * * @return margins in pixels */ protected int getGutterMargins() { @@ -459,7 +476,7 @@ public class TextArea extends JEditTextArea { /** * Set the gutter text of a specific line. - * + * * @param lineIdx * the line index (0-based) * @param text @@ -472,7 +489,7 @@ public class TextArea extends JEditTextArea { /** * Set the gutter text and color of a specific line. - * + * * @param lineIdx * the line index (0-based) * @param text @@ -487,7 +504,7 @@ public class TextArea extends JEditTextArea { /** * Clear the gutter text of a specific line. - * + * * @param lineIdx * the line index (0-based) */ @@ -508,7 +525,7 @@ public class TextArea extends JEditTextArea { /** * Retrieve the gutter text of a specific line. - * + * * @param lineIdx * the line index (0-based) * @return the gutter text @@ -519,7 +536,7 @@ public class TextArea extends JEditTextArea { /** * Retrieve the gutter text color for a specific line. - * + * * @param lineIdx * the line index * @return the gutter text color @@ -530,7 +547,7 @@ public class TextArea extends JEditTextArea { /** * Set the background color of a line. - * + * * @param lineIdx * 0-based line number * @param col @@ -543,7 +560,7 @@ public class TextArea extends JEditTextArea { /** * Clear the background color of a line. - * + * * @param lineIdx * 0-based line number */ @@ -564,7 +581,7 @@ public class TextArea extends JEditTextArea { /** * Get a lines background color. - * + * * @param lineIdx * 0-based line number * @return the color or null if no color was set for the specified line @@ -576,7 +593,7 @@ public class TextArea extends JEditTextArea { /** * Convert a character offset to a horizontal pixel position inside the text * area. Overridden to take gutter width into account. - * + * * @param line * the 0-based line number * @param offset @@ -591,7 +608,7 @@ public class TextArea extends JEditTextArea { /** * Convert a horizontal pixel position to a character offset. Overridden to * take gutter width into account. - * + * * @param line * the 0-based line number * @param x @@ -633,7 +650,7 @@ public class TextArea extends JEditTextArea { } return; } - + if (me.getButton() == MouseEvent.BUTTON3) { fetchPhrase(me); } @@ -739,8 +756,8 @@ public class TextArea extends JEditTextArea { } /** - * Calculates location of caret and displays the suggestion popup at the location. - * + * Calculates location of caret and displays the suggestion popup at the location. + * * @param defListModel * @param subWord */ @@ -771,7 +788,7 @@ public class TextArea extends JEditTextArea { location,editor); // else // suggestion.updateList(defListModel, subWord, location, position); -// +// // suggestion.setVisible(true); requestFocusInWindow(); // SwingUtilities.invokeLater(new Runnable() { @@ -793,4 +810,102 @@ public class TextArea extends JEditTextArea { } } + // TweakMode code + + // save input listeners to stop/start text edit + ComponentListener[] prevCompListeners; + MouseListener[] prevMouseListeners; + MouseMotionListener[] prevMMotionListeners; + KeyListener[] prevKeyListeners; + + boolean interactiveMode; + + /* remove all standard interaction listeners */ + public void removeAllListeners() + { + ComponentListener[] componentListeners = painter + .getComponentListeners(); + MouseListener[] mouseListeners = painter.getMouseListeners(); + MouseMotionListener[] mouseMotionListeners = painter + .getMouseMotionListeners(); + KeyListener[] keyListeners = editor.getKeyListeners(); + + for (ComponentListener cl : componentListeners) + painter.removeComponentListener(cl); + + for (MouseListener ml : mouseListeners) + painter.removeMouseListener(ml); + + for (MouseMotionListener mml : mouseMotionListeners) + painter.removeMouseMotionListener(mml); + + for (KeyListener kl : keyListeners) { + editor.removeKeyListener(kl); + } + } + + public void startInteractiveMode() + { + // ignore if we are already in interactiveMode + if (interactiveMode) + return; + + removeAllListeners(); + + // add our private interaction listeners + customPainter.addMouseListener(customPainter); + customPainter.addMouseMotionListener(customPainter); + customPainter.startInterativeMode(); + customPainter.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); + this.editable = false; + this.caretBlinks = false; + this.setCaretVisible(false); + interactiveMode = true; + } + + public void stopInteractiveMode() + { + // ignore if we are not in interactive mode + if (!interactiveMode) + return; + + removeAllListeners(); + addPrevListeners(); + + customPainter.stopInteractiveMode(); + customPainter.setCursor(new Cursor(Cursor.TEXT_CURSOR)); + this.editable = true; + this.caretBlinks = true; + this.setCaretVisible(true); + + interactiveMode = false; + } + + public int getHorizontalScroll() + { + return horizontal.getValue(); + } + + private void addPrevListeners() + { + // add the original text-edit listeners + for (ComponentListener cl : prevCompListeners) { + customPainter.addComponentListener(cl); + } + for (MouseListener ml : prevMouseListeners) { + customPainter.addMouseListener(ml); + } + for (MouseMotionListener mml : prevMMotionListeners) { + customPainter.addMouseMotionListener(mml); + } + for (KeyListener kl : prevKeyListeners) { + editor.addKeyListener(kl); + } + } + + public void updateInterface(ArrayList handles[], ArrayList colorBoxes[]) + { + customPainter.updateInterface(handles, colorBoxes); + } + } diff --git a/pdex/src/processing/mode/experimental/TextAreaPainter.java b/pdex/src/processing/mode/experimental/TextAreaPainter.java index 4961510d2..a53dd9740 100644 --- a/pdex/src/processing/mode/experimental/TextAreaPainter.java +++ b/pdex/src/processing/mode/experimental/TextAreaPainter.java @@ -17,27 +17,44 @@ */ package processing.mode.experimental; import static processing.mode.experimental.ExperimentalMode.log; +import galsasson.mode.tweak.ColorControlBox; +import galsasson.mode.tweak.ColorSelector; +import galsasson.mode.tweak.Handle; +import galsasson.mode.tweak.Settings; +import galsasson.mode.tweak.TweakEditor; import java.awt.Color; +import java.awt.Cursor; import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.RenderingHints; import java.awt.Toolkit; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.image.BufferedImage; +import java.util.ArrayList; import javax.swing.text.BadLocationException; import javax.swing.text.Segment; import javax.swing.text.Utilities; +import processing.app.SketchCode; import processing.app.syntax.TextAreaDefaults; import processing.app.syntax.TokenMarker; /** * Customized line painter. Adds support for background colors, left hand gutter * area with background color and text. - * + * * @author Martin Leopold */ -public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { +public class TextAreaPainter extends processing.app.syntax.TextAreaPainter + implements MouseListener, MouseMotionListener { protected TextArea ta; // we need the subclassed textarea @@ -79,6 +96,9 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { } }); + // TweakMode code + interactiveMode = false; + cursorType = Cursor.DEFAULT_CURSOR; } // public void processKeyEvent(KeyEvent evt) { @@ -141,7 +161,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { } if (Character.isDigit(word.charAt(0))) return; - + log(errorCheckerService.mainClassOffset + line + "|" + line + "| offset " + xLS + word + " <= \n"); errorCheckerService.getASTGenerator() @@ -161,7 +181,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { /** * Paint a line. Paints the gutter (with background color and text) then the * line (background color and text). - * + * * @param gfx * the graphics context * @param tokenMarker @@ -174,7 +194,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { protected void paintLine(Graphics gfx, TokenMarker tokenMarker, int line, int x) { try { - //TODO: This line is causing NPE's randomly ever since I added the toggle for + //TODO: This line is causing NPE's randomly ever since I added the toggle for //Java Mode/Debugger toolbar. super.paintLine(gfx, tokenMarker, line, x + ta.getGutterWidth()); } catch (Exception e) { @@ -183,22 +203,22 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { if(ta.editor.debugToolbarEnabled != null && ta.editor.debugToolbarEnabled.get()){ // paint gutter paintGutterBg(gfx, line, x); - + // disabled line background after P5 2.1, since it adds highlight by default - //paintLineBgColor(gfx, line, x + ta.getGutterWidth()); - + //paintLineBgColor(gfx, line, x + ta.getGutterWidth()); + paintGutterLine(gfx, line, x); - + // paint gutter symbol paintGutterText(gfx, line, x); - - } + + } paintErrorLine(gfx, line, x); } /** * Paint the gutter background (solid color). - * + * * @param gfx * the graphics context * @param line @@ -214,7 +234,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { /** * Paint the vertical gutter separator line. - * + * * @param gfx * the graphics context * @param line @@ -231,7 +251,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { /** * Paint the gutter text. - * + * * @param gfx * the graphics context * @param line @@ -268,7 +288,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { /** * Paint the background color of a line. - * + * * @param gfx * the graphics context * @param line @@ -295,7 +315,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { /** * Paints the underline for an error/warning line - * + * * @param gfx * the graphics context * @param tokenMarker @@ -315,7 +335,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { boolean notFound = true; boolean isWarning = false; Problem problem = null; - + // Check if current line contains an error. If it does, find if it's an // error or warning for (ErrorMarker emarker : errorCheckerService.getEditor().errorBar.errorPoints) { @@ -343,7 +363,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { int start = ta.getLineStartOffset(line) + problem.getPDELineStartOffset(); int pLength = problem.getPDELineStopOffset() + 1 - problem.getPDELineStartOffset(); - + try { String badCode = null; String goodCode = null; @@ -375,7 +395,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { // gfx.fillRect(x1, y, rw, height); // Let the painting begin! - + // Little rect at starting of a line containing errors - disabling it for now // gfx.setColor(errorMarkerColor); // if (isWarning) { @@ -383,7 +403,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { // } // gfx.fillRect(1, y + 2, 3, height - 2); - + gfx.setColor(errorColor); if (isWarning) { gfx.setColor(warningColor); @@ -411,7 +431,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { /** * Trims out trailing whitespaces (to the right) - * + * * @param string * @return - String */ @@ -428,7 +448,7 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { /** * Sets ErrorCheckerService and loads theme for TextAreaPainter(XQMode) - * + * * @param ecs * @param mode */ @@ -503,4 +523,322 @@ public class TextAreaPainter extends processing.app.syntax.TextAreaPainter { } + // TweakMode code + protected int horizontalAdjustment = 0; + + public boolean interactiveMode = false; + public ArrayList handles[]; + public ArrayList colorBoxes[]; + + public Handle mouseHandle = null; + public ColorSelector colorSelector; + + int cursorType; + BufferedImage cursorImg = new BufferedImage(16, 16, BufferedImage.TYPE_INT_ARGB); + + // Create a new blank cursor. + Cursor blankCursor = Toolkit.getDefaultToolkit().createCustomCursor( + cursorImg, new Point(0, 0), "blank cursor"); + + + /** + * Repaints the text. + * @param gfx The graphics context + */ + @Override + public synchronized void paint(Graphics gfx) + { + super.paint(gfx); + + if (interactiveMode && handles!=null) + { + int currentTab = ta.editor.getSketch().getCurrentCodeIndex(); + // enable anti-aliasing + Graphics2D g2d = (Graphics2D)gfx; + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + + for (Handle n : handles[currentTab]) + { + // update n position and width, and draw it + int lineStartChar = ta.getLineStartOffset(n.line); + int x = ta.offsetToX(n.line, n.newStartChar - lineStartChar); + int y = ta.lineToY(n.line) + fm.getHeight() + 1; + int end = ta.offsetToX(n.line, n.newEndChar - lineStartChar); + n.setPos(x, y); + n.setWidth(end - x); + n.draw(g2d, n==mouseHandle); + } + + // draw color boxes + for (ColorControlBox cBox: colorBoxes[currentTab]) + { + int lineStartChar = ta.getLineStartOffset(cBox.getLine()); + int x = ta.offsetToX(cBox.getLine(), cBox.getCharIndex() - lineStartChar); + int y = ta.lineToY(cBox.getLine()) + fm.getDescent(); + cBox.setPos(x, y+1); + cBox.draw(g2d); + } + } + } + + public void startInterativeMode() + { + interactiveMode = true; + repaint(); + } + + public void stopInteractiveMode() + { + interactiveMode = false; + + if (colorSelector != null) { + // close color selector + colorSelector.hide(); + colorSelector.frame.dispatchEvent(new WindowEvent(colorSelector.frame, WindowEvent.WINDOW_CLOSING)); + } + + repaint(); + } + + // Update the interface + public void updateInterface(ArrayList handles[], ArrayList colorBoxes[]) + { + this.handles = handles; + this.colorBoxes = colorBoxes; + + initInterfacePositions(); + repaint(); + } + + /** + * Initialize all the number changing interfaces. + * synchronize this method to prevent the execution of 'paint' in the middle. + * (don't paint while we make changes to the text of the editor) + */ + public synchronized void initInterfacePositions() + { + SketchCode[] code = ta.editor.getSketch().getCode(); + int prevScroll = ta.getVerticalScrollPosition(); + String prevText = ta.getText(); + + for (int tab=0; tab