moving things around to merge PDE X

This commit is contained in:
Ben Fry
2015-01-20 14:56:21 -05:00
parent 25099cfbfa
commit 260d131c00
56 changed files with 38 additions and 2 deletions

View File

@@ -0,0 +1,367 @@
package galsasson.mode.tweak;
import java.awt.BasicStroke;
import java.awt.Color;
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<Handle> handles;
ColorMode colorMode;
Color color;
boolean ilegalColor = false;
boolean isBW;
boolean isHex;
String drawContext;
// interface
int x, y, width, height;
TextAreaPainter painter;
public ColorControlBox(String context, ColorMode mode, ArrayList<Handle> 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(TextAreaPainter textAreaPainter, int x, int y, int w, int h)
{
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);
// draw current color
g2d.setColor(color);
g2d.fillRoundRect(0, 0, width, height, 5, 5);
// draw black outline
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) {
int value = handles.get(0).newValue.intValue();
if ((value&0xff000000) == 0) {
return true;
}
}
return false;
}
/**
* Check if color is hex or webcolor
* @return
* true if number is hex or webcolor
*/
private boolean isHexColor()
{
if (handles.get(0).type == "hex" || handles.get(0).type == "webcolor") {
int value = handles.get(0).value.intValue();
if ((value&0xff000000) != 0) {
return true;
}
}
return false;
}
public Color getCurrentColor()
{
try {
if (handles.size() == 1)
{
if (isBW) {
// treat as color(gray)
float gray = handles.get(0).newValue.floatValue();
return verifiedGrayColor(gray);
}
else {
// treat as color(argb)
int argb = handles.get(0).newValue.intValue();
return verifiedHexColor(argb);
}
}
else if (handles.size() == 2)
{
if (isBW) {
// color(gray, alpha)
float gray = handles.get(0).newValue.floatValue();
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);
}
}
else if (handles.size() == 3)
{
// color(v1, v2, v3)
float v1 = handles.get(0).newValue.floatValue();
float v2 = handles.get(1).newValue.floatValue();
float v3 = handles.get(2).newValue.floatValue();
if (colorMode.modeType == ColorMode.RGB) {
return verifiedRGBColor(v1, v2, v3, colorMode.aMax);
}
else {
return verifiedHSBColor(v1, v2, v3, colorMode.aMax);
}
}
else if (handles.size() == 4)
{
// color(v1, v2, v3, alpha)
float v1 = handles.get(0).newValue.floatValue();
float v2 = handles.get(1).newValue.floatValue();
float v3 = handles.get(2).newValue.floatValue();
float a = handles.get(3).newValue.floatValue();
if (colorMode.modeType == ColorMode.RGB) {
return verifiedRGBColor(v1, v2, v3, a);
}
else {
return verifiedHSBColor(v1, v2, v3, a);
}
}
}
catch (Exception e) {
System.out.println("error parsing color value: " + e.toString());
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);
}
private Color verifiedHexColor(int argb, float alpha)
{
int r = (argb>>16)&0xff;
int g = (argb>>8)&0xff;
int b = (argb&0xff);
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 ||
g < 0 || g > colorMode.v2Max ||
b < 0 || b > colorMode.v3Max) {
return colorError();
}
ilegalColor = false;
r = r/colorMode.v1Max * 255;
g = g/colorMode.v2Max * 255;
b = b/colorMode.v3Max * 255;
return new Color((int)r, (int)g, (int)b, 255);
}
public Color verifiedHSBColor(float h, float s, float b, float a)
{
if (h < 0 || h > colorMode.v1Max ||
s < 0 || s > colorMode.v2Max ||
b < 0 || b > colorMode.v3Max) {
return colorError();
}
ilegalColor = false;
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;
return Color.WHITE;
}
public void colorChanged()
{
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;
return handles.get(lastHandle).newEndChar + 2;
}
/* 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 && my<y+height) {
return true;
}
return false;
}
/* Only show the color box if mouse is on the same line
*
* return true if there was change
*/
public boolean setMouseY(int my)
{
boolean change = false;
if (my>y && my<y+height) {
if (!visible) {
change = true;
}
visible = true;
}
else {
if (visible) {
change = true;
}
visible = false;
}
return change;
}
/* Update the color numbers with the new values that were selected
* in the color selector
*
* hue, saturation and brightness parameters are always 0-255
*/
public void selectorChanged(int hue, int saturation, int brightness)
{
if (isBW) {
// color(gray) or color(gray, alpha)
handles.get(0).setValue((float)hue/255*colorMode.v1Max);
}
else {
if (handles.size() == 1 || handles.size() == 2) {
// color(argb)
int prevVal = handles.get(0).newValue.intValue();
int prevAlpha = (prevVal>>24)&0xff;
Color c = Color.getHSBColor((float)hue/255, (float)saturation/255, (float)brightness/255);
int newVal = (prevAlpha<<24) | (c.getRed()<<16) | (c.getGreen()<<8) | (c.getBlue());
handles.get(0).setValue(newVal);
}
else if (handles.size() == 3 || handles.size() == 4) {
// color(v1, v2, v3) or color(v1, v2, v3, alpha)
if (colorMode.modeType == ColorMode.HSB) {
// HSB
float v1 = (float)hue/255 * colorMode.v1Max;
float v2 = (float)saturation/255 * colorMode.v2Max;
float v3 = (float)brightness/255 * colorMode.v3Max;
handles.get(0).setValue(v1);
handles.get(1).setValue(v2);
handles.get(2).setValue(v3);
}
else {
// RGB
Color c = Color.getHSBColor((float)hue/255, (float)saturation/255, (float)brightness/255);
handles.get(0).setValue((float)c.getRed()/255*colorMode.v1Max);
handles.get(1).setValue((float)c.getGreen()/255*colorMode.v2Max);
handles.get(2).setValue((float)c.getBlue()/255*colorMode.v3Max);
}
}
}
// update our own color
color = getCurrentColor();
// update code text painter so the user will see the changes
painter.updateCodeText();
painter.repaint();
}
public String toString()
{
return handles.size() + " handles, color mode: " + colorMode.toString();
}
}

