Now with shader language and many fps
[SugarCubes.git] / UIImplementation.pde
CommitLineData
d626bc9b
MS
1/**
2 * DOUBLE BLACK DIAMOND DOUBLE BLACK DIAMOND
3 *
4 * //\\ //\\ //\\ //\\
5 * ///\\\ ///\\\ ///\\\ ///\\\
6 * \\\/// \\\/// \\\/// \\\///
7 * \\// \\// \\// \\//
8 *
9 * EXPERTS ONLY!! EXPERTS ONLY!!
10 *
11 * Custom UI components using the framework.
12 */
b5d6d7a0
BM
13
14import java.nio.*;
7d60f6f6 15import java.util.Arrays;
36e19b7b 16class UICubesLayer extends UICameraComponent {
b5d6d7a0
BM
17
18int nvert = 200000;
19int SIZEOF_INT = Integer.SIZE / 8;
20int SIZEOF_FLOAT = Float.SIZE / 8;
21
22PGL pgl;
23PShader sh;
24
25int vertLoc;
26int colorLoc;
27
28IntBuffer vboName;
29FloatBuffer vertData;
30
31 boolean initted = false;
32 PShape sha1;
33 int numPoints = 10000;
34
35 void initme()
36 {
37 nvert = model.points.size();
38 sh = loadShader("frag.glsl", "vert.glsl");
39 /*color[] simulationColors = lx.getColors();
40 sha1= createShape();
41 sha1.beginShape(POINTS);
42 for (LXPoint p : model.points) {
43 stroke(simulationColors[p.index]);
44 //pointColor(simulationColors[p.index]);
45 gl2.glPointColor=100;
46 sha1.vertex(p.x, p.y, p.z);
47 }
48 sha1.endShape();*/
49 float[] temp = new float[nvert * 7];
50 for (LXPoint p : model.points) {
51 // position
52 temp[p.index * 7 + 0] = p.x;
53 temp[p.index * 7 + 1] = p.y;
54 temp[p.index * 7 + 2] = p.z;
55
56 // color
57 temp[p.index * 7 + 3] = 0.0;
58 temp[p.index * 7 + 4] = 0.0;
59 temp[p.index * 7 + 5] = 0.0;
60 temp[p.index * 7 + 6] = 1.0;
61 }
62
63 vertData = allocateDirectFloatBuffer(nvert * 7);
64 vertData.rewind();
65 vertData.put(temp);
66 vertData.position(0);
67 vboName = allocateDirectIntBuffer(1);
68 initVBO();
69 }
36e19b7b 70 void onDraw(UI ui) {
b5d6d7a0
BM
71 if(!initted)
72 {
73 initted=true;
74 initme();
75 }
36e19b7b
MS
76 color[] simulationColors = lx.getColors();
77 String displayMode = uiCrossfader.getDisplayMode();
78 if (displayMode == "A") {
79 simulationColors = lx.engine.getDeck(LEFT_DECK).getColors();
80 } else if (displayMode == "B") {
81 simulationColors = lx.engine.getDeck(RIGHT_DECK).getColors();
d626bc9b 82 }
36e19b7b
MS
83
84 long simulationStart = System.nanoTime();
85 if (simulationOn) {
86 drawSimulation(simulationColors);
87 }
88 simulationNanos = System.nanoTime() - simulationStart;
b5d6d7a0 89 camera();
36e19b7b 90 strokeWeight(1);
d626bc9b 91 }
36e19b7b
MS
92 void drawSimulation(color[] simulationColors) {
93 translate(0, 30, 0);
b5d6d7a0 94
36e19b7b 95 fill(#141414);
b5d6d7a0 96 //drawBox(0, -TRAILER_HEIGHT, 0, 0, 0, 0, TRAILER_WIDTH, TRAILER_HEIGHT, TRAILER_DEPTH, TRAILER_HEIGHT/2.);
36e19b7b
MS
97 fill(#070707);
98 stroke(#222222);
99 beginShape();
100 vertex(0, 0, 0);
101 vertex(TRAILER_WIDTH, 0, 0);
102 vertex(TRAILER_WIDTH, 0, TRAILER_DEPTH);
103 vertex(0, 0, TRAILER_DEPTH);
104 endShape();
105
106 // Draw the logo on the front of platform
107 pushMatrix();
108 translate(0, 0, -1);
109 float s = .07;
110 scale(s, -s, s);
111 image(logo, TRAILER_WIDTH/2/s-logo.width/2, TRAILER_HEIGHT/2/s-logo.height/2-2/s);
112 popMatrix();
d626bc9b 113
36e19b7b
MS
114 noStroke();
115 for (Cube c : model.cubes) {
116 drawCube(c);
d626bc9b 117 }
b5d6d7a0 118
36e19b7b 119 noFill();
b5d6d7a0
BM
120 //strokeWeight(2);
121 int count=0;
122
123 ///magic:
124
125 pgl = beginPGL();
126
127
128 sh.bind();
129
130 vertLoc = pgl.getAttribLocation(sh.glProgram, "vertex");
131 colorLoc = pgl.getAttribLocation(sh.glProgram, "color");
132
133 pgl.bindBuffer(PGL.ARRAY_BUFFER, vboName.get(0));
134 pgl.enableVertexAttribArray(vertLoc);
135 pgl.enableVertexAttribArray(colorLoc);
136
137 pgl.vertexAttribPointer(vertLoc, 3, PGL.FLOAT, false, 7 * SIZEOF_FLOAT, 0);
138 pgl.vertexAttribPointer(colorLoc, 4, PGL.FLOAT, false, 7 * SIZEOF_FLOAT, 3 * SIZEOF_FLOAT);
139
140 pgl.drawArrays(PGL.POINTS, 0, nvert);
141
142 pgl.disableVertexAttribArray(vertLoc);
143 pgl.disableVertexAttribArray(colorLoc);
144 pgl.bindBuffer(PGL.ARRAY_BUFFER, 0);
145
146 sh.unbind();
147 endPGL();
148 createGeometry(simulationColors);
149 pgl.bindBuffer(PGL.ARRAY_BUFFER, vboName.get(0));
150 pgl.bufferData(PGL.ARRAY_BUFFER, nvert * 7 * SIZEOF_FLOAT, vertData, PGL.STATIC_DRAW);
151 }
152
153 void createGeometry(color[] simulationColors) {
36e19b7b 154 for (LXPoint p : model.points) {
b5d6d7a0
BM
155 vertData.put(p.index * 7 + 3, ((simulationColors[p.index] >> 16) & 0xFF)/255.0);
156 vertData.put(p.index * 7 + 4, ((simulationColors[p.index] >> 8) & 0xFF)/255.0);
157 vertData.put(p.index * 7 + 5, (simulationColors[p.index]& 0xFF)/255.0);
158 }
36e19b7b 159 }
b5d6d7a0
BM
160void initVBO() {
161
162 pgl = beginPGL();
163 pgl.genBuffers(1, vboName);
164 pgl.bindBuffer(PGL.ARRAY_BUFFER, vboName.get(0));
165 pgl.bufferData(PGL.ARRAY_BUFFER, nvert * 7 * SIZEOF_FLOAT, vertData, PGL.DYNAMIC_DRAW);
166 pgl.bindBuffer(PGL.ARRAY_BUFFER, 0);
167 endPGL();
168}
169
170IntBuffer allocateDirectIntBuffer(int n) {
171 return ByteBuffer.allocateDirect(n * SIZEOF_INT).order(ByteOrder.nativeOrder()).asIntBuffer();
172}
173
174FloatBuffer allocateDirectFloatBuffer(int n) {
175 return ByteBuffer.allocateDirect(n * SIZEOF_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();
176}
36e19b7b
MS
177
178 void drawCube(Cube c) {
179 float in = .15;
180 noStroke();
181 fill(#393939);
b5d6d7a0 182 //drawBox(c.x+in, c.y+in, c.z+in, c.rx, c.ry, c.rz, Cube.EDGE_WIDTH-in*2, Cube.EDGE_HEIGHT-in*2, Cube.EDGE_WIDTH-in*2, Cube.CHANNEL_WIDTH-in);
36e19b7b
MS
183 }
184
185 void drawBox(float x, float y, float z, float rx, float ry, float rz, float xd, float yd, float zd, float sw) {
186 pushMatrix();
187 translate(x, y, z);
188 rotate(rx / 180. * PI, -1, 0, 0);
189 rotate(ry / 180. * PI, 0, -1, 0);
190 rotate(rz / 180. * PI, 0, 0, -1);
191 for (int i = 0; i < 4; ++i) {
192 float wid = (i % 2 == 0) ? xd : zd;
193
194 beginShape();
195 vertex(0, 0);
196 vertex(wid, 0);
197 vertex(wid, yd);
198 vertex(wid - sw, yd);
199 vertex(wid - sw, sw);
200 vertex(0, sw);
201 endShape();
202 beginShape();
203 vertex(0, sw);
204 vertex(0, yd);
205 vertex(wid - sw, yd);
206 vertex(wid - sw, yd - sw);
207 vertex(sw, yd - sw);
208 vertex(sw, sw);
209 endShape();
210
211 translate(wid, 0, 0);
212 rotate(HALF_PI, 0, -1, 0);
d626bc9b 213 }
36e19b7b 214 popMatrix();
d626bc9b
MS
215 }
216}
217
a8d55ade
MS
218class UIBlendMode extends UIWindow {
219 public UIBlendMode(float x, float y, float w, float h) {
4e6626a9
MS
220 super(lx.ui, "BLEND MODE", x, y, w, h);
221 List<UIScrollList.Item> items = new ArrayList<UIScrollList.Item>();
3f16fd02 222 for (LXTransition t : transitions) {
d626bc9b 223 items.add(new TransitionScrollItem(t));
a898d79b
MS
224 }
225 final UIScrollList tList;
4e6626a9 226 (tList = new UIScrollList(1, UIWindow.TITLE_LABEL_HEIGHT, w-2, 60)).setItems(items).addToContainer(this);
a8d55ade 227
0c7bfdb5 228 lx.engine.getDeck(RIGHT_DECK).addListener(new LXDeck.AbstractListener() {
42a424d7 229 public void faderTransitionDidChange(LXDeck deck, LXTransition transition) {
a898d79b 230 tList.redraw();
d626bc9b 231 }
a898d79b
MS
232 });
233 }
a8d55ade 234
4e6626a9 235 class TransitionScrollItem extends UIScrollList.AbstractItem {
a8d55ade 236 private final LXTransition transition;
3f16fd02 237 private final String label;
a8d55ade
MS
238
239 TransitionScrollItem(LXTransition transition) {
240 this.transition = transition;
3f16fd02 241 this.label = className(transition, "Transition");
a8d55ade
MS
242 }
243
244 public String getLabel() {
245 return label;
246 }
247
248 public boolean isSelected() {
0c7bfdb5 249 return this.transition == lx.engine.getDeck(RIGHT_DECK).getFaderTransition();
a8d55ade
MS
250 }
251
252 public boolean isPending() {
253 return false;
254 }
255
256 public void onMousePressed() {
0c7bfdb5 257 lx.engine.getDeck(RIGHT_DECK).setFaderTransition(this.transition);
a8d55ade 258 }
d626bc9b 259 }
a8d55ade 260
d626bc9b
MS
261}
262
a8d55ade 263class UICrossfader extends UIWindow {
d626bc9b 264
a8d55ade 265 private final UIToggleSet displayMode;
d626bc9b 266
a8d55ade 267 public UICrossfader(float x, float y, float w, float h) {
4e6626a9 268 super(lx.ui, "CROSSFADER", x, y, w, h);
a8d55ade 269
0c7bfdb5 270 new UISlider(4, UIWindow.TITLE_LABEL_HEIGHT, w-9, 32).setParameter(lx.engine.getDeck(RIGHT_DECK).getFader()).addToContainer(this);
4e6626a9 271 (displayMode = new UIToggleSet(4, UIWindow.TITLE_LABEL_HEIGHT + 36, w-9, 20)).setOptions(new String[] { "A", "COMP", "B" }).setValue("COMP").addToContainer(this);
d626bc9b
MS
272 }
273
88a3dd9e
MS
274 public UICrossfader setDisplayMode(String value) {
275 displayMode.setValue(value);
276 return this;
277 }
278
a8d55ade
MS
279 public String getDisplayMode() {
280 return displayMode.getValue();
d626bc9b
MS
281 }
282}
283
284class UIEffects extends UIWindow {
285 UIEffects(float x, float y, float w, float h) {
4e6626a9 286 super(lx.ui, "FX", x, y, w, h);
d626bc9b 287
4e6626a9
MS
288 int yp = UIWindow.TITLE_LABEL_HEIGHT;
289 List<UIScrollList.Item> items = new ArrayList<UIScrollList.Item>();
0c7bfdb5
MS
290 int i = 0;
291 for (LXEffect fx : effectsArr) {
292 items.add(new FXScrollItem(fx, i++));
d626bc9b
MS
293 }
294 final UIScrollList effectsList = new UIScrollList(1, yp, w-2, 60).setItems(items);
295 effectsList.addToContainer(this);
4e6626a9 296 yp += effectsList.getHeight() + 10;
d626bc9b 297
4e6626a9 298 final UIKnob[] parameterKnobs = new UIKnob[4];
d626bc9b 299 for (int ki = 0; ki < parameterKnobs.length; ++ki) {
4e6626a9 300 parameterKnobs[ki] = new UIKnob(5 + 34*(ki % 4), yp + (ki/4) * 48);
d626bc9b
MS
301 parameterKnobs[ki].addToContainer(this);
302 }
303
0c7bfdb5
MS
304 LXParameterListener fxListener = new LXParameterListener() {
305 public void onParameterChanged(LXParameter parameter) {
d626bc9b 306 int i = 0;
0c7bfdb5 307 for (LXParameter p : getSelectedEffect().getParameters()) {
d626bc9b
MS
308 if (i >= parameterKnobs.length) {
309 break;
310 }
4e6626a9
MS
311 if (p instanceof BasicParameter) {
312 parameterKnobs[i++].setParameter((BasicParameter) p);
313 }
d626bc9b
MS
314 }
315 while (i < parameterKnobs.length) {
316 parameterKnobs[i++].setParameter(null);
317 }
318 }
319 };
320
0c7bfdb5
MS
321 selectedEffect.addListener(fxListener);
322 fxListener.onParameterChanged(null);
d626bc9b
MS
323
324 }
325
4e6626a9 326 class FXScrollItem extends UIScrollList.AbstractItem {
d626bc9b 327
0c7bfdb5
MS
328 private final LXEffect effect;
329 private final int index;
330 private final String label;
d626bc9b 331
0c7bfdb5 332 FXScrollItem(LXEffect effect, int index) {
d626bc9b 333 this.effect = effect;
0c7bfdb5
MS
334 this.index = index;
335 this.label = className(effect, "Effect");
d626bc9b
MS
336 }
337
338 public String getLabel() {
339 return label;
340 }
341
342 public boolean isSelected() {
0c7bfdb5 343 return !effect.isEnabled() && (effect == getSelectedEffect());
d626bc9b
MS
344 }
345
346 public boolean isPending() {
347 return effect.isEnabled();
348 }
349
d626bc9b 350 public void onMousePressed() {
0c7bfdb5 351 if (effect == getSelectedEffect()) {
d626bc9b
MS
352 if (effect.isMomentary()) {
353 effect.enable();
354 } else {
355 effect.toggle();
356 }
8f7f055d 357 } else {
0c7bfdb5 358 selectedEffect.setValue(index);
d626bc9b
MS
359 }
360 }
361
362 public void onMouseReleased() {
363 if (effect.isMomentary()) {
364 effect.disable();
365 }
366 }
367
368 }
369
370}
371
372class UIOutput extends UIWindow {
e037f60f 373 public UIOutput(GrizzlyOutput[] grizzlies, float x, float y, float w, float h) {
4e6626a9
MS
374 super(lx.ui, "OUTPUT", x, y, w, h);
375 float yp = UIWindow.TITLE_LABEL_HEIGHT;
1f42cce7 376
4e6626a9 377 final UIScrollList outputs = new UIScrollList(1, UIWindow.TITLE_LABEL_HEIGHT, w-2, 80);
1f42cce7 378
4e6626a9 379 List<UIScrollList.Item> items = new ArrayList<UIScrollList.Item>();
e037f60f
MS
380 for (GrizzlyOutput grizzly : grizzlies) {
381 items.add(new GrizzlyScrollItem(grizzly));
382 grizzly.enabled.addListener(new LXParameterListener() {
383 public void onParameterChanged(LXParameter parameter) {
1f42cce7 384 outputs.redraw();
d626bc9b
MS
385 }
386 });
d626bc9b 387 }
1f42cce7
MS
388 outputs.setItems(items).addToContainer(this);
389 }
390
e037f60f
MS
391 class GrizzlyScrollItem extends UIScrollList.AbstractItem {
392 final GrizzlyOutput output;
393
394 GrizzlyScrollItem(GrizzlyOutput output) {
395 this.output = output;
1f42cce7
MS
396 }
397
398 public String getLabel() {
e037f60f 399 return output.ipAddress;
1f42cce7
MS
400 }
401
402 public boolean isSelected() {
e037f60f 403 return output.enabled.isOn();
1f42cce7
MS
404 }
405
8f7f055d 406 public void onMousePressed() {
4749563e 407 output.enabled.setValue(!isSelected());
1f42cce7
MS
408 }
409 }
d626bc9b
MS
410}
411
412class UITempo extends UIWindow {
413
414 private final UIButton tempoButton;
415
416 UITempo(float x, float y, float w, float h) {
4e6626a9
MS
417 super(lx.ui, "TEMPO", x, y, w, h);
418 tempoButton = new UIButton(4, UIWindow.TITLE_LABEL_HEIGHT, w-10, 20) {
d626bc9b
MS
419 protected void onToggle(boolean active) {
420 if (active) {
421 lx.tempo.tap();
422 }
423 }
424 }.setMomentary(true);
425 tempoButton.addToContainer(this);
4e6626a9 426 new UITempoBlipper(8, UIWindow.TITLE_LABEL_HEIGHT + 5, 12, 12).addToContainer(this);
d626bc9b
MS
427 }
428
4e6626a9
MS
429 class UITempoBlipper extends UIObject {
430 UITempoBlipper(float x, float y, float w, float h) {
431 super(x, y, w, h);
432 }
d626bc9b 433
4e6626a9
MS
434 void onDraw(UI ui, PGraphics pg) {
435 tempoButton.setLabel("" + ((int)(lx.tempo.bpm() * 10)) / 10.);
436
437 // Overlay tempo thing with openGL, redraw faster than button UI
438 pg.fill(color(0, 0, 24 - 8*lx.tempo.rampf()));
439 pg.noStroke();
440 pg.rect(0, 0, width, height);
441
442 redraw();
443 }
d626bc9b 444 }
4e6626a9 445
d626bc9b
MS
446}
447
448class UIMapping extends UIWindow {
449
450 private static final String MAP_MODE_ALL = "ALL";
451 private static final String MAP_MODE_CHANNEL = "CHNL";
452 private static final String MAP_MODE_CUBE = "CUBE";
453
454 private static final String CUBE_MODE_ALL = "ALL";
455 private static final String CUBE_MODE_STRIP = "SNGL";
456 private static final String CUBE_MODE_PATTERN = "PTRN";
457
458 private final MappingTool mappingTool;
459
460 private final UIIntegerBox channelBox;
461 private final UIIntegerBox cubeBox;
462 private final UIIntegerBox stripBox;
463
464 UIMapping(MappingTool tool, float x, float y, float w, float h) {
4e6626a9 465 super(lx.ui, "MAPPING", x, y, w, h);
d626bc9b
MS
466 mappingTool = tool;
467
4e6626a9 468 int yp = UIWindow.TITLE_LABEL_HEIGHT;
78a44a1b 469 new UIToggleSet(4, yp, w-10, 20) {
d626bc9b
MS
470 protected void onToggle(String value) {
471 if (value == MAP_MODE_ALL) mappingTool.mappingMode = mappingTool.MAPPING_MODE_ALL;
472 else if (value == MAP_MODE_CHANNEL) mappingTool.mappingMode = mappingTool.MAPPING_MODE_CHANNEL;
473 else if (value == MAP_MODE_CUBE) mappingTool.mappingMode = mappingTool.MAPPING_MODE_SINGLE_CUBE;
474 }
475 }.setOptions(new String[] { MAP_MODE_ALL, MAP_MODE_CHANNEL, MAP_MODE_CUBE }).addToContainer(this);
476 yp += 24;
78a44a1b 477 new UILabel(4, yp+8, w-10, 20).setLabel("CHANNEL ID").addToContainer(this);
d626bc9b 478 yp += 24;
78a44a1b 479 (channelBox = new UIIntegerBox(4, yp, w-10, 20) {
d626bc9b
MS
480 protected void onValueChange(int value) {
481 mappingTool.setChannel(value-1);
482 }
483 }).setRange(1, mappingTool.numChannels()).addToContainer(this);
484 yp += 24;
485
78a44a1b 486 new UILabel(4, yp+8, w-10, 20).setLabel("CUBE ID").addToContainer(this);
d626bc9b 487 yp += 24;
78a44a1b 488 (cubeBox = new UIIntegerBox(4, yp, w-10, 20) {
d626bc9b
MS
489 protected void onValueChange(int value) {
490 mappingTool.setCube(value-1);
491 }
b9b7b3d4 492 }).setRange(1, model.cubes.size()).addToContainer(this);
d626bc9b
MS
493 yp += 24;
494
a8d55ade
MS
495 yp += 10;
496
4e6626a9 497 new UIScrollList(1, yp, w-2, 60).setItems(Arrays.asList(new UIScrollList.Item[] {
d626bc9b
MS
498 new ColorScrollItem(ColorScrollItem.COLOR_RED),
499 new ColorScrollItem(ColorScrollItem.COLOR_GREEN),
500 new ColorScrollItem(ColorScrollItem.COLOR_BLUE),
501 })).addToContainer(this);
502 yp += 64;
503
78a44a1b 504 new UILabel(4, yp+8, w-10, 20).setLabel("STRIP MODE").addToContainer(this);
d626bc9b
MS
505 yp += 24;
506
78a44a1b 507 new UIToggleSet(4, yp, w-10, 20) {
d626bc9b
MS
508 protected void onToggle(String value) {
509 if (value == CUBE_MODE_ALL) mappingTool.cubeMode = mappingTool.CUBE_MODE_ALL;
510 else if (value == CUBE_MODE_STRIP) mappingTool.cubeMode = mappingTool.CUBE_MODE_SINGLE_STRIP;
511 else if (value == CUBE_MODE_PATTERN) mappingTool.cubeMode = mappingTool.CUBE_MODE_STRIP_PATTERN;
512 }
513 }.setOptions(new String[] { CUBE_MODE_ALL, CUBE_MODE_STRIP, CUBE_MODE_PATTERN }).addToContainer(this);
514
515 yp += 24;
78a44a1b 516 new UILabel(4, yp+8, w-10, 20).setLabel("STRIP ID").addToContainer(this);
d626bc9b
MS
517
518 yp += 24;
78a44a1b 519 (stripBox = new UIIntegerBox(4, yp, w-10, 20) {
d626bc9b
MS
520 protected void onValueChange(int value) {
521 mappingTool.setStrip(value-1);
522 }
523 }).setRange(1, Cube.STRIPS_PER_CUBE).addToContainer(this);
524
525 }
526
527 public void setChannelID(int value) {
528 channelBox.setValue(value);
529 }
530
531 public void setCubeID(int value) {
532 cubeBox.setValue(value);
533 }
534
535 public void setStripID(int value) {
536 stripBox.setValue(value);
537 }
538
4e6626a9 539 class ColorScrollItem extends UIScrollList.AbstractItem {
d626bc9b
MS
540
541 public static final int COLOR_RED = 1;
542 public static final int COLOR_GREEN = 2;
543 public static final int COLOR_BLUE = 3;
544
545 private final int colorChannel;
546
547 ColorScrollItem(int colorChannel) {
548 this.colorChannel = colorChannel;
549 }
550
551 public String getLabel() {
552 switch (colorChannel) {
553 case COLOR_RED: return "Red";
554 case COLOR_GREEN: return "Green";
555 case COLOR_BLUE: return "Blue";
556 }
557 return "";
558 }
559
560 public boolean isSelected() {
561 switch (colorChannel) {
562 case COLOR_RED: return mappingTool.channelModeRed;
563 case COLOR_GREEN: return mappingTool.channelModeGreen;
564 case COLOR_BLUE: return mappingTool.channelModeBlue;
565 }
566 return false;
567 }
568
a8d55ade 569 public void onMousePressed() {
d626bc9b
MS
570 switch (colorChannel) {
571 case COLOR_RED: mappingTool.channelModeRed = !mappingTool.channelModeRed; break;
572 case COLOR_GREEN: mappingTool.channelModeGreen = !mappingTool.channelModeGreen; break;
573 case COLOR_BLUE: mappingTool.channelModeBlue = !mappingTool.channelModeBlue; break;
574 }
575 }
576 }
577}
578
579class UIDebugText extends UIContext {
580
581 private String line1 = "";
582 private String line2 = "";
583
584 UIDebugText(float x, float y, float w, float h) {
4e6626a9 585 super(lx.ui, x, y, w, h);
d626bc9b
MS
586 }
587
588 public UIDebugText setText(String line1) {
589 return setText(line1, "");
590 }
591
592 public UIDebugText setText(String line1, String line2) {
593 if (!line1.equals(this.line1) || !line2.equals(this.line2)) {
594 this.line1 = line1;
595 this.line2 = line2;
596 setVisible(line1.length() + line2.length() > 0);
597 redraw();
598 }
599 return this;
600 }
601
4e6626a9
MS
602 protected void onDraw(UI ui, PGraphics pg) {
603 super.onDraw(ui, pg);
d626bc9b
MS
604 if (line1.length() + line2.length() > 0) {
605 pg.noStroke();
606 pg.fill(#444444);
4e6626a9
MS
607 pg.rect(0, 0, width, height);
608 pg.textFont(ui.getItemFont());
a8d55ade 609 pg.textSize(10);
d626bc9b
MS
610 pg.textAlign(LEFT, TOP);
611 pg.fill(#cccccc);
612 pg.text(line1, 4, 4);
613 pg.text(line2, 4, 24);
614 }
615 }
616}
617
34327c96 618class UISpeed extends UIWindow {
fa4f822d
MS
619
620 final BasicParameter speed;
621
34327c96 622 UISpeed(float x, float y, float w, float h) {
4e6626a9 623 super(lx.ui, "SPEED", x, y, w, h);
fa4f822d 624 speed = new BasicParameter("SPEED", 0.5);
4e6626a9 625 speed.addListener(new LXParameterListener() {
34327c96
MS
626 public void onParameterChanged(LXParameter parameter) {
627 lx.setSpeed(parameter.getValuef() * 2);
628 }
4e6626a9
MS
629 });
630 new UISlider(4, UIWindow.TITLE_LABEL_HEIGHT, w-10, 20).setParameter(speed).addToContainer(this);
34327c96
MS
631 }
632}
633
a8d55ade
MS
634class UIMidi extends UIWindow {
635
9692dc7b
MS
636 private final UIToggleSet deckMode;
637 private final UIButton logMode;
a8d55ade 638
d6ac1ee8 639 UIMidi(final MidiEngine midiEngine, float x, float y, float w, float h) {
4e6626a9 640 super(lx.ui, "MIDI", x, y, w, h);
d6ac1ee8 641
a8d55ade 642 // Processing compiler doesn't seem to get that list of class objects also conform to interface
4e6626a9 643 List<UIScrollList.Item> scrollItems = new ArrayList<UIScrollList.Item>();
d6ac1ee8 644 for (SCMidiInput mc : midiEngine.getControllers()) {
30bf6510 645 scrollItems.add(mc);
a8d55ade 646 }
30bf6510 647 final UIScrollList scrollList;
4e6626a9 648 (scrollList = new UIScrollList(1, UIWindow.TITLE_LABEL_HEIGHT, w-2, 100)).setItems(scrollItems).addToContainer(this);
d6ac1ee8
MS
649 (deckMode = new UIToggleSet(4, 130, 90, 20) {
650 protected void onToggle(String value) {
651 midiEngine.setFocusedDeck(value == "A" ? 0 : 1);
652 }
653 }).setOptions(new String[] { "A", "B" }).addToContainer(this);
4df91daf 654 (logMode = new UIButton(98, 130, w-103, 20)).setLabel("LOG").addToContainer(this);
30bf6510
MS
655
656 SCMidiInputListener listener = new SCMidiInputListener() {
657 public void onEnabled(SCMidiInput controller, boolean enabled) {
658 scrollList.redraw();
659 }
660 };
d6ac1ee8 661 for (SCMidiInput mc : midiEngine.getControllers()) {
30bf6510
MS
662 mc.addListener(listener);
663 }
d6ac1ee8
MS
664
665 midiEngine.addListener(new MidiEngineListener() {
666 public void onFocusedDeck(int deckIndex) {
667 deckMode.setValue(deckIndex == 0 ? "A" : "B");
668 }
669 });
30bf6510 670
9692dc7b
MS
671 }
672
673 public boolean logMidi() {
674 return logMode.isActive();
a8d55ade
MS
675 }
676
42a424d7 677 public LXDeck getFocusedDeck() {
0c7bfdb5 678 return lx.engine.getDeck(deckMode.getValue() == "A" ? LEFT_DECK : RIGHT_DECK);
a8d55ade
MS
679 }
680}
681
d626bc9b
MS
682String className(Object p, String suffix) {
683 String s = p.getClass().getName();
684 int li;
685 if ((li = s.lastIndexOf(".")) > 0) {
686 s = s.substring(li + 1);
687 }
688 if (s.indexOf("SugarCubes$") == 0) {
689 s = s.substring("SugarCubes$".length());
690 }
691 if ((suffix != null) && ((li = s.indexOf(suffix)) != -1)) {
692 s = s.substring(0, li);
693 }
694 return s;
695}