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