View File

@@ -0,0 +1,97 @@
package galsasson.mode.tweak;
public class ColorMode {
final static int RGB = 0;
final static int HSB = 1;
float v1Max, v2Max, v3Max, aMax;
int modeType;
boolean unrecognizedMode;
String drawContext;
public ColorMode(String context)
{
this.drawContext = context;
modeType = RGB;
v1Max = 255;
v2Max = 255;
v3Max = 255;
aMax = 255;
unrecognizedMode = false;
}
public ColorMode(String context, int type, float v1, float v2, float v3, float a)
{
this.drawContext = context;
modeType = type;
v1Max = v1;
v2Max = v2;
v3Max = v3;
aMax = a;
unrecognizedMode = false;
}
public static ColorMode fromString(String context, String mode)
{
try
{
String[] elements = mode.split(",");
// determine the type of the color mode
int type = RGB;
if (elements[0].trim().equals("HSB")) {
type = HSB;
}
if (elements.length == 1) {
// colorMode in the form of colorMode(type)
return new ColorMode(context, type, 255, 255, 255, 255);
}
else if (elements.length == 2) {
// colorMode in the form of colorMode(type, max)
float max = Float.parseFloat(elements[1].trim());
return new ColorMode(context, type, max, max, max, max);
}
else if (elements.length == 4) {
// colorMode in the form of colorMode(type, max1, max2, max3)
float r = Float.parseFloat(elements[1].trim());
float g = Float.parseFloat(elements[2].trim());
float b = Float.parseFloat(elements[3].trim());
return new ColorMode(context, type, r, g, b, 255);
}
else if (elements.length == 5) {
// colorMode in the form of colorMode(type, max1, max2, max3, maxA)
float r = Float.parseFloat(elements[1].trim());
float g = Float.parseFloat(elements[2].trim());
float b = Float.parseFloat(elements[3].trim());
float a = Float.parseFloat(elements[4].trim());
return new ColorMode(context, type, r, g, b, a);
}
}
catch(Exception e) { }
/* if we failed to parse this mode (uses variables etc..)
* we should still keep it so we'll know there is a mode declaration
* and we should mark it as unrecognizable
*/
ColorMode newMode = new ColorMode(context);
newMode.unrecognizedMode = true;
return newMode;
}
public String toString()
{
String type;
if (modeType == RGB) {
type = "RGB";
}
else {
type = "HSB";
}
return "ColorMode: " + type + ": (" + v1Max + ", " + v2Max + ", " + v3Max + ", " + aMax + ")";
}
}

View File

@@ -0,0 +1,31 @@
package galsasson.mode.tweak;
import java.awt.Color;
public class ColorScheme {
private static ColorScheme instance = null;
public Color redStrokeColor;
public Color progressFillColor;
public Color progressEmptyColor;
public Color markerColor;
public Color whitePaneColor;
private ColorScheme()
{
redStrokeColor = new Color(160, 20, 20); // dark red
progressEmptyColor = new Color(180, 180, 180, 200);
progressFillColor = new Color(0, 0, 0, 200);
markerColor = new Color(228, 200, 91, 127);
whitePaneColor = new Color(255, 255, 255, 120);
}
public static ColorScheme getInstance() {
if (instance == null) {
instance = new ColorScheme();
}
return instance;
}
}

View File

