Some cleanups and listen to deck for transition changes
[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 }
27 final UIScrollList patternList = new UIScrollList(1, yp, w-2, 160).setItems(items);
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
89class UICrossfader extends UIWindow {
a898d79b
MS
90
91 private final UIToggleSet displayMode;
92
d626bc9b
MS
93 public UICrossfader(float x, float y, float w, float h) {
94 super("CROSSFADER", x, y, w, h);
95
96 List<ScrollItem> items = new ArrayList<ScrollItem>();
a898d79b 97 for (LXTransition t : glucose.getTransitions()) {
d626bc9b 98 items.add(new TransitionScrollItem(t));
a898d79b
MS
99 }
100 final UIScrollList tList;
101 (tList = new UIScrollList(1, titleHeight, w-2, 120)).setItems(items).addToContainer(this);
fe30b226 102 new UIParameterSlider(4, titleHeight + 126, w-10, 24).setParameter(lx.engine.getDeck(1).getCrossfader()).addToContainer(this);
a898d79b
MS
103 (displayMode = new UIToggleSet(4, 182, w-10, 20)).setOptions(new String[] { "A", "COMP", "B" }).setValue("COMP").addToContainer(this);
104
105 lx.engine.getDeck(1).addListener(new Engine.AbstractListener() {
106 public void blendTransitionDidChange(Engine.Deck deck, LXTransition transition) {
107 tList.redraw();
d626bc9b 108 }
a898d79b
MS
109 });
110 }
111
112 public String getDisplayMode() {
113 return displayMode.getValue();
d626bc9b
MS
114 }
115}
116
117class TransitionScrollItem extends AbstractScrollItem {
118 private final LXTransition transition;
119 private String label;
120
121 TransitionScrollItem(LXTransition transition) {
122 this.transition = transition;
123 label = className(transition, "Transition");
124 }
125
126 public String getLabel() {
127 return label;
128 }
129
130 public boolean isSelected() {
a898d79b 131 return transition == glucose.getSelectedTransition();
d626bc9b
MS
132 }
133
134 public boolean isPending() {
135 return false;
136 }
137
8f7f055d 138 public void onMousePressed() {
a898d79b 139 glucose.setSelectedTransition(transition);
d626bc9b
MS
140 }
141}
142
143class UIEffects extends UIWindow {
144 UIEffects(float x, float y, float w, float h) {
145 super("FX", x, y, w, h);
146
147 int yp = titleHeight;
148 List<ScrollItem> items = new ArrayList<ScrollItem>();
149 for (LXEffect fx : glucose.lx.getEffects()) {
150 items.add(new FXScrollItem(fx));
151 }
152 final UIScrollList effectsList = new UIScrollList(1, yp, w-2, 60).setItems(items);
153 effectsList.addToContainer(this);
154 yp += effectsList.h + 10;
155
156 final UIParameterKnob[] parameterKnobs = new UIParameterKnob[4];
157 for (int ki = 0; ki < parameterKnobs.length; ++ki) {
158 parameterKnobs[ki] = new UIParameterKnob(5 + 34*(ki % 4), yp + (ki/4) * 48);
159 parameterKnobs[ki].addToContainer(this);
160 }
161
162 GLucose.EffectListener fxListener = new GLucose.EffectListener() {
163 public void effectSelected(LXEffect effect) {
164 int i = 0;
165 for (LXParameter p : effect.getParameters()) {
166 if (i >= parameterKnobs.length) {
167 break;
168 }
169 parameterKnobs[i++].setParameter(p);
170 }
171 while (i < parameterKnobs.length) {
172 parameterKnobs[i++].setParameter(null);
173 }
174 }
175 };
176
177 glucose.addEffectListener(fxListener);
178 fxListener.effectSelected(glucose.getSelectedEffect());
179
180 }
181
182 class FXScrollItem extends AbstractScrollItem {
183
184 private LXEffect effect;
185 private String label;
186
187 FXScrollItem(LXEffect effect) {
188 this.effect = effect;
189 label = className(effect, "Effect");
190 }
191
192 public String getLabel() {
193 return label;
194 }
195
196 public boolean isSelected() {
197 return !effect.isEnabled() && (glucose.getSelectedEffect() == effect);
198 }
199
200 public boolean isPending() {
201 return effect.isEnabled();
202 }
203
d626bc9b
MS
204 public void onMousePressed() {
205 if (glucose.getSelectedEffect() == effect) {
206 if (effect.isMomentary()) {
207 effect.enable();
208 } else {
209 effect.toggle();
210 }
8f7f055d
MS
211 } else {
212 glucose.setSelectedEffect(effect);
d626bc9b
MS
213 }
214 }
215
216 public void onMouseReleased() {
217 if (effect.isMomentary()) {
218 effect.disable();
219 }
220 }
221
222 }
223
224}
225
226class UIOutput extends UIWindow {
227 public UIOutput(float x, float y, float w, float h) {
228 super("OUTPUT", x, y, w, h);
229 float yp = titleHeight;
1f42cce7
MS
230
231 final UIScrollList outputs = new UIScrollList(1, titleHeight, w-2, 80);
232
233 List<ScrollItem> items = new ArrayList<ScrollItem>();
d626bc9b 234 for (final PandaDriver panda : pandaBoards) {
1f42cce7 235 items.add(new PandaScrollItem(panda));
d626bc9b
MS
236 panda.setListener(new PandaDriver.Listener() {
237 public void onToggle(boolean active) {
1f42cce7 238 outputs.redraw();
d626bc9b
MS
239 }
240 });
d626bc9b 241 }
1f42cce7
MS
242 outputs.setItems(items).addToContainer(this);
243 }
244
245 class PandaScrollItem extends AbstractScrollItem {
246 final PandaDriver panda;
247 PandaScrollItem(PandaDriver panda) {
248 this.panda = panda;
249 }
250
251 public String getLabel() {
252 return panda.ip;
253 }
254
255 public boolean isSelected() {
256 return panda.isEnabled();
257 }
258
8f7f055d 259 public void onMousePressed() {
1f42cce7
MS
260 panda.toggle();
261 }
262 }
d626bc9b
MS
263}
264
265class UITempo extends UIWindow {
266
267 private final UIButton tempoButton;
268
269 UITempo(float x, float y, float w, float h) {
270 super("TEMPO", x, y, w, h);
78a44a1b 271 tempoButton = new UIButton(4, titleHeight, w-10, 20) {
d626bc9b
MS
272 protected void onToggle(boolean active) {
273 if (active) {
274 lx.tempo.tap();
275 }
276 }
277 }.setMomentary(true);
278 tempoButton.addToContainer(this);
279 }
280
281 public void draw() {
282 tempoButton.setLabel("" + ((int)(lx.tempo.bpm() * 10)) / 10.);
283 super.draw();
284
285 // Overlay tempo thing with openGL, redraw faster than button UI
286 fill(color(0, 0, 24 - 8*lx.tempo.rampf()));
287 noStroke();
288 rect(x + 8, y + titleHeight + 5, 12, 12);
289 }
290}
291
292class UIMapping extends UIWindow {
293
294 private static final String MAP_MODE_ALL = "ALL";
295 private static final String MAP_MODE_CHANNEL = "CHNL";
296 private static final String MAP_MODE_CUBE = "CUBE";
297
298 private static final String CUBE_MODE_ALL = "ALL";
299 private static final String CUBE_MODE_STRIP = "SNGL";
300 private static final String CUBE_MODE_PATTERN = "PTRN";
301
302 private final MappingTool mappingTool;
303
304 private final UIIntegerBox channelBox;
305 private final UIIntegerBox cubeBox;
306 private final UIIntegerBox stripBox;
307
308 UIMapping(MappingTool tool, float x, float y, float w, float h) {
309 super("MAPPING", x, y, w, h);
310 mappingTool = tool;
311
312 int yp = titleHeight;
78a44a1b 313 new UIToggleSet(4, yp, w-10, 20) {
d626bc9b
MS
314 protected void onToggle(String value) {
315 if (value == MAP_MODE_ALL) mappingTool.mappingMode = mappingTool.MAPPING_MODE_ALL;
316 else if (value == MAP_MODE_CHANNEL) mappingTool.mappingMode = mappingTool.MAPPING_MODE_CHANNEL;
317 else if (value == MAP_MODE_CUBE) mappingTool.mappingMode = mappingTool.MAPPING_MODE_SINGLE_CUBE;
318 }
319 }.setOptions(new String[] { MAP_MODE_ALL, MAP_MODE_CHANNEL, MAP_MODE_CUBE }).addToContainer(this);
320 yp += 24;
78a44a1b 321 new UILabel(4, yp+8, w-10, 20).setLabel("CHANNEL ID").addToContainer(this);
d626bc9b 322 yp += 24;
78a44a1b 323 (channelBox = new UIIntegerBox(4, yp, w-10, 20) {
d626bc9b
MS
324 protected void onValueChange(int value) {
325 mappingTool.setChannel(value-1);
326 }
327 }).setRange(1, mappingTool.numChannels()).addToContainer(this);
328 yp += 24;
329
78a44a1b 330 new UILabel(4, yp+8, w-10, 20).setLabel("CUBE ID").addToContainer(this);
d626bc9b 331 yp += 24;
78a44a1b 332 (cubeBox = new UIIntegerBox(4, yp, w-10, 20) {
d626bc9b
MS
333 protected void onValueChange(int value) {
334 mappingTool.setCube(value-1);
335 }
336 }).setRange(1, glucose.model.cubes.size()).addToContainer(this);
337 yp += 24;
338
78a44a1b 339 new UILabel(4, yp+8, w-10, 20).setLabel("COLORS").addToContainer(this);
d626bc9b
MS
340 yp += 24;
341
342 new UIScrollList(1, yp, w-2, 60).setItems(Arrays.asList(new ScrollItem[] {
343 new ColorScrollItem(ColorScrollItem.COLOR_RED),
344 new ColorScrollItem(ColorScrollItem.COLOR_GREEN),
345 new ColorScrollItem(ColorScrollItem.COLOR_BLUE),
346 })).addToContainer(this);
347 yp += 64;
348
78a44a1b 349 new UILabel(4, yp+8, w-10, 20).setLabel("STRIP MODE").addToContainer(this);
d626bc9b
MS
350 yp += 24;
351
78a44a1b 352 new UIToggleSet(4, yp, w-10, 20) {
d626bc9b
MS
353 protected void onToggle(String value) {
354 if (value == CUBE_MODE_ALL) mappingTool.cubeMode = mappingTool.CUBE_MODE_ALL;
355 else if (value == CUBE_MODE_STRIP) mappingTool.cubeMode = mappingTool.CUBE_MODE_SINGLE_STRIP;
356 else if (value == CUBE_MODE_PATTERN) mappingTool.cubeMode = mappingTool.CUBE_MODE_STRIP_PATTERN;
357 }
358 }.setOptions(new String[] { CUBE_MODE_ALL, CUBE_MODE_STRIP, CUBE_MODE_PATTERN }).addToContainer(this);
359
360 yp += 24;
78a44a1b 361 new UILabel(4, yp+8, w-10, 20).setLabel("STRIP ID").addToContainer(this);
d626bc9b
MS
362
363 yp += 24;
78a44a1b 364 (stripBox = new UIIntegerBox(4, yp, w-10, 20) {
d626bc9b
MS
365 protected void onValueChange(int value) {
366 mappingTool.setStrip(value-1);
367 }
368 }).setRange(1, Cube.STRIPS_PER_CUBE).addToContainer(this);
369
370 }
371
372 public void setChannelID(int value) {
373 channelBox.setValue(value);
374 }
375
376 public void setCubeID(int value) {
377 cubeBox.setValue(value);
378 }
379
380 public void setStripID(int value) {
381 stripBox.setValue(value);
382 }
383
384 class ColorScrollItem extends AbstractScrollItem {
385
386 public static final int COLOR_RED = 1;
387 public static final int COLOR_GREEN = 2;
388 public static final int COLOR_BLUE = 3;
389
390 private final int colorChannel;
391
392 ColorScrollItem(int colorChannel) {
393 this.colorChannel = colorChannel;
394 }
395
396 public String getLabel() {
397 switch (colorChannel) {
398 case COLOR_RED: return "Red";
399 case COLOR_GREEN: return "Green";
400 case COLOR_BLUE: return "Blue";
401 }
402 return "";
403 }
404
405 public boolean isSelected() {
406 switch (colorChannel) {
407 case COLOR_RED: return mappingTool.channelModeRed;
408 case COLOR_GREEN: return mappingTool.channelModeGreen;
409 case COLOR_BLUE: return mappingTool.channelModeBlue;
410 }
411 return false;
412 }
413
414 public void select() {
415 switch (colorChannel) {
416 case COLOR_RED: mappingTool.channelModeRed = !mappingTool.channelModeRed; break;
417 case COLOR_GREEN: mappingTool.channelModeGreen = !mappingTool.channelModeGreen; break;
418 case COLOR_BLUE: mappingTool.channelModeBlue = !mappingTool.channelModeBlue; break;
419 }
420 }
421 }
422}
423
424class UIDebugText extends UIContext {
425
426 private String line1 = "";
427 private String line2 = "";
428
429 UIDebugText(float x, float y, float w, float h) {
430 super(x, y, w, h);
431 }
432
433 public UIDebugText setText(String line1) {
434 return setText(line1, "");
435 }
436
437 public UIDebugText setText(String line1, String line2) {
438 if (!line1.equals(this.line1) || !line2.equals(this.line2)) {
439 this.line1 = line1;
440 this.line2 = line2;
441 setVisible(line1.length() + line2.length() > 0);
442 redraw();
443 }
444 return this;
445 }
446
447 protected void onDraw(PGraphics pg) {
448 super.onDraw(pg);
449 if (line1.length() + line2.length() > 0) {
450 pg.noStroke();
451 pg.fill(#444444);
452 pg.rect(0, 0, w, h);
453 pg.textFont(defaultItemFont);
454 pg.textAlign(LEFT, TOP);
455 pg.fill(#cccccc);
456 pg.text(line1, 4, 4);
457 pg.text(line2, 4, 24);
458 }
459 }
460}
461
462String className(Object p, String suffix) {
463 String s = p.getClass().getName();
464 int li;
465 if ((li = s.lastIndexOf(".")) > 0) {
466 s = s.substring(li + 1);
467 }
468 if (s.indexOf("SugarCubes$") == 0) {
469 s = s.substring("SugarCubes$".length());
470 }
471 if ((suffix != null) && ((li = s.indexOf(suffix)) != -1)) {
472 s = s.substring(0, li);
473 }
474 return s;
475}