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