@@ -0,0 +1,398 @@
package galsasson.mode.tweak;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import javax.swing.Box;
import javax.swing.JFrame;
import processing.core.PApplet;
import processing.core.PGraphics;
import processing.core.PImage;
public class ColorSelector {
int hue, saturation, brightness;
public JFrame frame;
public ColorControlBox colorBox;
ColorSelectorBox selectorBox;
ColorSelectorSlider selectorSlider;
SelectorTopBar topBar;
public ColorSelector(ColorControlBox colorBox)
{
this.colorBox = colorBox;
createFrame();
}
public void createFrame()
{
frame = new JFrame();
frame.setBackground(Color.BLACK);
Box box = Box.createHorizontalBox();
box.setBackground(Color.BLACK);
selectorSlider = new ColorSelectorSlider();
if (!colorBox.isBW) {
selectorBox = new ColorSelectorBox();
box.add(selectorBox.getCanvas());
}
box.add(Box.createHorizontalGlue());
box.add(selectorSlider.getCanvas(), BorderLayout.CENTER);
box.add(Box.createHorizontalGlue());
frame.getContentPane().add(box, BorderLayout.CENTER);
frame.pack();
frame.setResizable(false);
frame.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
selectorBox.init();
selectorSlider.init();
}
public void show(int x, int y)
{
frame.setLocation(x, y);
frame.setVisible(true);
frame.repaint();
}
public void hide()
{
this.colorBox = null;
frame.setVisible(false);
}
public void refreshColor()
{
if (colorBox.ilegalColor) {
return;
}
setColor(colorBox.color);
}
public void setColor(Color c)
{
if (selectorBox != null) {
selectorBox.setToColor(c);
}
selectorSlider.setToColor(c);
repaintSelector();
}
public void satBrightChanged()
{
repaintSelector();
}
public void hueChanged()
{
if (selectorBox != null) {
selectorBox.renderBack();
}
repaintSelector();
}
public void repaintSelector()
{
if (selectorBox != null) {
selectorBox.redraw();
}
selectorSlider.redraw();
}
/*
* PApplets for the interactive color fields
*/
public class ColorSelectorBox extends PApplet {
int lastX, lastY;
PImage backImg;
public int sketchWidth() { return 255; }
public int sketchHeight() { return 255; }
public void setup() {
noLoop();
colorMode(HSB, 255, 255, 255);
noFill();
if (!colorBox.ilegalColor) {
setToColor(colorBox.color);
}
renderBack();
}
public void draw() {
image(backImg, 0, 0);
stroke((lastY<128) ? 0 : 255);
pushMatrix();
translate(lastX, lastY);
ellipse(0, 0, 5, 5);
line(-8, 0, -6, 0);
line(6, 0, 8, 0);
line(0, -8, 0, -6);
line(0, 6, 0, 8);
popMatrix();
}
public void renderBack() {
PGraphics buf = createGraphics(255, 255);
buf.colorMode(HSB, 255, 255, 255);
buf.beginDraw();
buf.loadPixels();
int index=0;
for (int j=0; j<255; j++) {
for (int i=0; i<255; i++) {
buf.pixels[index++] = color(hue, i, 255-j);
}
}
buf.updatePixels();
buf.endDraw();
backImg = buf.get();
}
public void setToColor(Color c) {
// set selector color
float hsb[] = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null);
saturation = (int)(hsb[1]*255);
brightness = (int)(hsb[2]*255);
lastX = saturation;
lastY = 255 - brightness;
}
public void mousePressed() {
if (mouseX < 0 || mouseX > 255 ||
mouseY < 0 || mouseY > 255) {
return;
}
lastX = mouseX;
lastY = mouseY;
updateColor();
}
public void mouseDragged() {
if (mouseX < 0 || mouseX > 255 ||
mouseY < 0 || mouseY > 255) {
return;
}
lastX = mouseX;
lastY = mouseY;
updateColor();
}
public void updateColor() {
saturation = lastX;
brightness = 255 - lastY;
satBrightChanged();
colorBox.selectorChanged(hue, saturation, brightness);
}
/*
public Dimension getPreferredSize() {
return new Dimension(255, 255);
}
public Dimension getMinimumSize() {
return new Dimension(255, 255);
}
public Dimension getMaximumSize() {
return new Dimension(255, 255);
}
*/
}
public class ColorSelectorSlider extends PApplet {
PImage backImg;
int lastY;
public void setup() {
size(30, 255);
noLoop();
colorMode(HSB, 255, 255, 255);
strokeWeight(1);
noFill();
loadPixels();
if (!colorBox.ilegalColor) {
setToColor(colorBox.color);
}
// draw the slider background
renderBack();
}
public void draw() {
image(backImg, 0, 0);
if (colorBox.isBW) {
stroke(lastY<128 ? 0 : 255);
}
else {
stroke(0);
}
pushMatrix();
translate(0, lastY);
// draw left bracket
beginShape();
vertex(5, -2);
vertex(1, -2);
vertex(1, 2);
vertex(5, 2);
endShape();
// draw middle lines
line(13, 0, 17, 0);
line(15, -2, 15, 2);
// draw right bracket
beginShape();
vertex(24, -2);
vertex(28, -2);
vertex(28, 2);
vertex(24, 2);
endShape();
popMatrix();
if (colorBox.isBW) {
stroke(255);
rect(0, 0, 29, 254);
}
else {
stroke(0);
line(0, 0, 0, 255);
line(29, 0, 29, 255);
}
}
public void renderBack() {
PGraphics buf = createGraphics(30, 255);
buf.beginDraw();
buf.loadPixels();
int index=0;
for (int j=0; j<255; j++) {
for (int i=0; i<30; i++) {
if (colorBox.isBW) {
buf.pixels[index++] = color(255-j);
}
else {
buf.pixels[index++] = color(255-j, 255, 255);
}
}
}
buf.updatePixels();
buf.endDraw();
backImg = buf.get();
}
public void setToColor(Color c)
{
// set slider position
if (colorBox.isBW) {
hue = c.getRed();
}
else {
float hsb[] = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null);
hue = (int)(hsb[0]*255);
}
lastY = 255 - hue;
}
public void mousePressed()
{
if (mouseX < 0 || mouseX > 30 ||
mouseY < 0 || mouseY > 255) {
return;
}
lastY = mouseY;
updateColor();
}
public void mouseDragged()
{
if (mouseX < 0 || mouseX > 30 ||
mouseY < 0 || mouseY > 255) {
return;
}
lastY = mouseY;
updateColor();
}
public void updateColor()
{
hue = 255 - lastY;
hueChanged();
colorBox.selectorChanged(hue, saturation, brightness);
}
public Dimension getPreferredSize() {
return new Dimension(30, 255);
}
public Dimension getMinimumSize() {
return new Dimension(30, 255);
}
public Dimension getMaximumSize() {
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);
}
public Dimension getMinimumSize() {
return new Dimension(barWidth, barHeight);
}
public Dimension getMaximumSize() {
return new Dimension(barWidth, barHeight);
}
}
}

View File

