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