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