@@ -0,0 +1,74 @@
package galsasson.mode.tweak;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.geom.AffineTransform;
public class HProgressBar {
int x, y, size, width;
int pos;
int lPolyX, rPolyX;
Polygon rightPoly, leftPoly;
public HProgressBar(int size, int width)
{
this.size = size;
this.width = width;
x = 0;
y = 0;
setPos(0);
int xl[] = {0, 0, -(int)(size/1.5)};
int yl[] = {-(int)((float)size/3), (int)((float)size/3), 0};
leftPoly = new Polygon(xl, yl, 3);
int xr[] = {0, (int)(size/1.5), 0};
int yr[] = {-(int)((float)size/3), 0, (int)((float)size/3)};
rightPoly = new Polygon(xr, yr, 3);
}
public void setPos(int pos)
{
this.pos = pos;
lPolyX = 0;
rPolyX = 0;
if (pos > 0) {
rPolyX = pos;
}
else if (pos < 0) {
lPolyX = pos;
}
}
public void setWidth(int width)
{
this.width = width;
}
public void draw(Graphics2D g2d)
{
AffineTransform trans = g2d.getTransform();
g2d.translate(x, y);
// draw white cover on text line
g2d.setColor(ColorScheme.getInstance().whitePaneColor);
g2d.fillRect(-200+lPolyX, -size, 200-lPolyX-width/2, size+1);
g2d.fillRect(width/2, -size, 200+rPolyX, size+1);
// draw left and right triangles and leading line
g2d.setColor(ColorScheme.getInstance().progressFillColor);
AffineTransform tmp = g2d.getTransform();
g2d.translate(-width/2 - 5 + lPolyX, -size/2);
g2d.fillRect(0, -1, -lPolyX, 2);
g2d.fillPolygon(leftPoly);
g2d.setTransform(tmp);
g2d.translate(width/2 + 5 + rPolyX, -size/2);
g2d.fillRect(-rPolyX, -1, rPolyX+1, 2);
g2d.fillPolygon(rightPoly);
g2d.setTransform(tmp);
g2d.setTransform(trans);
}
}

View File

@@ -0,0 +1,262 @@
package galsasson.mode.tweak;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.Locale;
public class Handle {
public String type;
public String name;
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 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;
HProgressBar progBar = null;
String textFormat;
// the client that sends the changes
UDPTweakClient tweakClient;
public Handle(String t, String n, int vi, String v, int ti, int l, int sc,
int ec, int dp) {
type = t;
name = n;
varIndex = vi;
strValue = v;
tabIndex = ti;
line = l;
startChar = sc;
endChar = ec;
decimalPlaces = dp;
incValue = (float) (1 / Math.pow(10, decimalPlaces));
if (type == "int") {
value = newValue = Integer.parseInt(strValue);
strNewValue = strValue;
textFormat = "%d";
} else if (type == "hex") {
Long val = Long.parseLong(strValue.substring(2, strValue.length()),
16);
value = newValue = val.intValue();
strNewValue = strValue;
textFormat = "0x%x";
} else if (type == "webcolor") {
Long val = Long.parseLong(strValue.substring(1, strValue.length()),
16);
val = val | 0xff000000;
value = newValue = val.intValue();
strNewValue = strValue;
textFormat = "#%06x";
} else if (type == "float") {
value = newValue = Float.parseFloat(strValue);
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) {
change = 0;
return;
}
setValue(newValue.intValue() + (int) change);
} else if (type == "hex") {
setValue(newValue.intValue() + (int) change);
} else if (type == "webcolor") {
setValue(newValue.intValue() + (int) change);
} else if (type == "float") {
setValue(newValue.floatValue() + change);
}
updateColorBox();
}
public void setValue(Number value) {
if (type == "int") {
newValue = value.intValue();
strNewValue = String.format(Locale.US, textFormat,
newValue.intValue());
} else if (type == "hex") {
newValue = value.intValue();
strNewValue = String.format(Locale.US, textFormat,
newValue.intValue());
} else if (type == "webcolor") {
newValue = value.intValue();
// keep only RGB
int val = (newValue.intValue() & 0xffffff);
strNewValue = String.format(Locale.US, textFormat, val);
} else if (type == "float") {
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());
}
// send new data to the server in the sketch
sendNewValue();
}
public void updateColorBox() {
if (colorBox != null) {
colorBox.colorChanged();
}
}
private float getChange() {
int pixels = xCurrent - xLast;
return 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 && mx < x + width + 2 && my > y - height && my < y) {
return true;
}
return false;
}
public boolean valueChanged() {
if (type == "int") {
return (value.intValue() != newValue.intValue());
} else if (type == "hex") {
return (value.intValue() != newValue.intValue());
} else if (type == "webcolor") {
return (value.intValue() != newValue.intValue());
} else {
return (value.floatValue() != newValue.floatValue());
}
}
public void setColorBox(ColorControlBox box) {
colorBox = box;
}
public void setTweakClient(UDPTweakClient client) {
tweakClient = client;
}
public void sendNewValue() {
int index = varIndex;
try {
if (type == "int") {
tweakClient.sendInt(index, newValue.intValue());
} else if (type == "hex") {
tweakClient.sendInt(index, newValue.intValue());
} else if (type == "webcolor") {
tweakClient.sendInt(index, newValue.intValue());
} else if (type == "float") {
tweakClient.sendFloat(index, newValue.floatValue());
}
} catch (Exception e) {
System.out.println("error sending new value!");
}
}
public String toString() {
return type + " " + name + " = " + strValue + " (tab: " + tabIndex
+ ", line: " + line + ", start: " + startChar + ", end: "
+ endChar + ")";
}
}
/*
* Used for sorting the handles by order of occurrence inside each tab
*/
class HandleComparator implements Comparator<Handle> {
public int compare(Handle handle1, Handle handle2) {
int tab = handle1.tabIndex - handle2.tabIndex;
if (tab == 0) {
return handle1.startChar - handle2.startChar;
} else {
return tab;
}
}
}

