List<LXParameter> gparams;
-class DualBlender extends SCEffect {
+ class DualBlender extends SCEffect {
int lastSeen;
BasicParameter p1 = new BasicParameter("p1", 0);
BasicParameter p2 = new BasicParameter("p2", 0);
if(p==p7) { gparams.get(6).setValue(p.getValuef()); }
if(p==p8) { gparams.get(7).setValue(p.getValuef()); }
}
-
+
void doApply(int[] colors){
- if(doDual==true){
+ if (enabled) {
//gplay.onActive();
gplay.go(millis()-lastSeen);
lastSeen=millis();
int unmapRow (int a) { return btwn(a,0 , 4) ? a+53 : a; }
void SetLight (int row, int col, int clr){ if (midiout != null) midiout.sendNoteOn(col, unmapRow(row), clr); }
void keypad (int row, int col) { println(row + " " + col); }
- void onInactive() { bIsActive=false; DanTextLine1 = ""; DanTextLine2 = "";}
+ void onInactive() { bIsActive=false; DanTextLine1 = ""; DanTextLine2 = ""; uiDebugText.setText(""); }
void onActive () { bIsActive=true;
zSpinHue = 0;
for (int i=0; i<paramlist.size(); i++) ((_DhP)paramlist.get(i)).reset();
DanTextLine2 = "SLIDERS: ";
for (int i=0; i<8; i++) if (SliderText[i] != "") { DanTextLine2 += SliderText[i] + ": " + Sliders[i] + " "; }
+
+ uiDebugText.setText(DanTextLine1, DanTextLine2);
}
void run(int deltaMs) {
return P;
}
}
-//----------------------------------------------------------------------------------------------------------------------------------\r
+//----------------------------------------------------------------------------------------------------------------------------------
}
public void doApply(int[] colors) {
+ if (!enabled) {
+ return;
+ }
float bMod = bright.getValuef();
float sMod = sat.getValuef();
float hMod = hueShift.getValuef();
return new LXEffect[] {
new FlashEffect(lx),
new BoomEffect(glucose),
- // new DesaturationEffect(lx),
- // new ColorFuckerEffect(glucose),
new DualBlender(glucose),
+ // new DesaturationEffect(lx),
+ new ColorFuckerEffect(glucose),
};
}
numChannels = pandaMappings.length * PandaMapping.CHANNELS_PER_BOARD;
setChannel();
}
+
+ public int numChannels() {
+ return numChannels;
+ }
private void setChannel() {
activePanda = pandaMappings[channelIndex / PandaMapping.CHANNELS_PER_BOARD];
switch (mappingMode) {
case MAPPING_MODE_ALL: cubeOn = true; break;
case MAPPING_MODE_SINGLE_CUBE: cubeOn = (cubeIndex == ci); break;
- case MAPPING_MODE_CHANNEL: cubeOn = (channelIndex > 0); break;
+ case MAPPING_MODE_CHANNEL: cubeOn = (indexOfCubeInChannel > 0); break;
}
if (cubeOn) {
if (mappingMode == MAPPING_MODE_CHANNEL) {
}
++ci;
}
-
+ }
+
+ public void setCube(int index) {
+ cubeIndex = index % model.cubes.size();
}
public void incCube() {
cubeIndex += model.cubes.size();
}
}
+
+ public void setChannel(int index) {
+ channelIndex = index % numChannels;
+ setChannel();
+ }
public void incChannel() {
channelIndex = (channelIndex + 1) % numChannels;
setChannel();
}
+ public void setStrip(int index) {
+ stripIndex = index % Cube.STRIPS_PER_CUBE;
+ }
+
public void incStrip() {
stripIndex = (stripIndex + 1) % Cube.STRIPS_PER_CUBE;
}
stripIndex = (stripIndex + Cube.STRIPS_PER_CUBE - 1) % Cube.STRIPS_PER_CUBE;
}
- public void keyPressed() {
+ public void keyPressed(UIMapping uiMapping) {
switch (keyCode) {
case UP: if (mappingMode == MAPPING_MODE_CHANNEL) incChannel(); else incCube(); break;
case DOWN: if (mappingMode == MAPPING_MODE_CHANNEL) decChannel(); else decCube(); break;
case 'g': channelModeGreen = !channelModeGreen; break;
case 'b': channelModeBlue = !channelModeBlue; break;
}
+ uiMapping.setChannelID(channelIndex+1);
+ uiMapping.setCubeID(cubeIndex+1);
+ uiMapping.setStripID(stripIndex+1);
+ uiMapping.redraw();
}
+
}
--- /dev/null
+/**
+ * DOUBLE BLACK DIAMOND DOUBLE BLACK DIAMOND
+ *
+ * //\\ //\\ //\\ //\\
+ * ///\\\ ///\\\ ///\\\ ///\\\
+ * \\\/// \\\/// \\\/// \\\///
+ * \\// \\// \\// \\//
+ *
+ * EXPERTS ONLY!! EXPERTS ONLY!!
+ *
+ * Overlay UI that indicates pattern control, etc. This will be moved
+ * into the Processing library once it is stabilized and need not be
+ * regularly modified.
+ */
+
+class DebugUI {
+
+ final ChannelMapping[] channelList;
+ final int debugX = 5;
+ final int debugY = 5;
+ final int debugXSpacing = 28;
+ final int debugYSpacing = 21;
+ final int[][] debugState;
+ final int[] indexState;
+
+ final int CUBE_STATE_UNUSED = 0;
+ final int CUBE_STATE_USED = 1;
+ final int CUBE_STATE_DUPLICATED = 2;
+
+ final int DEBUG_STATE_ANIM = 0;
+ final int DEBUG_STATE_WHITE = 1;
+ final int DEBUG_STATE_OFF = 2;
+ final int DEBUG_STATE_UNUSED = 3;
+
+ DebugUI(PandaMapping[] pandaMappings) {
+ int totalChannels = pandaMappings.length * PandaMapping.CHANNELS_PER_BOARD;
+ debugState = new int[totalChannels+1][ChannelMapping.CUBES_PER_CHANNEL+1];
+ indexState = new int[glucose.model.cubes.size()+1];
+
+ channelList = new ChannelMapping[totalChannels];
+ int channelIndex = 0;
+ for (PandaMapping pm : pandaMappings) {
+ for (ChannelMapping channel : pm.channelList) {
+ channelList[channelIndex++] = channel;
+ }
+ }
+ for (int i = 0; i < debugState.length; ++i) {
+ for (int j = 0; j < debugState[i].length; ++j) {
+ debugState[i][j] = DEBUG_STATE_ANIM;
+ }
+ }
+
+ for (int rawIndex = 0; rawIndex < glucose.model.cubes.size()+1; ++rawIndex) {
+ indexState[rawIndex] = CUBE_STATE_UNUSED;
+ }
+ for (ChannelMapping channel : channelList) {
+ for (int rawCubeIndex : channel.objectIndices) {
+ if (rawCubeIndex > 0)
+ ++indexState[rawCubeIndex];
+ }
+ }
+ }
+
+ void draw() {
+ noStroke();
+ int xBase = debugX;
+ int yPos = debugY;
+
+ textSize(10);
+
+ fill(#000000);
+ rect(0, 0, debugX + 5*debugXSpacing, height);
+
+ int channelNum = 0;
+ for (ChannelMapping channel : channelList) {
+ int xPos = xBase;
+ drawNumBox(xPos, yPos, channelNum+1, debugState[channelNum][0]);
+ xPos += debugXSpacing;
+
+ switch (channel.mode) {
+ case ChannelMapping.MODE_CUBES:
+ int stateIndex = 0;
+ boolean first = true;
+ for (int rawCubeIndex : channel.objectIndices) {
+ if (rawCubeIndex < 0) {
+ break;
+ }
+ if (first) {
+ first = false;
+ } else {
+ stroke(#999999);
+ line(xPos - 12, yPos + 8, xPos, yPos + 8);
+ }
+ drawNumBox(xPos, yPos, rawCubeIndex, debugState[channelNum][stateIndex+1], indexState[rawCubeIndex]);
+ ++stateIndex;
+ xPos += debugXSpacing;
+ }
+ break;
+ case ChannelMapping.MODE_BASS:
+ drawNumBox(xPos, yPos, "B", debugState[channelNum][1]);
+ break;
+ case ChannelMapping.MODE_SPEAKER:
+ drawNumBox(xPos, yPos, "S" + channel.objectIndices[0], debugState[channelNum][1]);
+ break;
+ case ChannelMapping.MODE_STRUTS_AND_FLOOR:
+ drawNumBox(xPos, yPos, "F", debugState[channelNum][1]);
+ break;
+ case ChannelMapping.MODE_NULL:
+ break;
+ default:
+ throw new RuntimeException("Unhandled channel mapping mode: " + channel.mode);
+ }
+
+ yPos += debugYSpacing;
+ ++channelNum;
+ }
+ drawNumBox(xBase, yPos, "A", debugState[channelNum][0]);
+ yPos += debugYSpacing * 2;
+
+ noFill();
+ fill(#CCCCCC);
+ text("Unused Cubes", xBase, yPos + 12);
+ yPos += debugYSpacing;
+
+ int xIndex = 0;
+ for (int rawIndex = 1; rawIndex <= glucose.model.cubes.size(); ++rawIndex) {
+ if (indexState[rawIndex] == CUBE_STATE_UNUSED) {
+ drawNumBox(xBase + (xIndex * debugXSpacing), yPos, rawIndex, DEBUG_STATE_UNUSED);
+ ++xIndex;
+ if (xIndex > 4) {
+ xIndex = 0;
+ yPos += debugYSpacing + 2;
+ }
+ }
+ }
+ }
+
+
+ void drawNumBox(int xPos, int yPos, int label, int state) {
+ drawNumBox(xPos, yPos, "" + label, state);
+ }
+
+ void drawNumBox(int xPos, int yPos, String label, int state) {
+ drawNumBox(xPos, yPos, "" + label, state, CUBE_STATE_USED);
+ }
+
+ void drawNumBox(int xPos, int yPos, int label, int state, int cubeState) {
+ drawNumBox(xPos, yPos, "" + label, state, cubeState);
+ }
+
+ void drawNumBox(int xPos, int yPos, String label, int state, int cubeState) {
+ noFill();
+ color textColor = #cccccc;
+ switch (state) {
+ case DEBUG_STATE_ANIM:
+ noStroke();
+ fill(#880000);
+ rect(xPos, yPos, 16, 8);
+ fill(#000088);
+ rect(xPos, yPos+8, 16, 8);
+ noFill();
+ stroke(textColor);
+ break;
+ case DEBUG_STATE_WHITE:
+ stroke(textColor);
+ fill(#e9e9e9);
+ textColor = #333333;
+ break;
+ case DEBUG_STATE_OFF:
+ stroke(textColor);
+ break;
+ case DEBUG_STATE_UNUSED:
+ stroke(textColor);
+ fill(#880000);
+ break;
+ }
+
+ if (cubeState >= CUBE_STATE_DUPLICATED) {
+ stroke(textColor = #FF0000);
+ }
+
+ rect(xPos, yPos, 16, 16);
+ noStroke();
+ fill(textColor);
+ text(label, xPos + 2, yPos + 12);
+ }
+
+ void maskColors(color[] colors) {
+ color white = #FFFFFF;
+ color off = #000000;
+ int channelIndex = 0;
+ int state;
+ for (ChannelMapping channel : channelList) {
+ switch (channel.mode) {
+ case ChannelMapping.MODE_CUBES:
+ int cubeIndex = 1;
+ for (int rawCubeIndex : channel.objectIndices) {
+ if (rawCubeIndex >= 0) {
+ state = debugState[channelIndex][cubeIndex];
+ if (state != DEBUG_STATE_ANIM) {
+ color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
+ Cube cube = glucose.model.getCubeByRawIndex(rawCubeIndex);
+ for (Point p : cube.points) {
+ colors[p.index] = debugColor;
+ }
+ }
+ }
+ ++cubeIndex;
+ }
+ break;
+
+ case ChannelMapping.MODE_BASS:
+ state = debugState[channelIndex][1];
+ if (state != DEBUG_STATE_ANIM) {
+ color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
+ for (Strip s : glucose.model.bassBox.boxStrips) {
+ for (Point p : s.points) {
+ colors[p.index] = debugColor;
+ }
+ }
+ }
+ break;
+
+ case ChannelMapping.MODE_STRUTS_AND_FLOOR:
+ state = debugState[channelIndex][1];
+ if (state != DEBUG_STATE_ANIM) {
+ color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
+ for (Point p : glucose.model.boothFloor.points) {
+ colors[p.index] = debugColor;
+ }
+ for (Strip s : glucose.model.bassBox.struts) {
+ for (Point p : s.points) {
+ colors[p.index] = debugColor;
+ }
+ }
+ }
+ break;
+
+ case ChannelMapping.MODE_SPEAKER:
+ state = debugState[channelIndex][1];
+ if (state != DEBUG_STATE_ANIM) {
+ color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
+ for (Point p : glucose.model.speakers.get(channel.objectIndices[0]).points) {
+ colors[p.index] = debugColor;
+ }
+ }
+ break;
+
+ case ChannelMapping.MODE_NULL:
+ break;
+
+ default:
+ throw new RuntimeException("Unhandled channel mapping mode: " + channel.mode);
+ }
+ ++channelIndex;
+ }
+ }
+
+ boolean mousePressed() {
+ int dx = (mouseX - debugX) / debugXSpacing;
+ int dy = (mouseY - debugY) / debugYSpacing;
+ if ((dy < 0) || (dy >= debugState.length)) {
+ return false;
+ }
+ if ((dx < 0) || (dx >= debugState[dy].length)) {
+ return false;
+ }
+ int newState = debugState[dy][dx] = (debugState[dy][dx] + 1) % 3;
+ if (dy == debugState.length-1) {
+ for (int[] states : debugState) {
+ for (int i = 0; i < states.length; ++i) {
+ states[i] = newState;
+ }
+ }
+ } else if (dx == 0) {
+ for (int i = 0; i < debugState[dy].length; ++i) {
+ debugState[dy][i] = newState;
+ }
+ }
+ return true;
+ }
+}
+
LXPattern[] patterns;
LXTransition[] transitions;
LXEffect[] effects;
-OverlayUI ui;
-ControlUI controlUI;
-MappingUI mappingUI;
PandaDriver[] pandaBoards;
boolean mappingMode = false;
boolean debugMode = false;
DebugUI debugUI;
+String displayMode;
+
+UIContext[] overlays;
+UIPatternDeck uiPatternA;
+UIMapping uiMapping;
+UIDebugText uiDebugText;
// Camera variables
float eyeR, eyeA, eyeX, eyeY, eyeZ, midX, midY, midZ;
+LXPattern[] _patterns(GLucose glucose) {
+ LXPattern[] patterns = patterns(glucose);
+ for (LXPattern p : patterns) {
+ p.setTransition(new DissolveTransition(glucose.lx).setDuration(1000));
+ }
+ return patterns;
+}
+
void setup() {
startMillis = lastMillis = millis();
logTime("Built GLucose engine");
// Set the patterns
- glucose.lx.setPatterns(patterns = patterns(glucose));
+ Engine engine = lx.engine;
+ glucose.setTransitions(transitions = transitions(glucose));
+ logTime("Built transitions");
+ engine.setPatterns(patterns = _patterns(glucose));
+ engine.addDeck(_patterns(glucose));
+ engine.getDeck(1).setBlendTransition(transitions[0]);
logTime("Built patterns");
glucose.lx.addEffects(effects = effects(glucose));
logTime("Built effects");
- glucose.setTransitions(transitions = transitions(glucose));
- logTime("Built transitions");
// Build output driver
PandaMapping[] pandaMappings = buildPandaList();
logTime("Built PandaDriver");
// Build overlay UI
- ui = controlUI = new ControlUI();
- mappingUI = new MappingUI(mappingTool);
debugUI = new DebugUI(pandaMappings);
+ overlays = new UIContext[] {
+ uiPatternA = new UIPatternDeck(lx.engine.getDeck(0), "PATTERN A", 4, 4, 140, 344),
+ new UICrossfader(4, 352, 140, 152),
+ new UIOutput(4, 508, 140, 122),
+
+ new UIPatternDeck(lx.engine.getDeck(1), "PATTERN B", width-144, 4, 140, 344),
+ new UIEffects(width-144, 352, 140, 144),
+ new UITempo(width-144, 498, 140, 50),
+
+ uiDebugText = new UIDebugText(4, height-64, width-8, 44),
+ uiMapping = new UIMapping(mappingTool, 4, 4, 140, 344),
+ };
+ uiMapping.setVisible(false);
logTime("Built overlay UI");
// MIDI devices
logTime("Setup MIDI devices");
// Setup camera
- midX = TRAILER_WIDTH/2. + 20;
+ midX = TRAILER_WIDTH/2.;
midY = glucose.model.yMax/2;
midZ = TRAILER_DEPTH/2.;
eyeR = -290;
eyeA = .15;
- eyeY = midY + 20;
+ eyeY = midY + 70;
eyeX = midX + eyeR*sin(eyeA);
eyeZ = midZ + eyeR*cos(eyeA);
addMouseWheelListener(new java.awt.event.MouseWheelListener() {
void draw() {
// Draws the simulation and the 2D UI overlay
background(40);
- color[] colors = glucose.getColors();
+ color[] colors = glucose.getColors();;
+ if (displayMode == "A") {
+ colors = lx.engine.getDeck(0).getColors();
+ } else if (displayMode == "B") {
+ colors = lx.engine.getDeck(1).getColors();
+ }
if (debugMode) {
debugUI.maskColors(colors);
}
0, -1, 0
);
+ translate(0, 10, 0);
+
noStroke();
fill(#141414);
drawBox(0, -TRAILER_HEIGHT, 0, 0, 0, 0, TRAILER_WIDTH, TRAILER_HEIGHT, TRAILER_DEPTH, TRAILER_HEIGHT/2.);
}
endShape();
- // 2D Overlay
- camera();
- javax.media.opengl.GL gl = ((PGraphicsOpenGL)g).beginGL();
- gl.glClear(javax.media.opengl.GL.GL_DEPTH_BUFFER_BIT);
- ((PGraphicsOpenGL)g).endGL();
- strokeWeight(1);
+ // 2D Overlay UI
drawUI();
-
+
+ // Send output colors
+ color[] sendColors = glucose.getColors();
if (debugMode) {
- debugUI.draw();
+ debugUI.maskColors(colors);
}
// Gamma correction here. Apply a cubic to the brightness
}
void drawUI() {
+ camera();
+ javax.media.opengl.GL gl = ((PGraphicsOpenGL)g).beginGL();
+ gl.glClear(javax.media.opengl.GL.GL_DEPTH_BUFFER_BIT);
+ ((PGraphicsOpenGL)g).endGL();
+ strokeWeight(1);
+
if (uiOn) {
- ui.draw();
- } else {
- ui.drawHelpTip();
+ for (UIContext context : overlays) {
+ context.draw();
+ }
+ }
+
+ // Always draw FPS meter
+ fill(#555555);
+ textSize(9);
+ textAlign(LEFT, BASELINE);
+ text("FPS: " + ((int) (frameRate*10)) / 10. + " / " + targetFramerate + " (-/+)", 4, height-4);
+
+ if (debugMode) {
+ debugUI.draw();
}
- ui.drawFPS();
- ui.drawDanText();
}
boolean uiOn = true;
-int restoreToIndex = -1;
-
-boolean doDual = false;
+LXPattern restoreToPattern = null;
void keyPressed() {
if (mappingMode) {
- mappingTool.keyPressed();
+ mappingTool.keyPressed(uiMapping);
}
switch (key) {
- case 'w':
- doDual = !doDual;
- break;
case '-':
case '_':
frameRate(--targetFramerate);
break;
case 'm':
mappingMode = !mappingMode;
+ uiPatternA.setVisible(!mappingMode);
+ uiMapping.setVisible(mappingMode);
if (mappingMode) {
- LXPattern pattern = lx.getPattern();
- for (int i = 0; i < patterns.length; ++i) {
- if (pattern == patterns[i]) {
- restoreToIndex = i;
- break;
- }
- }
- ui = mappingUI;
+ restoreToPattern = lx.getPattern();
lx.setPatterns(new LXPattern[] { mappingTool });
} else {
- ui = controlUI;
lx.setPatterns(patterns);
- lx.goIndex(restoreToIndex);
+ lx.goPattern(restoreToPattern);
}
break;
case 'p':
int mx, my;
void mousePressed() {
- ui.mousePressed();
- if (mouseX < ui.leftPos) {
- if (debugMode) {
- debugUI.mousePressed();
- }
- mx = mouseX;
- my = mouseY;
+ boolean debugged = false;
+ if (debugMode) {
+ debugged = debugUI.mousePressed();
+ }
+ if (!debugged) {
+ for (UIContext context : overlays) {
+ context.mousePressed(mouseX, mouseY);
+ }
}
+ mx = mouseX;
+ my = mouseY;
}
void mouseDragged() {
- if (mouseX > ui.leftPos) {
- ui.mouseDragged();
- } else {
+ boolean dragged = false;
+ for (UIContext context : overlays) {
+ dragged |= context.mouseDragged(mouseX, mouseY);
+ }
+ if (!dragged) {
int dx = mouseX - mx;
int dy = mouseY - my;
mx = mouseX;
}
void mouseReleased() {
- ui.mouseReleased();
+ for (UIContext context : overlays) {
+ context.mouseReleased(mouseX, mouseY);
+ }
+
+ // ui.mouseReleased();
}
void mouseWheel(int delta) {
- if (mouseX > ui.leftPos) {
- ui.mouseWheel(delta);
- } else {
+ boolean wheeled = false;
+ for (UIContext context : overlays) {
+ wheeled |= context.mouseWheel(mouseX, mouseY, delta);
+ }
+
+ if (!wheeled) {
eyeR = constrain(eyeR - delta, -500, -80);
eyeX = midX + eyeR*sin(eyeA);
eyeZ = midZ + eyeR*cos(eyeA);
+++ /dev/null
-import java.lang.reflect.*;
-
-/**
- * DOUBLE BLACK DIAMOND DOUBLE BLACK DIAMOND
- *
- * //\\ //\\ //\\ //\\
- * ///\\\ ///\\\ ///\\\ ///\\\
- * \\\/// \\\/// \\\/// \\\///
- * \\// \\// \\// \\//
- *
- * EXPERTS ONLY!! EXPERTS ONLY!!
- *
- * Overlay UI that indicates pattern control, etc. This will be moved
- * into the Processing library once it is stabilized and need not be
- * regularly modified.
- */
-abstract class OverlayUI {
- protected final PFont titleFont = createFont("Myriad Pro", 10);
- protected final color titleColor = #AAAAAA;
- protected final PFont itemFont = createFont("Lucida Grande", 11);
- protected final PFont knobFont = titleFont;
- protected final int w = 140;
- protected final int leftPos;
- protected final int leftTextPos;
- protected final int lineHeight = 20;
- protected final int sectionSpacing = 12;
- protected final int controlSpacing = 18;
- protected final int tempoHeight = 20;
- protected final int knobSize = 28;
- protected final float knobIndent = .4;
- protected final int knobSpacing = 6;
- protected final int knobLabelHeight = 14;
- protected final int scrollWidth = 14;
- protected final color lightBlue = #666699;
- protected final color lightGreen = #669966;
- protected final int toggleButtonSize = 10;
-
- private PImage logo;
-
- protected final int STATE_DEFAULT = 0;
- protected final int STATE_ACTIVE = 1;
- protected final int STATE_PENDING = 2;
-
- protected int[] pandaLeft = new int[pandaBoards.length];
- protected final int pandaWidth = 64;
- protected final int pandaHeight = 13;
- protected final int pandaTop = height-16;
-
- protected int eligibleLeft;
-
- protected OverlayUI() {
- leftPos = width - w;
- leftTextPos = leftPos + 4;
- logo = loadImage("logo-sm.png");
- }
-
- protected void drawLogoAndBackground() {
- image(logo, 4, 4);
- stroke(color(0, 0, 100));
- // fill(color(0, 0, 50, 50)); // alpha is bad for perf
- fill(color(0, 0, 30));
- rect(leftPos-1, -1, w+2, height+2);
- }
-
- protected void drawToggleTip(String s) {
- fill(#999999);
- textFont(itemFont);
- textAlign(LEFT);
- text(s, leftTextPos, height-6);
- }
-
- protected void drawHelpTip() {
- textFont(itemFont);
- textAlign(RIGHT);
- text("Tap 'u' to restore UI", width-4, height-6);
- }
-
- public void drawDanText() {
- textFont(itemFont);
- textAlign(LEFT);
- fill(#FFFFFF);
- text(DanTextLine1, 4, height-50);
- text(DanTextLine2, 4, height-30);
- }
-
- public void drawFPS() {
- textFont(titleFont);
- textAlign(LEFT);
- noStroke();
- fill(#666666);
- int lPos = 4;
- String fps = "FPS: " + (((int)(frameRate * 10)) / 10.);
- text(fps, lPos, height-6);
- lPos += 48;
-
- String target = "Target (-/+):";
- text(target, lPos, height-6);
- fill(#000000);
- lPos += textWidth(target) + 4;
- rect(lPos, height-16, 24, 13);
- fill(#666666);
- text("" + targetFramerate, lPos + (24 - textWidth("" + targetFramerate))/2, height-6);
- lPos += 32;
- String pandaOutput = "PandaOutput (p):";
- text(pandaOutput, lPos, height-6);
- lPos += textWidth(pandaOutput)+4;
- int pi = 0;
- for (PandaDriver p : pandaBoards) {
- pandaLeft[pi++] = lPos;
- fill(p.enabled ? #666666 : #000000);
- rect(lPos, pandaTop, pandaWidth, pandaHeight);
- fill(p.enabled ? #000000 : #666666);
- text(p.ip, lPos + (pandaWidth - textWidth(p.ip)) / 2, height-6);
- lPos += pandaWidth + 8;
- }
-
- }
-
- protected int drawObjectList(int yPos, String title, Object[] items, Method stateMethod) {
- int sz = (items != null) ? items.length : 0;
- return drawObjectList(yPos, title, items, stateMethod, sz, 0);
- }
-
- protected int drawObjectList(int yPos, String title, Object[] items, Method stateMethod, int scrollLength, int scrollPos) {
- return drawObjectList(yPos, title, items, classNameArray(items, null), stateMethod, scrollLength, scrollPos);
- }
-
- protected int drawObjectList(int yPos, String title, Object[] items, String[] names, Method stateMethod) {
- int sz = (items != null) ? items.length : 0;
- return drawObjectList(yPos, title, items, names, stateMethod, sz, 0);
- }
-
- protected void drawToggleButton(float x, float y, boolean eligible, color textColor) {
- noFill();
- stroke(textColor);
- rect(x, y, toggleButtonSize, toggleButtonSize);
- if (eligible) {
- noStroke();
- fill(textColor);
- rect(x + 2, y + 2, toggleButtonSize - 4, toggleButtonSize - 4);
- }
- }
-
- protected int drawObjectList(int yPos, String title, Object[] items, String[] names, Method stateMethod, int scrollLength, int scrollPos) {
- noStroke();
- fill(titleColor);
- textFont(titleFont);
- textAlign(LEFT);
- text(title, leftTextPos, yPos += lineHeight);
- if (items != null) {
- boolean hasScroll = (scrollPos > 0) || (scrollLength < items.length);
- textFont(itemFont);
- color textColor;
- boolean even = true;
- int yTop = yPos+6;
- for (int i = scrollPos; i < items.length && i < (scrollPos + scrollLength); ++i) {
- Object o = items[i];
- int state = STATE_DEFAULT;
- try {
- state = ((Integer) stateMethod.invoke(this, o)).intValue();
- } catch (Exception x) {
- throw new RuntimeException(x);
- }
- switch (state) {
- case STATE_ACTIVE:
- fill(lightGreen);
- textColor = #eeeeee;
- break;
- case STATE_PENDING:
- fill(lightBlue);
- textColor = color(0, 0, 75 + 15*sin(millis()/200.));;
- break;
- default:
- textColor = 0;
- fill(even ? #666666 : #777777);
- break;
- }
- noStroke();
- rect(leftPos, yPos+6, w, lineHeight);
- fill(textColor);
- text(names[i], leftTextPos, yPos += lineHeight);
- if (lx.isAutoTransitionEnabled() && items[i] instanceof LXPattern) {
- boolean eligible = ((LXPattern)items[i]).isEligible();
- eligibleLeft = leftPos + w - (hasScroll ? scrollWidth : 0) - 15;
- drawToggleButton(eligibleLeft, yPos-8, eligible, textColor);
- }
- even = !even;
- }
- if (hasScroll) {
- int yHere = yPos+6;
- noStroke();
- fill(color(0, 0, 0, 50));
- rect(leftPos + w - scrollWidth, yTop, scrollWidth, yHere - yTop);
- fill(#666666);
- rect(leftPos + w - scrollWidth + 2, yTop + (yHere-yTop) * (scrollPos / (float)items.length), scrollWidth - 4, (yHere - yTop) * (scrollLength / (float)items.length));
-
- }
-
- }
- return yPos;
- }
-
- protected String[] classNameArray(Object[] objects, String suffix) {
- if (objects == null) {
- return null;
- }
- String[] names = new String[objects.length];
- for (int i = 0; i < objects.length; ++i) {
- names[i] = className(objects[i], suffix);
- }
- return names;
- }
-
- protected String className(Object p, String suffix) {
- String s = p.getClass().getName();
- int li;
- if ((li = s.lastIndexOf(".")) > 0) {
- s = s.substring(li + 1);
- }
- if (s.indexOf("SugarCubes$") == 0) {
- s = s.substring("SugarCubes$".length());
- }
- if ((suffix != null) && ((li = s.indexOf(suffix)) != -1)) {
- s = s.substring(0, li);
- }
- return s;
- }
-
- protected int objectClickIndex(int firstItemY) {
- return (mouseY - firstItemY) / lineHeight;
- }
-
- abstract public void draw();
- abstract public void mousePressed();
- abstract public void mouseDragged();
- abstract public void mouseReleased();
- abstract public void mouseWheel(int delta);
-}
-
-/**
- * UI for control of patterns, transitions, effects.
- */
-class ControlUI extends OverlayUI {
- private final String[] patternNames;
- private final String[] transitionNames;
- private final String[] effectNames;
-
- private int firstPatternY;
- private int firstPatternKnobY;
- private int firstTransitionY;
- private int firstTransitionKnobY;
- private int firstEffectY;
- private int firstEffectKnobY;
-
- private int autoRotateX;
- private int autoRotateY;
-
- private final int PATTERN_LIST_LENGTH = 8;
- private int patternScrollPos = 0;
-
- private int tempoY;
-
- private Method patternStateMethod;
- private Method transitionStateMethod;
- private Method effectStateMethod;
-
- ControlUI() {
- patternNames = classNameArray(patterns, "Pattern");
- transitionNames = classNameArray(transitions, "Transition");
- effectNames = classNameArray(effects, "Effect");
-
- try {
- patternStateMethod = getClass().getMethod("getState", LXPattern.class);
- effectStateMethod = getClass().getMethod("getState", LXEffect.class);
- transitionStateMethod = getClass().getMethod("getState", LXTransition.class);
- } catch (Exception x) {
- throw new RuntimeException(x);
- }
- }
-
- public void draw() {
- drawLogoAndBackground();
- int yPos = 0;
- autoRotateX = leftPos + w - 29;
- autoRotateY = yPos + 12;
- drawToggleButton(autoRotateX, autoRotateY, lx.isAutoTransitionEnabled(), #999999);
- fill(lx.isAutoTransitionEnabled() ? #222222: #999999);
- text("A", autoRotateX + 2, autoRotateY + 9);
- firstPatternY = yPos + lineHeight + 6;
- yPos = drawObjectList(yPos, "PATTERN", patterns, patternNames, patternStateMethod, PATTERN_LIST_LENGTH, patternScrollPos);
- yPos += controlSpacing;
- firstPatternKnobY = yPos;
- int xPos = leftTextPos;
- for (int i = 0; i < glucose.NUM_PATTERN_KNOBS/2; ++i) {
- drawKnob(xPos, yPos, knobSize, glucose.patternKnobs.get(i));
- drawKnob(xPos, yPos + knobSize + knobSpacing + knobLabelHeight, knobSize, glucose.patternKnobs.get(glucose.NUM_PATTERN_KNOBS/2 + i));
- xPos += knobSize + knobSpacing;
- }
- yPos += 2*(knobSize + knobLabelHeight) + knobSpacing;
-
- yPos += sectionSpacing;
- firstTransitionY = yPos + lineHeight + 6;
- yPos = drawObjectList(yPos, "TRANSITION", transitions, transitionNames, transitionStateMethod);
- yPos += controlSpacing;
- firstTransitionKnobY = yPos;
- xPos = leftTextPos;
- for (VirtualTransitionKnob knob : glucose.transitionKnobs) {
- drawKnob(xPos, yPos, knobSize, knob);
- xPos += knobSize + knobSpacing;
- }
- yPos += knobSize + knobLabelHeight;
-
- yPos += sectionSpacing;
- firstEffectY = yPos + lineHeight + 6;
- yPos = drawObjectList(yPos, "FX", effects, effectNames, effectStateMethod);
- yPos += controlSpacing;
- firstEffectKnobY = yPos;
- xPos = leftTextPos;
- for (VirtualEffectKnob knob : glucose.effectKnobs) {
- drawKnob(xPos, yPos, knobSize, knob);
- xPos += knobSize + knobSpacing;
- }
- yPos += knobSize + knobLabelHeight;
-
- yPos += sectionSpacing;
- yPos = drawObjectList(yPos, "TEMPO", null, null, null);
- yPos += 6;
- tempoY = yPos;
- stroke(#111111);
- fill(tempoDown ? lightGreen : color(0, 0, 35 - 8*lx.tempo.rampf()));
- rect(leftPos + 4, yPos, w - 8, tempoHeight);
- fill(0);
- textAlign(CENTER);
- text("" + ((int)(lx.tempo.bpmf() * 100) / 100.), leftPos + w/2., yPos + tempoHeight - 6);
- yPos += tempoHeight;
-
- drawToggleTip("Tap 'u' to hide");
- }
-
- public LXParameter getOrNull(List<LXParameter> items, int index) {
- if (index < items.size()) {
- return items.get(index);
- }
- return null;
- }
-
- public int getState(LXPattern p) {
- if (p == lx.getPattern()) {
- return STATE_ACTIVE;
- } else if (p == lx.getNextPattern()) {
- return STATE_PENDING;
- }
- return STATE_DEFAULT;
- }
-
- public int getState(LXEffect e) {
- if (e.isEnabled()) {
- return STATE_PENDING;
- } else if (e == glucose.getSelectedEffect()) {
- return STATE_ACTIVE;
- }
- return STATE_DEFAULT;
- }
-
- public int getState(LXTransition t) {
- if (t == lx.getTransition()) {
- return STATE_PENDING;
- } else if (t == glucose.getSelectedTransition()) {
- return STATE_ACTIVE;
- }
- return STATE_DEFAULT;
- }
-
- private void drawKnob(int xPos, int yPos, int knobSize, LXParameter knob) {
- final float knobValue = knob.getValuef();
- String knobLabel = knob.getLabel();
- if (knobLabel == null) {
- knobLabel = "-";
- } else if (knobLabel.length() > 4) {
- knobLabel = knobLabel.substring(0, 4);
- }
-
- ellipseMode(CENTER);
- noStroke();
- fill(#222222);
- // For some reason this arc call really crushes drawing performance. Presumably
- // because openGL is drawing it and when we overlap the second set of arcs it
- // does a bunch of depth buffer intersection tests? Ellipse with a trapezoid cut out is faster
- // arc(xPos + knobSize/2, yPos + knobSize/2, knobSize, knobSize, HALF_PI + knobIndent, HALF_PI + knobIndent + (TWO_PI-2*knobIndent));
- ellipse(xPos + knobSize/2, yPos + knobSize/2, knobSize, knobSize);
-
- float endArc = HALF_PI + knobIndent + (TWO_PI-2*knobIndent)*knobValue;
- fill(lightGreen);
- arc(xPos + knobSize/2, yPos + knobSize/2, knobSize, knobSize, HALF_PI + knobIndent, endArc);
-
- // Mask notch out of knob
- fill(color(0, 0, 30));
- beginShape();
- vertex(xPos + knobSize/2, yPos + knobSize/2.);
- vertex(xPos + knobSize/2 - 6, yPos + knobSize);
- vertex(xPos + knobSize/2 + 6, yPos + knobSize);
- endShape();
-
- // Center circle of knob
- fill(#333333);
- ellipse(xPos + knobSize/2, yPos + knobSize/2, knobSize/2, knobSize/2);
-
- fill(0);
- rect(xPos, yPos + knobSize + 2, knobSize, knobLabelHeight - 2);
- fill(#999999);
- textAlign(CENTER);
- textFont(knobFont);
- text(knobLabel, xPos + knobSize/2, yPos + knobSize + knobLabelHeight - 2);
- }
-
- private int patternKnobIndex = -1;
- private int transitionKnobIndex = -1;
- private int effectKnobIndex = -1;
- private boolean patternScrolling = false;
-
- private int lastY;
- private int releaseEffect = -1;
- private boolean tempoDown = false;
-
- public void mousePressed() {
- lastY = mouseY;
- patternKnobIndex = transitionKnobIndex = effectKnobIndex = -1;
- releaseEffect = -1;
- patternScrolling = false;
-
- for (int p = 0; p < pandaLeft.length; ++p) {
- int xp = pandaLeft[p];
- if ((mouseX >= xp) &&
- (mouseX < xp + pandaWidth) &&
- (mouseY >= pandaTop) &&
- (mouseY < pandaTop + pandaHeight)) {
- pandaBoards[p].toggle();
- }
- }
-
- if (mouseX < leftPos) {
- return;
- }
-
- if ((mouseX >= autoRotateX) &&
- (mouseX < autoRotateX + toggleButtonSize) &&
- (mouseY >= autoRotateY) &&
- (mouseY < autoRotateY + toggleButtonSize)) {
- if (lx.isAutoTransitionEnabled()) {
- lx.disableAutoTransition();
- println("Auto pattern transition disabled");
- } else {
- lx.enableAutoTransition(60000);
- println("Auto pattern transition enabled");
- }
- return;
- }
-
- if (mouseY > tempoY) {
- if (mouseY - tempoY < tempoHeight) {
- lx.tempo.tap();
- tempoDown = true;
- }
- } else if ((mouseY >= firstEffectKnobY) && (mouseY < firstEffectKnobY + knobSize + knobLabelHeight)) {
- effectKnobIndex = (mouseX - leftTextPos) / (knobSize + knobSpacing);
- } else if (mouseY > firstEffectY) {
- int effectIndex = objectClickIndex(firstEffectY);
- if (effectIndex < effects.length) {
- if (effects[effectIndex] == glucose.getSelectedEffect()) {
- effects[effectIndex].enable();
- releaseEffect = effectIndex;
- }
- glucose.setSelectedEffect(effectIndex);
- }
- } else if ((mouseY >= firstTransitionKnobY) && (mouseY < firstTransitionKnobY + knobSize + knobLabelHeight)) {
- transitionKnobIndex = (mouseX - leftTextPos) / (knobSize + knobSpacing);
- } else if (mouseY > firstTransitionY) {
- int transitionIndex = objectClickIndex(firstTransitionY);
- if (transitionIndex < transitions.length) {
- glucose.setSelectedTransition(transitionIndex);
- }
- } else if ((mouseY >= firstPatternKnobY) && (mouseY < firstPatternKnobY + 2*(knobSize+knobLabelHeight) + knobSpacing)) {
- patternKnobIndex = (mouseX - leftTextPos) / (knobSize + knobSpacing);
- if (mouseY >= firstPatternKnobY + knobSize + knobLabelHeight + knobSpacing) {
- patternKnobIndex += glucose.NUM_PATTERN_KNOBS / 2;
- }
- } else if (mouseY > firstPatternY) {
- if ((patterns.length > PATTERN_LIST_LENGTH) && (mouseX > width - scrollWidth)) {
- patternScrolling = true;
- } else {
- int patternIndex = objectClickIndex(firstPatternY);
- if (patternIndex < patterns.length) {
- if (lx.isAutoTransitionEnabled() && (mouseX > eligibleLeft)) {
- patterns[patternIndex + patternScrollPos].toggleEligible();
- } else {
- lx.goIndex(patternIndex + patternScrollPos);
- }
- }
- }
- }
- }
-
- int scrolldy = 0;
- public void mouseDragged() {
- int dy = lastY - mouseY;
- scrolldy += dy;
- lastY = mouseY;
- if (patternKnobIndex >= 0 && patternKnobIndex < glucose.NUM_PATTERN_KNOBS) {
- LXParameter p = glucose.patternKnobs.get(patternKnobIndex);
- p.setValue(constrain(p.getValuef() + dy*.01, 0, 1));
- } else if (effectKnobIndex >= 0 && effectKnobIndex < glucose.NUM_EFFECT_KNOBS) {
- LXParameter p = glucose.effectKnobs.get(effectKnobIndex);
- p.setValue(constrain(p.getValuef() + dy*.01, 0, 1));
- } else if (transitionKnobIndex >= 0 && transitionKnobIndex < glucose.NUM_TRANSITION_KNOBS) {
- LXParameter p = glucose.transitionKnobs.get(transitionKnobIndex);
- p.setValue(constrain(p.getValuef() + dy*.01, 0, 1));
- } else if (patternScrolling) {
- int scroll = scrolldy / lineHeight;
- scrolldy = scrolldy % lineHeight;
- patternScrollPos = constrain(patternScrollPos - scroll, 0, patterns.length - PATTERN_LIST_LENGTH);
- }
- }
-
- public void mouseReleased() {
- patternScrolling = false;
- tempoDown = false;
- if (releaseEffect >= 0) {
- effects[releaseEffect].trigger();
- releaseEffect = -1;
- }
- }
-
- public void mouseWheel(int delta) {
- if (mouseY > firstPatternY) {
- int patternIndex = objectClickIndex(firstPatternY);
- if (patternIndex < PATTERN_LIST_LENGTH) {
- patternScrollPos = constrain(patternScrollPos + delta, 0, patterns.length - PATTERN_LIST_LENGTH);
- }
- }
- }
-
-}
-
-/**
- * UI for control of mapping.
- */
-class MappingUI extends OverlayUI {
-
- private MappingTool mappingTool;
-
- private final String MAPPING_MODE_ALL = "All On";
- private final String MAPPING_MODE_CHANNEL = "Channel";
- private final String MAPPING_MODE_SINGLE_CUBE = "Single Cube";
-
- private final String[] mappingModes = {
- MAPPING_MODE_ALL,
- MAPPING_MODE_CHANNEL,
- MAPPING_MODE_SINGLE_CUBE
- };
- private final Method mappingModeStateMethod;
-
- private final String CUBE_MODE_ALL = "All Strips";
- private final String CUBE_MODE_SINGLE_STRIP = "Single Strip";
- private final String CUBE_MODE_STRIP_PATTERN = "Strip Pattern";
- private final String[] cubeModes = {
- CUBE_MODE_ALL,
- CUBE_MODE_SINGLE_STRIP,
- CUBE_MODE_STRIP_PATTERN
- };
- private final Method cubeModeStateMethod;
-
- private final String CHANNEL_MODE_RED = "Red";
- private final String CHANNEL_MODE_GREEN = "Green";
- private final String CHANNEL_MODE_BLUE = "Blue";
- private final String[] channelModes = {
- CHANNEL_MODE_RED,
- CHANNEL_MODE_GREEN,
- CHANNEL_MODE_BLUE,
- };
- private final Method channelModeStateMethod;
-
- private int firstMappingY;
- private int firstCubeY;
- private int firstChannelY;
- private int channelFieldY;
- private int cubeFieldY;
- private int stripFieldY;
-
- private boolean dragCube;
- private boolean dragStrip;
- private boolean dragChannel;
-
- MappingUI(MappingTool mappingTool) {
- this.mappingTool = mappingTool;
- try {
- mappingModeStateMethod = getClass().getMethod("getMappingState", Object.class);
- channelModeStateMethod = getClass().getMethod("getChannelState", Object.class);
- cubeModeStateMethod = getClass().getMethod("getCubeState", Object.class);
- } catch (Exception x) {
- throw new RuntimeException(x);
- }
- }
-
- public int getMappingState(Object mappingMode) {
- boolean active = false;
- if (mappingMode == MAPPING_MODE_ALL) {
- active = mappingTool.mappingMode == mappingTool.MAPPING_MODE_ALL;
- } else if (mappingMode == MAPPING_MODE_CHANNEL) {
- active = mappingTool.mappingMode == mappingTool.MAPPING_MODE_CHANNEL;
- } else if (mappingMode == MAPPING_MODE_SINGLE_CUBE) {
- active = mappingTool.mappingMode == mappingTool.MAPPING_MODE_SINGLE_CUBE;
- }
- return active ? STATE_ACTIVE : STATE_DEFAULT;
- }
-
- public int getChannelState(Object channelMode) {
- boolean active = false;
- if (channelMode == CHANNEL_MODE_RED) {
- active = mappingTool.channelModeRed;
- } else if (channelMode == CHANNEL_MODE_GREEN) {
- active = mappingTool.channelModeGreen;
- } else if (channelMode == CHANNEL_MODE_BLUE) {
- active = mappingTool.channelModeBlue;
- }
- return active ? STATE_ACTIVE : STATE_DEFAULT;
- }
-
- public int getCubeState(Object cubeMode) {
- boolean active = false;
- if (cubeMode == CUBE_MODE_ALL) {
- active = mappingTool.cubeMode == mappingTool.CUBE_MODE_ALL;
- } else if (cubeMode == CUBE_MODE_SINGLE_STRIP) {
- active = mappingTool.cubeMode == mappingTool.CUBE_MODE_SINGLE_STRIP;
- } else if (cubeMode == CUBE_MODE_STRIP_PATTERN) {
- active = mappingTool.cubeMode == mappingTool.CUBE_MODE_STRIP_PATTERN;
- }
- return active ? STATE_ACTIVE : STATE_DEFAULT;
- }
-
- public void draw() {
- drawLogoAndBackground();
-
- int yPos = 0;
- firstMappingY = yPos + lineHeight + 6;
- yPos = drawObjectList(yPos, "MAPPING MODE", mappingModes, mappingModes, mappingModeStateMethod);
- yPos += sectionSpacing;
-
- firstCubeY = yPos + lineHeight + 6;
- yPos = drawObjectList(yPos, "CUBE MODE", cubeModes, cubeModes, cubeModeStateMethod);
- yPos += sectionSpacing;
-
- firstChannelY = yPos + lineHeight + 6;
- yPos = drawObjectList(yPos, "CHANNELS", channelModes, channelModes, channelModeStateMethod);
- yPos += sectionSpacing;
-
- channelFieldY = yPos + lineHeight + 6;
- yPos = drawValueField(yPos, "CHANNEL ID", mappingTool.channelIndex + 1);
- yPos += sectionSpacing;
-
- cubeFieldY = yPos + lineHeight + 6;
- yPos = drawValueField(yPos, "CUBE ID", glucose.model.getRawIndexForCube(mappingTool.cubeIndex));
- yPos += sectionSpacing;
-
- stripFieldY = yPos + lineHeight + 6;
- yPos = drawValueField(yPos, "STRIP ID", mappingTool.stripIndex + 1);
-
- drawToggleTip("Tap 'm' to return");
- }
-
- private int drawValueField(int yPos, String label, int value) {
- yPos += lineHeight;
- textAlign(LEFT);
- textFont(titleFont);
- fill(titleColor);
- text(label, leftTextPos, yPos);
- fill(0);
- yPos += 6;
- rect(leftTextPos, yPos, w-8, lineHeight);
- yPos += lineHeight;
-
- fill(#999999);
- textAlign(CENTER);
- textFont(itemFont);
- text("" + value, leftTextPos + (w-8)/2, yPos - 5);
-
- return yPos;
- }
-
- private int lastY;
-
- public void mousePressed() {
- dragCube = dragStrip = dragChannel = false;
- lastY = mouseY;
-
- if (mouseX < leftPos) {
- return;
- }
-
- if (mouseY >= stripFieldY) {
- if (mouseY < stripFieldY + lineHeight) {
- dragStrip = true;
- }
- } else if (mouseY >= cubeFieldY) {
- if (mouseY < cubeFieldY + lineHeight) {
- dragCube = true;
- }
- } else if (mouseY >= channelFieldY) {
- if (mouseY < channelFieldY + lineHeight) {
- dragChannel = true;
- }
- } else if (mouseY >= firstChannelY) {
- int index = objectClickIndex(firstChannelY);
- switch (index) {
- case 0: mappingTool.channelModeRed = !mappingTool.channelModeRed; break;
- case 1: mappingTool.channelModeGreen = !mappingTool.channelModeGreen; break;
- case 2: mappingTool.channelModeBlue = !mappingTool.channelModeBlue; break;
- }
- } else if (mouseY >= firstCubeY) {
- int index = objectClickIndex(firstCubeY);
- switch (index) {
- case 0: mappingTool.cubeMode = mappingTool.CUBE_MODE_ALL; break;
- case 1: mappingTool.cubeMode = mappingTool.CUBE_MODE_SINGLE_STRIP; break;
- case 2: mappingTool.cubeMode = mappingTool.CUBE_MODE_STRIP_PATTERN; break;
- }
- } else if (mouseY >= firstMappingY) {
- int index = objectClickIndex(firstMappingY);
- switch (index) {
- case 0: mappingTool.mappingMode = mappingTool.MAPPING_MODE_ALL; break;
- case 1: mappingTool.mappingMode = mappingTool.MAPPING_MODE_CHANNEL; break;
- case 2: mappingTool.mappingMode = mappingTool.MAPPING_MODE_SINGLE_CUBE; break;
- }
- }
- }
-
- public void mouseReleased() {}
- public void mouseWheel(int delta) {}
-
- public void mouseDragged() {
- final int DRAG_THRESHOLD = 5;
- int dy = lastY - mouseY;
- if (abs(dy) >= DRAG_THRESHOLD) {
- lastY = mouseY;
- if (dragCube) {
- if (dy < 0) {
- mappingTool.decCube();
- } else {
- mappingTool.incCube();
- }
- } else if (dragStrip) {
- if (dy < 0) {
- mappingTool.decStrip();
- } else {
- mappingTool.incStrip();
- }
- } else if (dragChannel) {
- if (dy < 0) {
- mappingTool.decChannel();
- } else {
- mappingTool.incChannel();
- }
- }
- }
-
- }
-}
-
-class DebugUI {
-
- final ChannelMapping[] channelList;
- final int debugX = 5;
- final int debugY = 5;
- final int debugXSpacing = 28;
- final int debugYSpacing = 21;
- final int[][] debugState;
- final int[] indexState;
-
- final int CUBE_STATE_UNUSED = 0;
- final int CUBE_STATE_USED = 1;
- final int CUBE_STATE_DUPLICATED = 2;
-
- final int DEBUG_STATE_ANIM = 0;
- final int DEBUG_STATE_WHITE = 1;
- final int DEBUG_STATE_OFF = 2;
- final int DEBUG_STATE_UNUSED = 3;
-
- DebugUI(PandaMapping[] pandaMappings) {
- int totalChannels = pandaMappings.length * PandaMapping.CHANNELS_PER_BOARD;
- debugState = new int[totalChannels+1][ChannelMapping.CUBES_PER_CHANNEL+1];
- indexState = new int[glucose.model.cubes.size()+1];
-
- channelList = new ChannelMapping[totalChannels];
- int channelIndex = 0;
- for (PandaMapping pm : pandaMappings) {
- for (ChannelMapping channel : pm.channelList) {
- channelList[channelIndex++] = channel;
- }
- }
- for (int i = 0; i < debugState.length; ++i) {
- for (int j = 0; j < debugState[i].length; ++j) {
- debugState[i][j] = DEBUG_STATE_ANIM;
- }
- }
-
- for (int rawIndex = 0; rawIndex < glucose.model.cubes.size()+1; ++rawIndex) {
- indexState[rawIndex] = CUBE_STATE_UNUSED;
- }
- for (ChannelMapping channel : channelList) {
- for (int rawCubeIndex : channel.objectIndices) {
- if (rawCubeIndex > 0)
- ++indexState[rawCubeIndex];
- }
- }
- }
-
- void draw() {
- noStroke();
- int xBase = debugX;
- int yPos = debugY;
-
- fill(#000000);
- rect(0, 0, debugX + 5*debugXSpacing, height);
-
- int channelNum = 0;
- for (ChannelMapping channel : channelList) {
- int xPos = xBase;
- drawNumBox(xPos, yPos, channelNum+1, debugState[channelNum][0]);
- xPos += debugXSpacing;
-
- switch (channel.mode) {
- case ChannelMapping.MODE_CUBES:
- int stateIndex = 0;
- boolean first = true;
- for (int rawCubeIndex : channel.objectIndices) {
- if (rawCubeIndex < 0) {
- break;
- }
- if (first) {
- first = false;
- } else {
- stroke(#999999);
- line(xPos - 12, yPos + 8, xPos, yPos + 8);
- }
- drawNumBox(xPos, yPos, rawCubeIndex, debugState[channelNum][stateIndex+1], indexState[rawCubeIndex]);
- ++stateIndex;
- xPos += debugXSpacing;
- }
- break;
- case ChannelMapping.MODE_BASS:
- drawNumBox(xPos, yPos, "B", debugState[channelNum][1]);
- break;
- case ChannelMapping.MODE_SPEAKER:
- drawNumBox(xPos, yPos, "S" + channel.objectIndices[0], debugState[channelNum][1]);
- break;
- case ChannelMapping.MODE_STRUTS_AND_FLOOR:
- drawNumBox(xPos, yPos, "F", debugState[channelNum][1]);
- break;
- case ChannelMapping.MODE_NULL:
- break;
- default:
- throw new RuntimeException("Unhandled channel mapping mode: " + channel.mode);
- }
-
- yPos += debugYSpacing;
- ++channelNum;
- }
- drawNumBox(xBase, yPos, "A", debugState[channelNum][0]);
- yPos += debugYSpacing * 2;
-
- noFill();
- fill(#CCCCCC);
- text("Unused Cubes", xBase, yPos + 12);
- yPos += debugYSpacing;
-
- int xIndex = 0;
- for (int rawIndex = 1; rawIndex <= glucose.model.cubes.size(); ++rawIndex) {
- if (indexState[rawIndex] == CUBE_STATE_UNUSED) {
- drawNumBox(xBase + (xIndex * debugXSpacing), yPos, rawIndex, DEBUG_STATE_UNUSED);
- ++xIndex;
- if (xIndex > 4) {
- xIndex = 0;
- yPos += debugYSpacing + 2;
- }
- }
- }
- }
-
-
- void drawNumBox(int xPos, int yPos, int label, int state) {
- drawNumBox(xPos, yPos, "" + label, state);
- }
-
- void drawNumBox(int xPos, int yPos, String label, int state) {
- drawNumBox(xPos, yPos, "" + label, state, CUBE_STATE_USED);
- }
-
- void drawNumBox(int xPos, int yPos, int label, int state, int cubeState) {
- drawNumBox(xPos, yPos, "" + label, state, cubeState);
- }
-
- void drawNumBox(int xPos, int yPos, String label, int state, int cubeState) {
- noFill();
- color textColor = #cccccc;
- switch (state) {
- case DEBUG_STATE_ANIM:
- noStroke();
- fill(#880000);
- rect(xPos, yPos, 16, 8);
- fill(#000088);
- rect(xPos, yPos+8, 16, 8);
- noFill();
- stroke(textColor);
- break;
- case DEBUG_STATE_WHITE:
- stroke(textColor);
- fill(#e9e9e9);
- textColor = #333333;
- break;
- case DEBUG_STATE_OFF:
- stroke(textColor);
- break;
- case DEBUG_STATE_UNUSED:
- stroke(textColor);
- fill(#880000);
- break;
- }
-
- if (cubeState >= CUBE_STATE_DUPLICATED) {
- stroke(textColor = #FF0000);
- }
-
- rect(xPos, yPos, 16, 16);
- noStroke();
- fill(textColor);
- text(label, xPos + 2, yPos + 12);
- }
-
- void maskColors(color[] colors) {
- color white = #FFFFFF;
- color off = #000000;
- int channelIndex = 0;
- int state;
- for (ChannelMapping channel : channelList) {
- switch (channel.mode) {
- case ChannelMapping.MODE_CUBES:
- int cubeIndex = 1;
- for (int rawCubeIndex : channel.objectIndices) {
- if (rawCubeIndex >= 0) {
- state = debugState[channelIndex][cubeIndex];
- if (state != DEBUG_STATE_ANIM) {
- color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
- Cube cube = glucose.model.getCubeByRawIndex(rawCubeIndex);
- for (Point p : cube.points) {
- colors[p.index] = debugColor;
- }
- }
- }
- ++cubeIndex;
- }
- break;
-
- case ChannelMapping.MODE_BASS:
- state = debugState[channelIndex][1];
- if (state != DEBUG_STATE_ANIM) {
- color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
- for (Strip s : glucose.model.bassBox.boxStrips) {
- for (Point p : s.points) {
- colors[p.index] = debugColor;
- }
- }
- }
- break;
-
- case ChannelMapping.MODE_STRUTS_AND_FLOOR:
- state = debugState[channelIndex][1];
- if (state != DEBUG_STATE_ANIM) {
- color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
- for (Point p : glucose.model.boothFloor.points) {
- colors[p.index] = debugColor;
- }
- for (Strip s : glucose.model.bassBox.struts) {
- for (Point p : s.points) {
- colors[p.index] = debugColor;
- }
- }
- }
- break;
-
- case ChannelMapping.MODE_SPEAKER:
- state = debugState[channelIndex][1];
- if (state != DEBUG_STATE_ANIM) {
- color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
- for (Point p : glucose.model.speakers.get(channel.objectIndices[0]).points) {
- colors[p.index] = debugColor;
- }
- }
- break;
-
- case ChannelMapping.MODE_NULL:
- break;
-
- default:
- throw new RuntimeException("Unhandled channel mapping mode: " + channel.mode);
- }
- ++channelIndex;
- }
- }
-
- void mousePressed() {
- int dx = (mouseX - debugX) / debugXSpacing;
- int dy = (mouseY - debugY) / debugYSpacing;
- if ((dy >= 0) && (dy < debugState.length)) {
- if ((dx >= 0) && (dx < debugState[dy].length)) {
- int newState = debugState[dy][dx] = (debugState[dy][dx] + 1) % 3;
- if (dy == debugState.length-1) {
- for (int[] states : debugState) {
- for (int i = 0; i < states.length; ++i) {
- states[i] = newState;
- }
- }
- } else if (dx == 0) {
- for (int i = 0; i < debugState[dy].length; ++i) {
- debugState[dy][i] = newState;
- }
- }
- }
- }
- }
-}
* will be moved into GLucose once stabilized.
*/
public static class PandaDriver {
+
+ interface Listener {
+ public void onToggle(boolean enabled);
+ }
+
+ private Listener listener = null;
+
// IP address
public final String ip;
private static final int NO_POINT = -1;
- public PandaDriver(String ip) {
- this.ip = ip;
-
- // Initialize our OSC output stuff
- address = new NetAddress(ip, 9001);
- message = new OscMessage("/shady/pointbuffer");
-
- // Build the array of points, initialize all to nothing
- points = new int[PandaMapping.PIXELS_PER_BOARD];
- for (int i = 0; i < points.length; ++i) {
- points[i] = NO_POINT;
- }
- }
-
- private final static int FORWARD = -1;
- private final static int BACKWARD = -2;
-
////////////////////////////////////////////////////////////////
//
// READ THIS RIGHT NOW BEFORE YOU MODIFY THE BELOW!!!!!!!!!!!!!
//
////////////////////////////////////////////////////////////////
+ private final static int FORWARD = -1;
+ private final static int BACKWARD = -2;
/**
* These constant arrays indicate the order in which the strips of a cube
{3, BACKWARD },
}
};
-
+
+ public PandaDriver(String ip) {
+ this.ip = ip;
+
+ // Initialize our OSC output stuff
+ address = new NetAddress(ip, 9001);
+ message = new OscMessage("/shady/pointbuffer");
+
+ // Build the array of points, initialize all to nothing
+ points = new int[PandaMapping.PIXELS_PER_BOARD];
+ for (int i = 0; i < points.length; ++i) {
+ points[i] = NO_POINT;
+ }
+ }
+
public PandaDriver(String ip, Model model, PandaMapping pm) {
this(ip);
return pi;
}
- public void disable() {
- if (enabled) {
- enabled = false;
- println("PandaBoard/" + ip + ": OFF");
+ public PandaDriver setListener(Listener listener) {
+ this.listener = listener;
+ return this;
+ }
+
+ public void setEnabled(boolean enabled) {
+ if (this.enabled != enabled) {
+ this.enabled = enabled;
+ println("PandaBoard/" + ip + ": " + (enabled ? "ON" : "OFF"));
+ if (listener != null) {
+ listener.onToggle(enabled);
+ }
}
}
+
+ public void disable() {
+ setEnabled(false);
+ }
public void enable() {
- if (!enabled) {
- enabled = true;
- println("PandaBoard/" + ip + ": ON");
- }
+ setEnabled(true);
}
public void toggle() {
- enabled = !enabled;
- println("PandaBoard/" + ip + ": " + (enabled ? "ON" : "OFF"));
+ setEnabled(!enabled);
}
public final void send(int[] colors) {
--- /dev/null
+/**
+ * DOUBLE BLACK DIAMOND DOUBLE BLACK DIAMOND
+ *
+ * //\\ //\\ //\\ //\\
+ * ///\\\ ///\\\ ///\\\ ///\\\
+ * \\\/// \\\/// \\\/// \\\///
+ * \\// \\// \\// \\//
+ *
+ * EXPERTS ONLY!! EXPERTS ONLY!!
+ *
+ * Little UI framework in progress to handle mouse events, layout,
+ * redrawing, etc.
+ */
+
+final color lightGreen = #669966;
+final color lightBlue = #666699;
+final color bgGray = #444444;
+final color defaultTextColor = #999999;
+final PFont defaultItemFont = createFont("Lucida Grande", 11);
+final PFont defaultTitleFont = createFont("Myriad Pro", 10);
+
+public abstract class UIObject {
+
+ protected final List<UIObject> children = new ArrayList<UIObject>();
+
+ protected boolean needsRedraw = true;
+ protected boolean childNeedsRedraw = true;
+
+ protected float x=0, y=0, w=0, h=0;
+
+ public UIContainer parent = null;
+
+ protected boolean visible = true;
+
+ public UIObject() {}
+
+ public UIObject(float x, float y, float w, float h) {
+ this.x = x;
+ this.y = y;
+ this.w = w;
+ this.h = h;
+ }
+
+ public boolean isVisible() {
+ return visible;
+ }
+
+ public UIObject setVisible(boolean visible) {
+ if (visible != this.visible) {
+ this.visible = visible;
+ redraw();
+ }
+ return this;
+ }
+
+ public final UIObject setPosition(float x, float y) {
+ this.x = x;
+ this.y = y;
+ redraw();
+ return this;
+ }
+
+ public final UIObject setSize(float w, float h) {
+ this.w = w;
+ this.h = h;
+ redraw();
+ return this;
+ }
+
+ public final UIObject addToContainer(UIContainer c) {
+ c.children.add(this);
+ this.parent = c;
+ return this;
+ }
+
+ public final UIObject removeFromContainer(UIContainer c) {
+ c.children.remove(this);
+ this.parent = null;
+ return this;
+ }
+
+ public final UIObject redraw() {
+ _redraw();
+ UIObject p = this.parent;
+ while (p != null) {
+ p.childNeedsRedraw = true;
+ p = p.parent;
+ }
+ return this;
+ }
+
+ private final void _redraw() {
+ needsRedraw = true;
+ for (UIObject child : children) {
+ childNeedsRedraw = true;
+ child._redraw();
+ }
+ }
+
+ public final void draw(PGraphics pg) {
+ if (!visible) {
+ return;
+ }
+ if (needsRedraw) {
+ needsRedraw = false;
+ onDraw(pg);
+ }
+ if (childNeedsRedraw) {
+ childNeedsRedraw = false;
+ for (UIObject child : children) {
+ if (needsRedraw || child.needsRedraw || child.childNeedsRedraw) {
+ pg.pushMatrix();
+ pg.translate(child.x, child.y);
+ child.draw(pg);
+ pg.popMatrix();
+ }
+ }
+ }
+ }
+
+ public final boolean contains(float x, float y) {
+ return
+ (x >= this.x && x < (this.x + this.w)) &&
+ (y >= this.y && y < (this.y + this.h));
+ }
+
+ protected void onDraw(PGraphics pg) {}
+ protected void onMousePressed(float mx, float my) {}
+ protected void onMouseReleased(float mx, float my) {}
+ protected void onMouseDragged(float mx, float my, float dx, float dy) {}
+ protected void onMouseWheel(float mx, float my, float dx) {}
+}
+
+public class UIContainer extends UIObject {
+
+ private UIObject focusedChild = null;
+
+ public UIContainer() {}
+
+ public UIContainer(float x, float y, float w, float h) {
+ super(x, y, w, h);
+ }
+
+ public UIContainer(UIObject[] children) {
+ for (UIObject child : children) {
+ child.addToContainer(this);
+ }
+ }
+
+ protected void onMousePressed(float mx, float my) {
+ for (int i = children.size() - 1; i >= 0; --i) {
+ UIObject child = children.get(i);
+ if (child.contains(mx, my)) {
+ child.onMousePressed(mx - child.x, my - child.y);
+ focusedChild = child;
+ break;
+ }
+ }
+ }
+
+ protected void onMouseReleased(float mx, float my) {
+ if (focusedChild != null) {
+ focusedChild.onMouseReleased(mx - focusedChild.x, my - focusedChild.y);
+ }
+ focusedChild = null;
+ }
+
+ protected void onMouseDragged(float mx, float my, float dx, float dy) {
+ if (focusedChild != null) {
+ focusedChild.onMouseDragged(mx - focusedChild.x, my - focusedChild.y, dx, dy);
+ }
+ }
+
+ protected void onMouseWheel(float mx, float my, float delta) {
+ for (UIObject child : children) {
+ if (child.contains(mx, my)) {
+ child.onMouseWheel(mx - child.x, mx - child.y, delta);
+ }
+ }
+ }
+
+}
+
+public class UIContext extends UIContainer {
+
+ final public PGraphics pg;
+
+ UIContext(float x, float y, float w, float h) {
+ super(x, y, w, h);
+ pg = createGraphics((int)w, (int)h, JAVA2D);
+ pg.smooth();
+ }
+
+ public void draw() {
+ if (!visible) {
+ return;
+ }
+ if (needsRedraw || childNeedsRedraw) {
+ pg.beginDraw();
+ draw(pg);
+ pg.endDraw();
+ }
+ image(pg, x, y);
+ }
+
+ private float px, py;
+ private boolean dragging = false;
+
+ public boolean mousePressed(float mx, float my) {
+ if (!visible) {
+ return false;
+ }
+ if (contains(mx, my)) {
+ dragging = true;
+ px = mx;
+ py = my;
+ onMousePressed(mx - x, my - y);
+ return true;
+ }
+ return false;
+ }
+
+ public boolean mouseReleased(float mx, float my) {
+ if (!visible) {
+ return false;
+ }
+ dragging = false;
+ onMouseReleased(mx - x, my - y);
+ return true;
+ }
+
+ public boolean mouseDragged(float mx, float my) {
+ if (!visible) {
+ return false;
+ }
+ if (dragging) {
+ float dx = mx - px;
+ float dy = my - py;
+ onMouseDragged(mx - x, my - y, dx, dy);
+ px = mx;
+ py = my;
+ return true;
+ }
+ return false;
+ }
+
+ public boolean mouseWheel(float mx, float my, float delta) {
+ if (!visible) {
+ return false;
+ }
+ if (contains(mx, my)) {
+ onMouseWheel(mx - x, my - y, delta);
+ return true;
+ }
+ return false;
+ }
+}
+
+public class UIWindow extends UIContext {
+
+ protected final static int titleHeight = 24;
+
+ public UIWindow(String label, float x, float y, float w, float h) {
+ super(x, y, w, h);
+ new UILabel(6, 8, w-6, titleHeight-8) {
+ protected void onMouseDragged(float mx, float my, float dx, float dy) {
+ parent.x = constrain(parent.x + dx, 0, width - w);
+ parent.y = constrain(parent.y + dy, 0, height - h);
+ }
+ }.setLabel(label).setFont(defaultTitleFont).addToContainer(this);
+ }
+
+ protected void onDraw(PGraphics pg) {
+ pg.noStroke();
+ pg.fill(#444444);
+ pg.stroke(#292929);
+ pg.rect(0, 0, w-1, h-1);
+ }
+}
+
+public class UILabel extends UIObject {
+
+ private PFont font = defaultTitleFont;
+ private color fontColor = #CCCCCC;
+ private String label = "";
+
+ public UILabel(float x, float y, float w, float h) {
+ super(x, y, w, h);
+ }
+
+ protected void onDraw(PGraphics pg) {
+ pg.textAlign(LEFT, TOP);
+ pg.textFont(font);
+ pg.fill(fontColor);
+ pg.text(label, 0, 0);
+ }
+
+ public UILabel setFont(PFont font) {
+ this.font = font;
+ redraw();
+ return this;
+ }
+
+ public UILabel setFontColor(color fontColor) {
+ this.fontColor = fontColor;
+ redraw();
+ return this;
+ }
+
+ public UILabel setLabel(String label) {
+ this.label = label;
+ redraw();
+ return this;
+ }
+}
+
+public class UIButton extends UIObject {
+
+ private boolean active = false;
+ private boolean isMomentary = false;
+ private color borderColor = #666666;
+ private color inactiveColor = #222222;
+ private color activeColor = #669966;
+ private color labelColor = #999999;
+ private String label = "";
+
+ public UIButton(float x, float y, float w, float h) {
+ super(x, y, w, h);
+ }
+
+ public UIButton setMomentary(boolean momentary) {
+ isMomentary = momentary;
+ return this;
+ }
+
+ protected void onDraw(PGraphics pg) {
+ pg.stroke(borderColor);
+ pg.fill(active ? activeColor : inactiveColor);
+ pg.rect(0, 0, w, h);
+ if (label != null && label.length() > 0) {
+ pg.fill(active ? #FFFFFF : labelColor);
+ pg.textFont(defaultItemFont);
+ pg.textAlign(CENTER);
+ pg.text(label, w/2, h-5);
+ }
+ }
+
+ protected void onMousePressed(float mx, float my) {
+ if (isMomentary) {
+ setActive(true);
+ } else {
+ setActive(!active);
+ }
+ }
+
+ protected void onMouseReleased(float mx, float my) {
+ if (isMomentary) {
+ setActive(false);
+ }
+ }
+
+ public UIButton setActive(boolean active) {
+ this.active = active;
+ onToggle(active);
+ redraw();
+ return this;
+ }
+
+ public UIButton toggle() {
+ return setActive(!active);
+ }
+
+ protected void onToggle(boolean active) {}
+
+ public UIButton setBorderColor(color borderColor) {
+ if (this.borderColor != borderColor) {
+ this.borderColor = borderColor;
+ redraw();
+ }
+ return this;
+ }
+
+ public UIButton setActiveColor(color activeColor) {
+ if (this.activeColor != activeColor) {
+ this.activeColor = activeColor;
+ if (active) {
+ redraw();
+ }
+ }
+ return this;
+ }
+
+ public UIButton setInactiveColor(color inactiveColor) {
+ if (this.inactiveColor != inactiveColor) {
+ this.inactiveColor = inactiveColor;
+ if (!active) {
+ redraw();
+ }
+ }
+ return this;
+ }
+
+ public UIButton setLabelColor(color labelColor) {
+ if (this.labelColor != labelColor) {
+ this.labelColor = labelColor;
+ redraw();
+ }
+ return this;
+ }
+
+ public UIButton setLabel(String label) {
+ if (!this.label.equals(label)) {
+ this.label = label;
+ redraw();
+ }
+ return this;
+ }
+
+ public void onMousePressed() {
+ setActive(!active);
+ }
+}
+
+public class UIToggleSet extends UIObject {
+
+ private String[] options;
+ private int[] boundaries;
+ private String value;
+
+ public UIToggleSet(float x, float y, float w, float h) {
+ super(x, y, w, h);
+ }
+
+ public UIToggleSet setOptions(String[] options) {
+ this.options = options;
+ boundaries = new int[options.length];
+ int totalLength = 0;
+ for (String s : options) {
+ totalLength += s.length();
+ }
+ int lengthSoFar = 0;
+ for (int i = 0; i < options.length; ++i) {
+ lengthSoFar += options[i].length();
+ boundaries[i] = (int) (lengthSoFar * w / totalLength);
+ }
+ value = options[0];
+ redraw();
+ return this;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public UIToggleSet setValue(String option) {
+ value = option;
+ onToggle(value);
+ redraw();
+ return this;
+ }
+
+ public void onDraw(PGraphics pg) {
+ pg.stroke(#666666);
+ pg.fill(#222222);
+ pg.rect(0, 0, w, h);
+ for (int b : boundaries) {
+ pg.line(b, 1, b, h-1);
+ }
+ pg.noStroke();
+ pg.textAlign(CENTER);
+ pg.textFont(defaultItemFont);
+ int leftBoundary = 0;
+
+ for (int i = 0; i < options.length; ++i) {
+ boolean isActive = options[i] == value;
+ if (isActive) {
+ pg.fill(lightGreen);
+ pg.rect(leftBoundary + 1, 1, boundaries[i] - leftBoundary - 1, h-1);
+ }
+ pg.fill(isActive ? #FFFFFF : #999999);
+ pg.text(options[i], (leftBoundary + boundaries[i]) / 2., h-6);
+ leftBoundary = boundaries[i];
+ }
+ }
+
+ public void onMousePressed(float mx, float my) {
+ for (int i = 0; i < boundaries.length; ++i) {
+ if (mx < boundaries[i]) {
+ setValue(options[i]);
+ break;
+ }
+ }
+ }
+
+ protected void onToggle(String option) {}
+
+}
+
+
+public abstract class UIParameterControl extends UIObject implements LXParameter.Listener {
+ protected LXParameter parameter = null;
+
+ protected UIParameterControl(float x, float y, float w, float h) {
+ super(x, y, w, h);
+ }
+
+ public void onParameterChanged(LXParameter parameter) {
+ redraw();
+ }
+
+ public UIParameterControl setParameter(LXParameter parameter) {
+ if (this.parameter != null) {
+ if (this.parameter instanceof LXListenableParameter) {
+ ((LXListenableParameter)this.parameter).removeListener(this);
+ }
+ }
+ this.parameter = parameter;
+ if (this.parameter != null) {
+ if (this.parameter instanceof LXListenableParameter) {
+ ((LXListenableParameter)this.parameter).addListener(this);
+ }
+ }
+ redraw();
+ return this;
+ }
+}
+
+public class UIParameterKnob extends UIParameterControl {
+ private int knobSize = 28;
+ private final float knobIndent = .4;
+ private final int knobLabelHeight = 14;
+
+ public UIParameterKnob(float x, float y) {
+ this(x, y, 0, 0);
+ setSize(knobSize, knobSize + knobLabelHeight);
+ }
+
+ public UIParameterKnob(float x, float y, float w, float h) {
+ super(x, y, w, h);
+ }
+
+ protected void onDraw(PGraphics pg) {
+ float knobValue = (parameter != null) ? parameter.getValuef() : 0;
+
+ pg.ellipseMode(CENTER);
+ pg.noStroke();
+
+ pg.fill(bgGray);
+ pg.rect(0, 0, knobSize, knobSize);
+
+ // Full outer dark ring
+ pg.fill(#222222);
+ pg.arc(knobSize/2, knobSize/2, knobSize, knobSize, HALF_PI + knobIndent, HALF_PI + knobIndent + (TWO_PI-2*knobIndent));
+
+ // Light ring indicating value
+ pg.fill(lightGreen);
+ pg.arc(knobSize/2, knobSize/2, knobSize, knobSize, HALF_PI + knobIndent, HALF_PI + knobIndent + knobValue*(TWO_PI-2*knobIndent));
+
+ // Center circle of knob
+ pg.fill(#333333);
+ pg.ellipse(knobSize/2, knobSize/2, knobSize/2, knobSize/2);
+
+ String knobLabel = (parameter != null) ? parameter.getLabel() : null;
+ if (knobLabel == null) {
+ knobLabel = "-";
+ } else if (knobLabel.length() > 4) {
+ knobLabel = knobLabel.substring(0, 4);
+ }
+ pg.fill(#000000);
+ pg.rect(0, knobSize + 2, knobSize, knobLabelHeight - 2);
+ pg.fill(#999999);
+ pg.textAlign(CENTER);
+ pg.textFont(defaultTitleFont);
+ pg.text(knobLabel, knobSize/2, knobSize + knobLabelHeight - 2);
+ }
+
+ public void onMouseDragged(float mx, float my, float dx, float dy) {
+ if (parameter != null) {
+ float value = constrain(parameter.getValuef() - dy / 100., 0, 1);
+ parameter.setValue(value);
+ }
+ }
+}
+
+public class UIParameterSlider extends UIParameterControl {
+
+ private static final float handleWidth = 12;
+
+ UIParameterSlider(float x, float y, float w, float h) {
+ super(x, y, w, h);
+ }
+
+ protected void onDraw(PGraphics pg) {
+ pg.noStroke();
+ pg.fill(#333333);
+ pg.rect(0, 0, w, h);
+ pg.fill(#222222);
+ pg.rect(4, h/2-2, w-8, 4);
+ pg.fill(#666666);
+ pg.stroke(#222222);
+ pg.rect((int) (4 + parameter.getValuef() * (w-8-handleWidth)), 4, handleWidth, h-8);
+ }
+
+ private boolean editing = false;
+ protected void onMousePressed(float mx, float my) {
+ float handleLeft = 4 + parameter.getValuef() * (w-8-handleWidth);
+ if (mx >= handleLeft && mx < handleLeft + handleWidth) {
+ editing = true;
+ }
+ }
+
+ protected void onMouseReleased(float mx, float my) {
+ editing = false;
+ }
+
+ protected void onMouseDragged(float mx, float my, float dx, float dy) {
+ if (editing) {
+ parameter.setValue(constrain((mx - handleWidth/2. - 4) / (w-8-handleWidth), 0, 1));
+ }
+ }
+}
+
+public class UIScrollList extends UIObject {
+
+ private List<ScrollItem> items = new ArrayList<ScrollItem>();
+
+ private PFont itemFont = defaultItemFont;
+ private int itemHeight = 20;
+ private color selectedColor = lightGreen;
+ private color pendingColor = lightBlue;
+ private int scrollOffset = 0;
+ private int numVisibleItems = 0;
+
+ private boolean hasScroll;
+ private float scrollYStart;
+ private float scrollYHeight;
+
+ public UIScrollList(float x, float y, float w, float h) {
+ super(x, y, w, h);
+ }
+
+ protected void onDraw(PGraphics pg) {
+ int yp = 0;
+ boolean even = true;
+ for (int i = 0; i < numVisibleItems; ++i) {
+ if (i + scrollOffset >= items.size()) {
+ break;
+ }
+ ScrollItem item = items.get(i + scrollOffset);
+ color itemColor;
+ color labelColor = #FFFFFF;
+ if (item.isSelected()) {
+ itemColor = selectedColor;
+ } else if (item.isPending()) {
+ itemColor = pendingColor;
+ } else {
+ labelColor = #000000;
+ itemColor = even ? #666666 : #777777;
+ }
+ pg.noStroke();
+ pg.fill(itemColor);
+ pg.rect(0, yp, w, itemHeight);
+ pg.fill(labelColor);
+ pg.textFont(itemFont);
+ pg.textAlign(LEFT, TOP);
+ pg.text(item.getLabel(), 6, yp+4);
+
+ yp += itemHeight;
+ even = !even;
+ }
+ if (hasScroll) {
+ pg.noStroke();
+ pg.fill(color(0, 0, 100, 15));
+ pg.rect(w-12, 0, 12, h);
+ pg.fill(#333333);
+ pg.rect(w-12, scrollYStart, 12, scrollYHeight);
+ }
+
+ }
+
+ private boolean scrolling = false;
+ private ScrollItem pressedItem = null;
+
+ public void onMousePressed(float mx, float my) {
+ pressedItem = null;
+ if (hasScroll && mx >= w-12) {
+ if (my >= scrollYStart && my < (scrollYStart + scrollYHeight)) {
+ scrolling = true;
+ dAccum = 0;
+ }
+ } else {
+ int index = (int) my / itemHeight;
+ if (scrollOffset + index < items.size()) {
+ pressedItem = items.get(scrollOffset + index);
+ pressedItem.onMousePressed();
+ pressedItem.select();
+ redraw();
+ }
+ }
+ }
+
+ public void onMouseReleased(float mx, float my) {
+ scrolling = false;
+ if (pressedItem != null) {
+ pressedItem.onMouseReleased();
+ redraw();
+ }
+ }
+
+ private float dAccum = 0;
+ public void onMouseDragged(float mx, float my, float dx, float dy) {
+ if (scrolling) {
+ dAccum += dy;
+ float scrollOne = h / items.size();
+ int offset = (int) (dAccum / scrollOne);
+ if (offset != 0) {
+ dAccum -= offset * scrollOne;
+ setScrollOffset(scrollOffset + offset);
+ }
+ }
+ }
+
+ private float wAccum = 0;
+ public void onMouseWheel(float mx, float my, float delta) {
+ wAccum += delta;
+ int offset = (int) (wAccum / 5);
+ if (offset != 0) {
+ wAccum -= offset * 5;
+ setScrollOffset(scrollOffset + offset);
+ }
+ }
+
+ public void setScrollOffset(int offset) {
+ scrollOffset = constrain(offset, 0, items.size() - numVisibleItems);
+ scrollYStart = (int) (scrollOffset * h / items.size());
+ scrollYHeight = (int) (numVisibleItems * h / (float) items.size());
+ redraw();
+ }
+
+ public UIScrollList setItems(List<ScrollItem> items) {
+ this.items = items;
+ numVisibleItems = (int) (h / itemHeight);
+ hasScroll = items.size() > numVisibleItems;
+ setScrollOffset(0);
+ redraw();
+ return this;
+ }
+}
+
+public interface ScrollItem {
+ public boolean isSelected();
+ public boolean isPending();
+ public String getLabel();
+ public void select();
+ public void onMousePressed();
+ public void onMouseReleased();
+}
+
+public abstract class AbstractScrollItem implements ScrollItem {
+ public boolean isPending() {
+ return false;
+ }
+ public void select() {}
+ public void onMousePressed() {}
+ public void onMouseReleased() {}
+}
+
+public class UIIntegerBox extends UIObject {
+
+ private int minValue = 0;
+ private int maxValue = MAX_INT;
+ private int value = 0;
+
+ UIIntegerBox(float x, float y, float w, float h) {
+ super(x, y, w, h);
+ }
+
+ public UIIntegerBox setRange(int minValue, int maxValue) {
+ this.minValue = minValue;
+ this.maxValue = maxValue;
+ setValue(constrain(value, minValue, maxValue));
+ return this;
+ }
+
+ protected void onDraw(PGraphics pg) {
+ pg.stroke(#999999);
+ pg.fill(#222222);
+ pg.rect(0, 0, w, h);
+ pg.textAlign(CENTER, CENTER);
+ pg.textFont(defaultItemFont);
+ pg.fill(#999999);
+ pg.text("" + value, w/2, h/2);
+ }
+
+ protected void onValueChange(int value) {}
+
+ float dAccum = 0;
+ protected void onMousePressed(float mx, float my) {
+ dAccum = 0;
+ }
+
+ protected void onMouseDragged(float mx, float my, float dx, float dy) {
+ dAccum -= dy;
+ int offset = (int) (dAccum / 5);
+ dAccum = dAccum - (offset * 5);
+ setValue(value + offset);
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public UIIntegerBox setValue(int value) {
+ if (this.value != value) {
+ int range = (maxValue - minValue + 1);
+ while (value < minValue) {
+ value += range;
+ }
+ this.value = minValue + (value - minValue) % range;
+ this.onValueChange(this.value);
+ redraw();
+ }
+ return this;
+ }
+}
--- /dev/null
+/**
+ * DOUBLE BLACK DIAMOND DOUBLE BLACK DIAMOND
+ *
+ * //\\ //\\ //\\ //\\
+ * ///\\\ ///\\\ ///\\\ ///\\\
+ * \\\/// \\\/// \\\/// \\\///
+ * \\// \\// \\// \\//
+ *
+ * EXPERTS ONLY!! EXPERTS ONLY!!
+ *
+ * Custom UI components using the framework.
+ */
+
+class UIPatternDeck extends UIWindow {
+
+ Engine.Deck deck;
+
+ public UIPatternDeck(Engine.Deck deck, String label, float x, float y, float w, float h) {
+ super(label, x, y, w, h);
+ this.deck = deck;
+ int yp = titleHeight;
+
+ List<ScrollItem> items = new ArrayList<ScrollItem>();
+ for (LXPattern p : deck.getPatterns()) {
+ items.add(new PatternScrollItem(p));
+ }
+ final UIScrollList patternList = new UIScrollList(1, yp, w-2, 160).setItems(items);
+ patternList.addToContainer(this);
+ yp += patternList.h + 10;
+
+ final UIParameterKnob[] parameterKnobs = new UIParameterKnob[12];
+ for (int ki = 0; ki < parameterKnobs.length; ++ki) {
+ parameterKnobs[ki] = new UIParameterKnob(5 + 34*(ki % 4), yp + (ki/4) * 48);
+ parameterKnobs[ki].addToContainer(this);
+ }
+
+ Engine.Listener lxListener = new Engine.Listener() {
+ public void patternWillChange(Engine.Deck deck, LXPattern pattern, LXPattern nextPattern) {
+ patternList.redraw();
+ }
+ public void patternDidChange(Engine.Deck deck, LXPattern pattern) {
+ patternList.redraw();
+ int pi = 0;
+ for (LXParameter parameter : pattern.getParameters()) {
+ if (pi >= parameterKnobs.length) {
+ break;
+ }
+ parameterKnobs[pi++].setParameter(parameter);
+ }
+ while (pi < parameterKnobs.length) {
+ parameterKnobs[pi++].setParameter(null);
+ }
+ }
+ };
+
+ deck.addListener(lxListener);
+ lxListener.patternDidChange(deck, deck.getActivePattern());
+
+ }
+
+ class PatternScrollItem extends AbstractScrollItem {
+
+ private LXPattern pattern;
+ private String label;
+
+ PatternScrollItem(LXPattern pattern) {
+ this.pattern = pattern;
+ label = className(pattern, "Pattern");
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public boolean isSelected() {
+ return deck.getActivePattern() == pattern;
+ }
+
+ public boolean isPending() {
+ return deck.getNextPattern() == pattern;
+ }
+
+ public void select() {
+ deck.goPattern(pattern);
+ }
+ }
+}
+
+class UICrossfader extends UIWindow {
+
+ public UICrossfader(float x, float y, float w, float h) {
+ super("CROSSFADER", x, y, w, h);
+
+ List<ScrollItem> items = new ArrayList<ScrollItem>();
+ for (LXTransition t : transitions) {
+ items.add(new TransitionScrollItem(t));
+ }
+ new UIScrollList(1, titleHeight, w-2, 60).setItems(items).addToContainer(this);
+ new UIParameterSlider(6, titleHeight + 66, w-12, 24).setParameter(lx.engine.getDeck(1).getCrossfader()).addToContainer(this);
+ new UIToggleSet(6, 122, w-12, 20) {
+ protected void onToggle(String value) {
+ displayMode = value;
+ }
+ }.setOptions(new String[] { "A", "COMP", "B" }).setValue(displayMode = "COMP").addToContainer(this);
+ }
+}
+
+class TransitionScrollItem extends AbstractScrollItem {
+ private final LXTransition transition;
+ private String label;
+
+ TransitionScrollItem(LXTransition transition) {
+ this.transition = transition;
+ label = className(transition, "Transition");
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public boolean isSelected() {
+ return transition == lx.engine.getDeck(1).getBlendTransition();
+ }
+
+ public boolean isPending() {
+ return false;
+ }
+
+ public void select() {
+ lx.engine.getDeck(1).setBlendTransition(transition);
+ }
+}
+
+class UIEffects extends UIWindow {
+ UIEffects(float x, float y, float w, float h) {
+ super("FX", x, y, w, h);
+
+ int yp = titleHeight;
+ List<ScrollItem> items = new ArrayList<ScrollItem>();
+ for (LXEffect fx : glucose.lx.getEffects()) {
+ items.add(new FXScrollItem(fx));
+ }
+ final UIScrollList effectsList = new UIScrollList(1, yp, w-2, 60).setItems(items);
+ effectsList.addToContainer(this);
+ yp += effectsList.h + 10;
+
+ final UIParameterKnob[] parameterKnobs = new UIParameterKnob[4];
+ for (int ki = 0; ki < parameterKnobs.length; ++ki) {
+ parameterKnobs[ki] = new UIParameterKnob(5 + 34*(ki % 4), yp + (ki/4) * 48);
+ parameterKnobs[ki].addToContainer(this);
+ }
+
+ GLucose.EffectListener fxListener = new GLucose.EffectListener() {
+ public void effectSelected(LXEffect effect) {
+ int i = 0;
+ for (LXParameter p : effect.getParameters()) {
+ if (i >= parameterKnobs.length) {
+ break;
+ }
+ parameterKnobs[i++].setParameter(p);
+ }
+ while (i < parameterKnobs.length) {
+ parameterKnobs[i++].setParameter(null);
+ }
+ }
+ };
+
+ glucose.addEffectListener(fxListener);
+ fxListener.effectSelected(glucose.getSelectedEffect());
+
+ }
+
+ class FXScrollItem extends AbstractScrollItem {
+
+ private LXEffect effect;
+ private String label;
+
+ FXScrollItem(LXEffect effect) {
+ this.effect = effect;
+ label = className(effect, "Effect");
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public boolean isSelected() {
+ return !effect.isEnabled() && (glucose.getSelectedEffect() == effect);
+ }
+
+ public boolean isPending() {
+ return effect.isEnabled();
+ }
+
+ public void select() {
+ glucose.setSelectedEffect(effect);
+ }
+
+ public void onMousePressed() {
+ if (glucose.getSelectedEffect() == effect) {
+ if (effect.isMomentary()) {
+ effect.enable();
+ } else {
+ effect.toggle();
+ }
+ }
+ }
+
+ public void onMouseReleased() {
+ if (effect.isMomentary()) {
+ effect.disable();
+ }
+ }
+
+ }
+
+}
+
+class UIOutput extends UIWindow {
+ public UIOutput(float x, float y, float w, float h) {
+ super("OUTPUT", x, y, w, h);
+ float yp = titleHeight;
+ for (final PandaDriver panda : pandaBoards) {
+ final UIButton button = new UIButton(4, yp, w-8, 20) {
+ protected void onToggle(boolean active) {
+ panda.setEnabled(active);
+ }
+ }.setLabel(panda.ip);
+ button.addToContainer(this);
+ panda.setListener(new PandaDriver.Listener() {
+ public void onToggle(boolean active) {
+ button.setActive(active);
+ }
+ });
+ yp += 24;
+ }
+ }
+}
+
+class UITempo extends UIWindow {
+
+ private final UIButton tempoButton;
+
+ UITempo(float x, float y, float w, float h) {
+ super("TEMPO", x, y, w, h);
+ tempoButton = new UIButton(4, titleHeight, w-8, 20) {
+ protected void onToggle(boolean active) {
+ if (active) {
+ lx.tempo.tap();
+ }
+ }
+ }.setMomentary(true);
+ tempoButton.addToContainer(this);
+ }
+
+ public void draw() {
+ tempoButton.setLabel("" + ((int)(lx.tempo.bpm() * 10)) / 10.);
+ super.draw();
+
+ // Overlay tempo thing with openGL, redraw faster than button UI
+ fill(color(0, 0, 24 - 8*lx.tempo.rampf()));
+ noStroke();
+ rect(x + 8, y + titleHeight + 5, 12, 12);
+ }
+}
+
+class UIMapping extends UIWindow {
+
+ private static final String MAP_MODE_ALL = "ALL";
+ private static final String MAP_MODE_CHANNEL = "CHNL";
+ private static final String MAP_MODE_CUBE = "CUBE";
+
+ private static final String CUBE_MODE_ALL = "ALL";
+ private static final String CUBE_MODE_STRIP = "SNGL";
+ private static final String CUBE_MODE_PATTERN = "PTRN";
+
+ private final MappingTool mappingTool;
+
+ private final UIIntegerBox channelBox;
+ private final UIIntegerBox cubeBox;
+ private final UIIntegerBox stripBox;
+
+ UIMapping(MappingTool tool, float x, float y, float w, float h) {
+ super("MAPPING", x, y, w, h);
+ mappingTool = tool;
+
+ int yp = titleHeight;
+ new UIToggleSet(4, yp, w-8, 20) {
+ protected void onToggle(String value) {
+ if (value == MAP_MODE_ALL) mappingTool.mappingMode = mappingTool.MAPPING_MODE_ALL;
+ else if (value == MAP_MODE_CHANNEL) mappingTool.mappingMode = mappingTool.MAPPING_MODE_CHANNEL;
+ else if (value == MAP_MODE_CUBE) mappingTool.mappingMode = mappingTool.MAPPING_MODE_SINGLE_CUBE;
+ }
+ }.setOptions(new String[] { MAP_MODE_ALL, MAP_MODE_CHANNEL, MAP_MODE_CUBE }).addToContainer(this);
+ yp += 24;
+ new UILabel(4, yp+8, w-8, 20).setLabel("CHANNEL ID").addToContainer(this);
+ yp += 24;
+ (channelBox = new UIIntegerBox(4, yp, w-8, 20) {
+ protected void onValueChange(int value) {
+ mappingTool.setChannel(value-1);
+ }
+ }).setRange(1, mappingTool.numChannels()).addToContainer(this);
+ yp += 24;
+
+ new UILabel(4, yp+8, w-8, 20).setLabel("CUBE ID").addToContainer(this);
+ yp += 24;
+ (cubeBox = new UIIntegerBox(4, yp, w-8, 20) {
+ protected void onValueChange(int value) {
+ mappingTool.setCube(value-1);
+ }
+ }).setRange(1, glucose.model.cubes.size()).addToContainer(this);
+ yp += 24;
+
+ new UILabel(4, yp+8, w-8, 20).setLabel("COLORS").addToContainer(this);
+ yp += 24;
+
+ new UIScrollList(1, yp, w-2, 60).setItems(Arrays.asList(new ScrollItem[] {
+ new ColorScrollItem(ColorScrollItem.COLOR_RED),
+ new ColorScrollItem(ColorScrollItem.COLOR_GREEN),
+ new ColorScrollItem(ColorScrollItem.COLOR_BLUE),
+ })).addToContainer(this);
+ yp += 64;
+
+ new UILabel(4, yp+8, w-8, 20).setLabel("STRIP MODE").addToContainer(this);
+ yp += 24;
+
+ new UIToggleSet(4, yp, w-8, 20) {
+ protected void onToggle(String value) {
+ if (value == CUBE_MODE_ALL) mappingTool.cubeMode = mappingTool.CUBE_MODE_ALL;
+ else if (value == CUBE_MODE_STRIP) mappingTool.cubeMode = mappingTool.CUBE_MODE_SINGLE_STRIP;
+ else if (value == CUBE_MODE_PATTERN) mappingTool.cubeMode = mappingTool.CUBE_MODE_STRIP_PATTERN;
+ }
+ }.setOptions(new String[] { CUBE_MODE_ALL, CUBE_MODE_STRIP, CUBE_MODE_PATTERN }).addToContainer(this);
+
+ yp += 24;
+ new UILabel(4, yp+8, w-8, 20).setLabel("STRIP ID").addToContainer(this);
+
+ yp += 24;
+ (stripBox = new UIIntegerBox(4, yp, w-8, 20) {
+ protected void onValueChange(int value) {
+ mappingTool.setStrip(value-1);
+ }
+ }).setRange(1, Cube.STRIPS_PER_CUBE).addToContainer(this);
+
+ }
+
+ public void setChannelID(int value) {
+ channelBox.setValue(value);
+ }
+
+ public void setCubeID(int value) {
+ cubeBox.setValue(value);
+ }
+
+ public void setStripID(int value) {
+ stripBox.setValue(value);
+ }
+
+ class ColorScrollItem extends AbstractScrollItem {
+
+ public static final int COLOR_RED = 1;
+ public static final int COLOR_GREEN = 2;
+ public static final int COLOR_BLUE = 3;
+
+ private final int colorChannel;
+
+ ColorScrollItem(int colorChannel) {
+ this.colorChannel = colorChannel;
+ }
+
+ public String getLabel() {
+ switch (colorChannel) {
+ case COLOR_RED: return "Red";
+ case COLOR_GREEN: return "Green";
+ case COLOR_BLUE: return "Blue";
+ }
+ return "";
+ }
+
+ public boolean isSelected() {
+ switch (colorChannel) {
+ case COLOR_RED: return mappingTool.channelModeRed;
+ case COLOR_GREEN: return mappingTool.channelModeGreen;
+ case COLOR_BLUE: return mappingTool.channelModeBlue;
+ }
+ return false;
+ }
+
+ public void select() {
+ switch (colorChannel) {
+ case COLOR_RED: mappingTool.channelModeRed = !mappingTool.channelModeRed; break;
+ case COLOR_GREEN: mappingTool.channelModeGreen = !mappingTool.channelModeGreen; break;
+ case COLOR_BLUE: mappingTool.channelModeBlue = !mappingTool.channelModeBlue; break;
+ }
+ }
+ }
+}
+
+class UIDebugText extends UIContext {
+
+ private String line1 = "";
+ private String line2 = "";
+
+ UIDebugText(float x, float y, float w, float h) {
+ super(x, y, w, h);
+ }
+
+ public UIDebugText setText(String line1) {
+ return setText(line1, "");
+ }
+
+ public UIDebugText setText(String line1, String line2) {
+ if (!line1.equals(this.line1) || !line2.equals(this.line2)) {
+ this.line1 = line1;
+ this.line2 = line2;
+ setVisible(line1.length() + line2.length() > 0);
+ redraw();
+ }
+ return this;
+ }
+
+ protected void onDraw(PGraphics pg) {
+ super.onDraw(pg);
+ if (line1.length() + line2.length() > 0) {
+ pg.noStroke();
+ pg.fill(#444444);
+ pg.rect(0, 0, w, h);
+ pg.textFont(defaultItemFont);
+ pg.textAlign(LEFT, TOP);
+ pg.fill(#cccccc);
+ pg.text(line1, 4, 4);
+ pg.text(line2, 4, 24);
+ }
+ }
+}
+
+String className(Object p, String suffix) {
+ String s = p.getClass().getName();
+ int li;
+ if ((li = s.lastIndexOf(".")) > 0) {
+ s = s.substring(li + 1);
+ }
+ if (s.indexOf("SugarCubes$") == 0) {
+ s = s.substring("SugarCubes$".length());
+ }
+ if ((suffix != null) && ((li = s.indexOf(suffix)) != -1)) {
+ s = s.substring(0, li);
+ }
+ return s;
+}