View File

@@ -0,0 +1,5 @@
package galsasson.mode.tweak;
public class Settings {
public static boolean alwaysShowColorBoxes = true;
}

View File

@@ -0,0 +1,783 @@
package galsasson.mode.tweak;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SketchParser {
public List<List<ColorControlBox>> colorBoxes;
public List<List<Handle>> allHandles;
int intVarCount;
int floatVarCount;
final String varPrefix = "tweakmode";
String[] codeTabs;
boolean requiresComment;
ArrayList<ColorMode> colorModes;
List<List<Range>> 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
* cannot know which color mode relate to a color.
*/
handleMultipleColorModes();
}
public void addAllNumbers() {
//allHandles = new ArrayList[codeTabs.length]; // moved inside addAllDecimalNumbers
addAllDecimalNumbers();
addAllHexNumbers();
addAllWebColorNumbers();
//for (int i=0; i<codeTabs.length; i++) {
for (List<Handle> handle : allHandles) {
//Collections.sort(allHandles[i], new HandleComparator());
Collections.sort(handle, new HandleComparator());
}
}
/**
* Get a list of all the numbers in this sketch
* @return
* list of all numbers in the sketch (excluding hexadecimals)
*/
private void addAllDecimalNumbers() {
allHandles = new ArrayList<>();
// for every number found:
// save its type (int/float), name, value and position in code.
Pattern p = Pattern.compile("[\\[\\{<>(),\\t\\s\\+\\-\\/\\*^%!|&=?:~]\\d+\\.?\\d*");
for (int i = 0; i < codeTabs.length; i++) {
//allHandles[i] = new ArrayList<Handle>();
List<Handle> handles = new ArrayList<Handle>();
allHandles.add(handles);
String c = codeTabs[i];
Matcher m = p.matcher(c);
while (m.find()) {
boolean forceFloat = false;
int start = m.start()+1;
int end = m.end();
if (isInComment(start, codeTabs[i])) {
// ignore comments
continue;
}
if (requiresComment) {
// only add numbers that have the "// tweak" comment in their line
if (!lineHasTweakComment(start, c)) {
continue;
}
}
// ignore scientific notation (e.g. 1e-6)
boolean found = false;
for (Range r : scientificNotations.get(i)) {
if (r.contains(start)) {
found=true;
break;
}
}
if (found) {
continue;
}
// remove any 'f' after the number
if (c.charAt(end) == 'f') {
forceFloat = true;
end++;
}
// if its a negative, include the '-' sign
if (c.charAt(start-1) == '-') {
if (isNegativeSign(start-2, c)) {
start--;
}
}
// special case for ignoring (0x...). will be handled later
if (c.charAt(m.end()) == 'x' ||
c.charAt(m.end()) == 'X') {
continue;
}
// special case for ignoring number inside a string ("")
if (isInsideString(start, c))
continue;
// beware of the global assignment (bug from 26.07.2013)
if (isGlobal(m.start(), c))
continue;
int line = countLines(c.substring(0, start)) - 1; // zero based
String value = c.substring(start, end);
//value
if (value.contains(".") || forceFloat) {
// consider this as a float
String name = varPrefix + "_float[" + floatVarCount +"]";
int decimalDigits = getNumDigitsAfterPoint(value);
handles.add(new Handle("float", name, floatVarCount, value, i, line, start, end, decimalDigits));
floatVarCount++;
} else {
// consider this as an int
String name = varPrefix + "_int[" + intVarCount +"]";
handles.add(new Handle("int", name, intVarCount, value, i, line, start, end, 0));
intVarCount++;
}
}
}
}
/**
* Get a list of all the hexadecimal numbers in the code
* @return
* list of all hexadecimal numbers in the sketch
*/
private void addAllHexNumbers()
{
/* for every number found:
* save its type (int/float), name, value and position in code.
*/
Pattern p = Pattern.compile("[\\[\\{<>(),\\t\\s\\+\\-\\/\\*^%!|&=?:~]0x[A-Fa-f0-9]+");
for (int i=0; i<codeTabs.length; i++)
{
String c = codeTabs[i];
Matcher m = p.matcher(c);
while (m.find())
{
int start = m.start()+1;
int end = m.end();
if (isInComment(start, codeTabs[i])) {
// ignore comments
continue;
}
if (requiresComment) {
// only add numbers that have the "// tweak" comment in their line
if (!lineHasTweakComment(start, c)) {
continue;
}
}
// special case for ignoring number inside a string ("")
if (isInsideString(start, c)) {
continue;
}
// beware of the global assignment (bug from 26.07.2013)
if (isGlobal(m.start(), c)) {
continue;
}
int line = countLines(c.substring(0, start)) - 1; // zero based
String value = c.substring(start, end);
String name = varPrefix + "_int[" + intVarCount + "]";
Handle handle;
try {
handle = new Handle("hex", name, intVarCount, value, i, line, start, end, 0);
}
catch (NumberFormatException e) {
// don't add this number
continue;
}
allHandles.get(i).add(handle);
intVarCount++;
}
}
}
/**
* Get a list of all the webcolors (#) numbers in the code
* @return
* list of all hexadecimal numbers in the sketch
*/
private void addAllWebColorNumbers()
{
Pattern p = Pattern.compile("#[A-Fa-f0-9]{6}");
for (int i=0; i<codeTabs.length; i++)
{
String c = codeTabs[i];
Matcher m = p.matcher(c);
while (m.find())
{
int start = m.start();
int end = m.end();
if (isInComment(start, codeTabs[i])) {
// ignore comments
continue;
}
if (requiresComment) {
// only add numbers that have the "// tweak" comment in their line
if (!lineHasTweakComment(start, c)) {
continue;
}
}
// special case for ignoring number inside a string ("")
if (isInsideString(start, c)) {
continue;
}
// beware of the global assignment (bug from 26.07.2013)
if (isGlobal(m.start(), c)) {
continue;
}
int line = countLines(c.substring(0, start)) - 1; // zero based
String value = c.substring(start, end);
String name = varPrefix + "_int[" + intVarCount + "]";
Handle handle;
try {
handle = new Handle("webcolor", name, intVarCount, value, i, line, start, end, 0);
}
catch (NumberFormatException e) {
// don't add this number
continue;
}
allHandles.get(i).add(handle);
intVarCount++;
}
}
}
private ArrayList<ColorMode> findAllColorModes() {
ArrayList<ColorMode> modes = new ArrayList<ColorMode>();
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;
}
index += 9;
int parOpen = tab.indexOf('(', index);
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() {
colorBoxes = new ArrayList<>();
// search tab for the functions: 'color', 'fill', 'stroke', 'background', 'tint'
Pattern p = Pattern.compile("color\\(|color\\s\\(|fill[\\(\\s]|stroke[\\(\\s]|background[\\(\\s]|tint[\\(\\s]");
for (int i = 0; i < codeTabs.length; i++) {
//colorBoxes[i] = new ArrayList<ColorControlBox>();
List<ColorControlBox> colorBox = new ArrayList<ColorControlBox>();
colorBoxes.add(colorBox);
String tab = codeTabs[i];
Matcher m = p.matcher(tab);
while (m.find()) {
ArrayList<Handle> colorHandles = new ArrayList<Handle>();
// look for the '(' and ')' positions
int openPar = tab.indexOf("(", m.start());
int closePar = tab.indexOf(")", m.end());
if (openPar < 0 || closePar < 0) {
// ignore this color
continue;
}
if (isInComment(m.start(), tab)) {
// ignore colors in a comment
continue;
}
// look for handles inside the parenthesis
for (Handle handle : allHandles.get(i)) {
if (handle.startChar > openPar &&
handle.endChar <= closePar) {
// we have a match
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
* check there is no garbage left
*/
String insidePar = tab.substring(openPar+1, closePar);
for (Handle h : colorHandles) {
insidePar = insidePar.replaceFirst(h.strValue, "");
}
// make sure there is only ' ' and ',' left in the string.
boolean garbage = false;
for (int j=0; j<insidePar.length(); j++) {
if (insidePar.charAt(j) != ' ' && insidePar.charAt(j) != ',') {
// don't add this color box because we can not know the
// real value of this color
garbage = true;
}
}
// create a new color box
if (!garbage) {
// find the context of the color (e.g. this.fill() or <object>.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) {
colorBox.add(newCCB);
}
} else {
colorBox.add(newCCB);
}
}
}
}
}
}
private void createColorBoxesForLights() {
// search code for light color and material color functions.
Pattern p = Pattern.compile("ambientLight[\\(\\s]|directionalLight[\\(\\s]"+
"|pointLight[\\(\\s]|spotLight[\\(\\s]|lightSpecular[\\(\\s]"+
"|specular[\\(\\s]|ambient[\\(\\s]|emissive[\\(\\s]");
for (int i=0; i<codeTabs.length; i++) {
String tab = codeTabs[i];
Matcher m = p.matcher(tab);
while (m.find()) {
ArrayList<Handle> colorHandles = new ArrayList<Handle>();
// look for the '(' and ')' positions
int openPar = tab.indexOf("(", m.start());
int closePar = tab.indexOf(")", m.end());
if (openPar < 0 || closePar < 0) {
// ignore this color
continue;
}
if (isInComment(m.start(), tab)) {
// ignore colors in a comment
continue;
}
// put 'colorParamsEnd' after three parameters inside the parenthesis or at the close
int colorParamsEnd = openPar;
int commas=3;
while (commas-- > 0) {
colorParamsEnd=tab.indexOf(",", colorParamsEnd+1);
if (colorParamsEnd < 0 ||
colorParamsEnd > closePar) {
colorParamsEnd = closePar;
break;
}
}
for (Handle handle : allHandles.get(i)) {
if (handle.startChar > openPar &&
handle.endChar <= colorParamsEnd) {
// we have a match
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
* check there is no garbage left
*/
String insidePar = tab.substring(openPar+1, colorParamsEnd);
for (Handle h : colorHandles) {
insidePar = insidePar.replaceFirst(h.strValue, "");
}
// make sure there is only ' ' and ',' left in the string.
boolean garbage = false;
for (int j=0; j<insidePar.length(); j++) {
if (insidePar.charAt(j) != ' ' && insidePar.charAt(j) != ',') {
// don't add this color box because we can not know the
// real value of this color
garbage = true;
}
}
// create a new color box
if (!garbage) {
// find the context of the color (e.g. this.fill() or <object>.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) {
colorBoxes.get(i).add(newCCB);
}
} else {
colorBoxes.get(i).add(newCCB);
}
}
}
}
}
}
private ColorMode getColorModeForContext(String context) {
for (ColorMode cm: colorModes) {
if (cm.drawContext.equals(context)) {
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;
}
private void handleMultipleColorModes()
{
// count how many color modes per context
Map<String, Integer> modeCount = new HashMap<String, Integer>();
for (ColorMode cm : colorModes)
{
Integer prev = modeCount.get(cm.drawContext);
if (prev == null) {
prev=0;
}
modeCount.put(cm.drawContext, prev+1);
}
// find the contexts that have more than one color mode
ArrayList<String> multipleContexts = new ArrayList<String>();
Set<String> allContexts = modeCount.keySet();
for (String context : allContexts) {
if (modeCount.get(context) > 1) {
multipleContexts.add(context);
}
}
/* keep only hex and web color boxes in color calls
* that belong to 'multipleContexts' contexts
*/
for (int i=0; i<codeTabs.length; i++) {
ArrayList<ColorControlBox> toDelete = new ArrayList<ColorControlBox>();
for (String context : multipleContexts) {
for (ColorControlBox ccb : colorBoxes.get(i)) {
if (ccb.drawContext.equals(context) && !ccb.isHex) {
toDelete.add(ccb);
}
}
}
colorBoxes.get(i).removeAll(toDelete);
}
}
public List<List<Range>> getAllScientificNotations() {
//ArrayList<Range> notations[] = new ArrayList[codeTabs.length];
List<List<Range>> notations = new ArrayList<>();
Pattern p = Pattern.compile("[+\\-]?(?:0|[1-9]\\d*)(?:\\.\\d*)?[eE][+\\-]?\\d+");
//for (int i = 0; i < codeTabs.length; i++) {
for (String code : codeTabs) {
List<Range> notation = new ArrayList<Range>();
//notations[i] = new ArrayList<Range>();
//Matcher m = p.matcher(codeTabs[i]);
Matcher m = p.matcher(code);
while (m.find()) {
//notations[i].add(new Range(m.start(), m.end()));
notation.add(new Range(m.start(), m.end()));
}
notations.add(notation);
}
return notations;
}
public static boolean containsTweakComment(String[] codeTabs) {
for (String tab : codeTabs) {
if (hasTweakComment(tab)) {
return true;
}
}
return false;
}
static public boolean lineHasTweakComment(int pos, String code) {
int lineEnd = getEndOfLine(pos, code);
if (lineEnd < 0) {
return false;
}
String line = code.substring(pos, lineEnd);
return hasTweakComment(line);
}
static private boolean hasTweakComment(String code) {
Pattern p = Pattern.compile("\\/\\/.*tweak", Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(code);
return m.find();
}
static private boolean isNegativeSign(int pos, String code) {
// go back and look for ,{[(=?+-/*%<>:&|^!~
for (int i = pos; i >= 0; i--) {
char c = code.charAt(i);
if (c != ' ' && c != '\t') {
return (c==',' || c=='{' || c=='[' || c=='(' ||
c=='=' || c=='?' || c=='+' || c=='-' ||
c=='/' || c=='*' || c=='%' || c=='<' ||
c=='>' || c==':' || c=='&' || c=='|' ||
c=='^' || c=='!' || c=='~');
}
}
return false;
}
static 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;
}
return 0;
}
static private int countLines(String str) {
String[] lines = str.split("\r\n|\n\r|\n|\r");
return lines.length;
}
/**
* Are we inside a string? (TODO: ignore comments in the code)
* @param pos
* position in the code
* @param code
* the code
* @return
*/
static private boolean isInsideString(int pos, String code) {
int quoteNum = 0; // count '"'
for (int c = pos; c>=0 && code.charAt(c) != '\n'; c--) {
if (code.charAt(c) == '"') {
quoteNum++;
}
}
if (quoteNum%2 == 1) {
return true;
}
return false;
}
/**
* Is this a global position?
* @param pos position
* @param code code
* @return
* true if the position 'pos' is in global scope in the code 'code'
*/
static private boolean isGlobal(int pos, String code) {
int curlyScope = 0; // count '{-}'
for (int c=pos; c>=0; c--)
{
if (code.charAt(c) == '{') {
// check if a function or an array assignment
for (int cc=c; cc>=0; cc--) {
if (code.charAt(cc)==')') {
curlyScope++;
break;
}
else if (code.charAt(cc)==']') {
break;
}
else if (code.charAt(cc)==';') {
break;
}
}
}
else if (code.charAt(c) == '}') {
// check if a function or an array assignment
for (int cc=c; cc>=0; cc--) {
if (code.charAt(cc)==')') {
curlyScope--;
break;
}
else if (code.charAt(cc)==']') {
break;
}
else if (code.charAt(cc)==';') {
break;
}
}
}
}
if (curlyScope == 0) {
// it is a global position
return true;
}
return false;
};
static private boolean isInComment(int pos, String code) {
// look for one line comment
int lineStart = getStartOfLine(pos, code);
if (lineStart < 0) {
return false;
}
if (code.substring(lineStart, pos).indexOf("//") != -1) {
return true;
}
// TODO: look for block comments
return false;
}
static private int getEndOfLine(int pos, String code) {
return code.indexOf("\n", pos);
}
static private int getStartOfLine(int pos, String code) {
while (pos >= 0) {
if (code.charAt(pos) == '\n') {
return pos+1;
}
pos--;
}
return 0;
}
/** returns the object of the function starting at 'pos'
*
* @param pos
* @param code
* @return
*/
static private String getObject(int pos, String code) {
boolean readObject = false;
String obj = "this";
while (pos-- >= 0) {
if (code.charAt(pos) == '.') {
if (!readObject) {
obj = "";
readObject = true;
}
else {
break;
}
}
else if (code.charAt(pos) == ' ' || code.charAt(pos) == '\t') {
break;
}
else if (readObject) {
obj = code.charAt(pos) + obj;
}
}
return obj;
}
static public 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) {
return v >= start && v < end;
}
}
}

View File

@@ -0,0 +1,20 @@
package galsasson.mode.tweak;
import processing.app.Base;
import processing.app.Editor;
import processing.mode.java.JavaToolbar;
public class TweakToolbar extends JavaToolbar {
static protected final int RUN = 0;
static protected final int STOP = 1;
static protected final int NEW = 2;
static protected final int OPEN = 3;
static protected final int SAVE = 4;
static protected final int EXPORT = 5;
public TweakToolbar(Editor editor, Base base) {
super(editor, base);
}
}

View File

@@ -0,0 +1,182 @@
package galsasson.mode.tweak;
import java.net.*;
import java.nio.ByteBuffer;
public class UDPTweakClient {
private DatagramSocket socket;
private InetAddress address;
private boolean initialized;
private int sketchPort;
static final int VAR_INT = 0;
static final int VAR_FLOAT = 1;
static final int SHUTDOWN = 0xffffffff;
public UDPTweakClient(int sketchPort)
{
this.sketchPort = sketchPort;
try {
socket = new DatagramSocket();
// only local sketch is allowed
address = InetAddress.getByName("127.0.0.1");
initialized = true;
}
catch (SocketException e) {
initialized = false;
}
catch (UnknownHostException e) {
socket.close();
initialized = false;
}
catch (SecurityException e) {
socket.close();
initialized = false;
}
}
public void shutdown()
{
if (!initialized) {
return;
}
// send shutdown to the sketch
sendShutdown();
initialized = false;
}
public boolean sendInt(int index, int val)
{
if (!initialized) {
return false;
}
try {
byte[] buf = new byte[12];
ByteBuffer bb = ByteBuffer.wrap(buf);
bb.putInt(0, VAR_INT);
bb.putInt(4, index);
bb.putInt(8, val);
DatagramPacket packet = new DatagramPacket(buf, buf.length, address, sketchPort);
socket.send(packet);
}
catch (Exception e) {
return false;
}
return true;
}
public boolean sendFloat(int index, float val)
{
if (!initialized) {
return false;
}
try {
byte[] buf = new byte[12];
ByteBuffer bb = ByteBuffer.wrap(buf);
bb.putInt(0, VAR_FLOAT);
bb.putInt(4, index);
bb.putFloat(8, val);
DatagramPacket packet = new DatagramPacket(buf, buf.length, address, sketchPort);
socket.send(packet);
}
catch (Exception e) {
return false;
}
return true;
}
public boolean sendShutdown()
{
if (!initialized) {
return false;
}
try {
byte[] buf = new byte[12];
ByteBuffer bb = ByteBuffer.wrap(buf);
bb.putInt(0, SHUTDOWN);
DatagramPacket packet = new DatagramPacket(buf, buf.length, address, sketchPort);
socket.send(packet);
}
catch (Exception e) {
return false;
}
return true;
}
public static String getServerCode(int listenPort, boolean hasInts, boolean hasFloats)
{
String serverCode = ""+
"class TweakModeServer extends Thread\n"+
"{\n"+
" protected DatagramSocket socket = null;\n"+
" protected boolean running = true;\n"+
" final int INT_VAR = 0;\n"+
" final int FLOAT_VAR = 1;\n"+
" final int SHUTDOWN = 0xffffffff;\n"+
" public TweakModeServer() {\n"+
" this(\"TweakModeServer\");\n"+
" }\n"+
" public TweakModeServer(String name) {\n"+
" super(name);\n"+
" }\n"+
" public void setup()\n"+
" {\n"+
" try {\n"+
" socket = new DatagramSocket("+listenPort+");\n"+
" socket.setSoTimeout(250);\n"+
" } catch (IOException e) {\n"+
" println(\"error: could not create TweakMode server socket\");\n"+
" }\n"+
" }\n"+
" public void run()\n"+
" {\n"+
" byte[] buf = new byte[256];\n"+
" while(running)\n"+
" {\n"+
" try {\n"+
" DatagramPacket packet = new DatagramPacket(buf, buf.length);\n"+
" socket.receive(packet);\n"+
" ByteBuffer bb = ByteBuffer.wrap(buf);\n"+
" int type = bb.getInt(0);\n"+
" int index = bb.getInt(4);\n";
if (hasInts) {
serverCode +=
" if (type == INT_VAR) {\n"+
" int val = bb.getInt(8);\n"+
" tweakmode_int[index] = val;\n"+
" }\n"+
" else ";
}
if (hasFloats) {
serverCode +=
" if (type == FLOAT_VAR) {\n"+
" float val = bb.getFloat(8);\n"+
" tweakmode_float[index] = val;\n"+
" }\n"+
" else";
}
serverCode +=
" if (type == SHUTDOWN) {\n"+
" running = false;\n"+
" }\n"+
" } catch (SocketTimeoutException e) {\n"+
" // nothing to do here just try receiving again\n"+
" } catch (Exception e) {\n"+
" }\n"+
" }\n"+
" socket.close();\n"+
" }\n"+
"}\n\n\n";
return serverCode;
}
}