Commit | Line | Data |
---|---|---|
e73ef85d MS |
1 | import java.lang.reflect.*; |
2 | ||
49815cc0 | 3 | /** |
1ecdb44a MS |
4 | * DOUBLE BLACK DIAMOND DOUBLE BLACK DIAMOND |
5 | * | |
6 | * //\\ //\\ //\\ //\\ | |
7 | * ///\\\ ///\\\ ///\\\ ///\\\ | |
8 | * \\\/// \\\/// \\\/// \\\/// | |
9 | * \\// \\// \\// \\// | |
10 | * | |
11 | * EXPERTS ONLY!! EXPERTS ONLY!! | |
12 | * | |
49815cc0 MS |
13 | * Overlay UI that indicates pattern control, etc. This will be moved |
14 | * into the Processing library once it is stabilized and need not be | |
15 | * regularly modified. | |
16 | */ | |
bf551144 MS |
17 | abstract class OverlayUI { |
18 | protected final PFont titleFont = createFont("Myriad Pro", 10); | |
19 | protected final color titleColor = #AAAAAA; | |
20 | protected final PFont itemFont = createFont("Lucida Grande", 11); | |
21 | protected final PFont knobFont = titleFont; | |
22 | protected final int w = 140; | |
23 | protected final int leftPos; | |
24 | protected final int leftTextPos; | |
25 | protected final int lineHeight = 20; | |
26 | protected final int sectionSpacing = 12; | |
27 | protected final int controlSpacing = 18; | |
28 | protected final int tempoHeight = 20; | |
29 | protected final int knobSize = 28; | |
30 | protected final float knobIndent = .4; | |
31 | protected final int knobSpacing = 6; | |
32 | protected final int knobLabelHeight = 14; | |
33 | protected final color lightBlue = #666699; | |
34 | protected final color lightGreen = #669966; | |
49815cc0 | 35 | |
bf551144 MS |
36 | private PImage logo; |
37 | ||
38 | protected final int STATE_DEFAULT = 0; | |
39 | protected final int STATE_ACTIVE = 1; | |
40 | protected final int STATE_PENDING = 2; | |
41 | ||
42 | protected OverlayUI() { | |
43 | leftPos = width - w; | |
44 | leftTextPos = leftPos + 4; | |
45 | logo = loadImage("logo-sm.png"); | |
46 | } | |
47 | ||
48 | protected void drawLogoAndBackground() { | |
49 | image(logo, 4, 4); | |
50 | stroke(color(0, 0, 100)); | |
51 | // fill(color(0, 0, 50, 50)); // alpha is bad for perf | |
52 | fill(color(0, 0, 30)); | |
53 | rect(leftPos-1, -1, w+2, height+2); | |
54 | } | |
55 | ||
56 | protected void drawToggleTip(String s) { | |
57 | fill(#999999); | |
58 | textFont(itemFont); | |
59 | textAlign(LEFT); | |
60 | text(s, leftTextPos, height-6); | |
61 | } | |
62 | ||
63 | protected void drawHelpTip() { | |
64 | textFont(itemFont); | |
65 | textAlign(RIGHT); | |
66 | text("Tap 'u' to restore UI", width-4, height-6); | |
67 | } | |
68 | ||
69 | public void drawFPS() { | |
70 | textFont(titleFont); | |
71 | textAlign(LEFT); | |
72 | fill(#666666); | |
73 | text("FPS: " + (((int)(frameRate * 10)) / 10.), 4, height-6); | |
74 | } | |
75 | ||
76 | protected int drawObjectList(int yPos, String title, Object[] items, Method stateMethod) { | |
77 | return drawObjectList(yPos, title, items, classNameArray(items, null), stateMethod); | |
78 | } | |
79 | ||
80 | protected int drawObjectList(int yPos, String title, Object[] items, String[] names, Method stateMethod) { | |
81 | noStroke(); | |
82 | fill(titleColor); | |
83 | textFont(titleFont); | |
84 | textAlign(LEFT); | |
85 | text(title, leftTextPos, yPos += lineHeight); | |
86 | if (items != null) { | |
87 | textFont(itemFont); | |
88 | color textColor; | |
89 | boolean even = true; | |
90 | for (int i = 0; i < items.length; ++i) { | |
91 | Object o = items[i]; | |
92 | int state = STATE_DEFAULT; | |
93 | try { | |
94 | state = ((Integer) stateMethod.invoke(this, o)).intValue(); | |
95 | } catch (Exception x) { | |
96 | throw new RuntimeException(x); | |
97 | } | |
98 | switch (state) { | |
99 | case STATE_ACTIVE: | |
100 | fill(lightGreen); | |
101 | textColor = #eeeeee; | |
102 | break; | |
103 | case STATE_PENDING: | |
104 | fill(lightBlue); | |
105 | textColor = color(0, 0, 75 + 15*sin(millis()/200.));; | |
106 | break; | |
107 | default: | |
108 | textColor = 0; | |
109 | fill(even ? #666666 : #777777); | |
110 | break; | |
111 | } | |
112 | rect(leftPos, yPos+6, width, lineHeight); | |
113 | fill(textColor); | |
114 | text(names[i], leftTextPos, yPos += lineHeight); | |
115 | even = !even; | |
116 | } | |
117 | } | |
118 | return yPos; | |
119 | } | |
120 | ||
121 | protected String[] classNameArray(Object[] objects, String suffix) { | |
122 | if (objects == null) { | |
123 | return null; | |
124 | } | |
125 | String[] names = new String[objects.length]; | |
126 | for (int i = 0; i < objects.length; ++i) { | |
127 | names[i] = className(objects[i], suffix); | |
128 | } | |
129 | return names; | |
130 | } | |
131 | ||
132 | protected String className(Object p, String suffix) { | |
133 | String s = p.getClass().getName(); | |
134 | int li; | |
135 | if ((li = s.lastIndexOf(".")) > 0) { | |
136 | s = s.substring(li + 1); | |
137 | } | |
138 | if (s.indexOf("SugarCubes$") == 0) { | |
139 | s = s.substring("SugarCubes$".length()); | |
140 | } | |
141 | if ((suffix != null) && ((li = s.indexOf(suffix)) != -1)) { | |
142 | s = s.substring(0, li); | |
143 | } | |
144 | return s; | |
145 | } | |
146 | ||
147 | protected int objectClickIndex(int firstItemY) { | |
148 | return (mouseY - firstItemY) / lineHeight; | |
149 | } | |
150 | ||
151 | abstract public void draw(); | |
152 | abstract public void mousePressed(); | |
153 | abstract public void mouseDragged(); | |
154 | abstract public void mouseReleased(); | |
155 | } | |
156 | ||
157 | /** | |
158 | * UI for control of patterns, transitions, effects. | |
159 | */ | |
160 | class ControlUI extends OverlayUI { | |
49815cc0 MS |
161 | private final String[] patternNames; |
162 | private final String[] transitionNames; | |
163 | private final String[] effectNames; | |
49815cc0 MS |
164 | |
165 | private int firstPatternY; | |
3f8be614 | 166 | private int firstPatternKnobY; |
49815cc0 | 167 | private int firstTransitionY; |
3f8be614 | 168 | private int firstTransitionKnobY; |
49815cc0 | 169 | private int firstEffectY; |
3f8be614 MS |
170 | private int firstEffectKnobY; |
171 | ||
49815cc0 MS |
172 | private int tempoY; |
173 | ||
174 | private Method patternStateMethod; | |
175 | private Method transitionStateMethod; | |
176 | private Method effectStateMethod; | |
177 | ||
809f3518 | 178 | private final int NUM_PATTERN_KNOBS = 8; |
3f8be614 MS |
179 | private final int NUM_TRANSITION_KNOBS = 4; |
180 | private final int NUM_EFFECT_KNOBS = 4; | |
181 | ||
182 | private int activeTransitionIndex = 0; | |
183 | private int activeEffectIndex = 0; | |
184 | ||
809f3518 MS |
185 | public final VirtualPatternKnob[] patternKnobs; |
186 | public final VirtualTransitionKnob[] transitionKnobs; | |
187 | public final VirtualEffectKnob[] effectKnobs; | |
bf551144 MS |
188 | |
189 | ControlUI() { | |
3f8be614 MS |
190 | patternNames = classNameArray(patterns, "Pattern"); |
191 | transitionNames = classNameArray(transitions, "Transition"); | |
192 | effectNames = classNameArray(effects, "Effect"); | |
193 | ||
809f3518 MS |
194 | patternKnobs = new VirtualPatternKnob[NUM_PATTERN_KNOBS]; |
195 | for (int i = 0; i < patternKnobs.length; ++i) { | |
196 | patternKnobs[i] = new VirtualPatternKnob(i); | |
197 | } | |
198 | ||
3f8be614 MS |
199 | transitionKnobs = new VirtualTransitionKnob[NUM_TRANSITION_KNOBS]; |
200 | for (int i = 0; i < transitionKnobs.length; ++i) { | |
201 | transitionKnobs[i] = new VirtualTransitionKnob(i); | |
202 | } | |
203 | ||
204 | effectKnobs = new VirtualEffectKnob[NUM_EFFECT_KNOBS]; | |
205 | for (int i = 0; i < effectKnobs.length; ++i) { | |
206 | effectKnobs[i] = new VirtualEffectKnob(i); | |
207 | } | |
49815cc0 MS |
208 | |
209 | try { | |
210 | patternStateMethod = getClass().getMethod("getState", LXPattern.class); | |
211 | effectStateMethod = getClass().getMethod("getState", LXEffect.class); | |
212 | transitionStateMethod = getClass().getMethod("getState", LXTransition.class); | |
213 | } catch (Exception x) { | |
214 | throw new RuntimeException(x); | |
215 | } | |
216 | } | |
bf551144 MS |
217 | |
218 | public void draw() { | |
219 | drawLogoAndBackground(); | |
220 | int yPos = 0; | |
49815cc0 MS |
221 | firstPatternY = yPos + lineHeight + 6; |
222 | yPos = drawObjectList(yPos, "PATTERN", patterns, patternNames, patternStateMethod); | |
3f8be614 MS |
223 | yPos += controlSpacing; |
224 | firstPatternKnobY = yPos; | |
49815cc0 | 225 | int xPos = leftTextPos; |
809f3518 MS |
226 | for (int i = 0; i < NUM_PATTERN_KNOBS/2; ++i) { |
227 | drawKnob(xPos, yPos, knobSize, patternKnobs[i]); | |
228 | drawKnob(xPos, yPos + knobSize + knobSpacing + knobLabelHeight, knobSize, patternKnobs[NUM_PATTERN_KNOBS/2 + i]); | |
49815cc0 MS |
229 | xPos += knobSize + knobSpacing; |
230 | } | |
231 | yPos += 2*(knobSize + knobLabelHeight) + knobSpacing; | |
232 | ||
233 | yPos += sectionSpacing; | |
234 | firstTransitionY = yPos + lineHeight + 6; | |
235 | yPos = drawObjectList(yPos, "TRANSITION", transitions, transitionNames, transitionStateMethod); | |
3f8be614 MS |
236 | yPos += controlSpacing; |
237 | firstTransitionKnobY = yPos; | |
238 | xPos = leftTextPos; | |
239 | for (int i = 0; i < transitionKnobs.length; ++i) { | |
240 | drawKnob(xPos, yPos, knobSize, transitionKnobs[i]); | |
241 | xPos += knobSize + knobSpacing; | |
242 | } | |
243 | yPos += knobSize + knobLabelHeight; | |
49815cc0 MS |
244 | |
245 | yPos += sectionSpacing; | |
246 | firstEffectY = yPos + lineHeight + 6; | |
247 | yPos = drawObjectList(yPos, "FX", effects, effectNames, effectStateMethod); | |
3f8be614 MS |
248 | yPos += controlSpacing; |
249 | firstEffectKnobY = yPos; | |
250 | xPos = leftTextPos; | |
251 | for (int i = 0; i < effectKnobs.length; ++i) { | |
252 | drawKnob(xPos, yPos, knobSize, effectKnobs[i]); | |
253 | xPos += knobSize + knobSpacing; | |
254 | } | |
255 | yPos += knobSize + knobLabelHeight; | |
49815cc0 MS |
256 | |
257 | yPos += sectionSpacing; | |
258 | yPos = drawObjectList(yPos, "TEMPO", null, null, null); | |
259 | yPos += 6; | |
260 | tempoY = yPos; | |
261 | stroke(#111111); | |
262 | fill(tempoDown ? lightGreen : color(0, 0, 35 - 8*lx.tempo.rampf())); | |
263 | rect(leftPos + 4, yPos, w - 8, tempoHeight); | |
264 | fill(0); | |
265 | textAlign(CENTER); | |
266 | text("" + ((int)(lx.tempo.bpmf() * 100) / 100.), leftPos + w/2., yPos + tempoHeight - 6); | |
267 | yPos += tempoHeight; | |
268 | ||
bf551144 | 269 | drawToggleTip("Tap 'u' to hide"); |
49815cc0 MS |
270 | } |
271 | ||
3f8be614 | 272 | public LXParameter getOrNull(List<LXParameter> items, int index) { |
49815cc0 MS |
273 | if (index < items.size()) { |
274 | return items.get(index); | |
275 | } | |
276 | return null; | |
277 | } | |
278 | ||
49815cc0 MS |
279 | public int getState(LXPattern p) { |
280 | if (p == lx.getPattern()) { | |
281 | return STATE_ACTIVE; | |
282 | } else if (p == lx.getNextPattern()) { | |
283 | return STATE_PENDING; | |
284 | } | |
285 | return STATE_DEFAULT; | |
286 | } | |
287 | ||
288 | public int getState(LXEffect e) { | |
3f8be614 MS |
289 | if (e.isEnabled()) { |
290 | return STATE_PENDING; | |
291 | } else if (effects[activeEffectIndex] == e) { | |
292 | return STATE_ACTIVE; | |
293 | } | |
294 | return STATE_DEFAULT; | |
49815cc0 MS |
295 | } |
296 | ||
297 | public int getState(LXTransition t) { | |
298 | if (t == lx.getTransition()) { | |
299 | return STATE_PENDING; | |
300 | } else if (t == transitions[activeTransitionIndex]) { | |
301 | return STATE_ACTIVE; | |
302 | } | |
303 | return STATE_DEFAULT; | |
304 | } | |
49815cc0 | 305 | |
3f8be614 | 306 | private void drawKnob(int xPos, int yPos, int knobSize, LXParameter knob) { |
49815cc0 MS |
307 | final float knobValue = knob.getValuef(); |
308 | String knobLabel = knob.getLabel(); | |
3f8be614 | 309 | if (knobLabel == null) { |
49815cc0 | 310 | knobLabel = "-"; |
3f8be614 MS |
311 | } else if (knobLabel.length() > 4) { |
312 | knobLabel = knobLabel.substring(0, 4); | |
49815cc0 MS |
313 | } |
314 | ||
315 | ellipseMode(CENTER); | |
87f6fa39 | 316 | noStroke(); |
49815cc0 | 317 | fill(#222222); |
3f8be614 MS |
318 | // For some reason this arc call really crushes drawing performance. Presumably |
319 | // because openGL is drawing it and when we overlap the second set of arcs it | |
320 | // does a bunch of depth buffer intersection tests? Ellipse with a trapezoid cut out is faster | |
321 | // arc(xPos + knobSize/2, yPos + knobSize/2, knobSize, knobSize, HALF_PI + knobIndent, HALF_PI + knobIndent + (TWO_PI-2*knobIndent)); | |
322 | ellipse(xPos + knobSize/2, yPos + knobSize/2, knobSize, knobSize); | |
323 | ||
324 | float endArc = HALF_PI + knobIndent + (TWO_PI-2*knobIndent)*knobValue; | |
49815cc0 | 325 | fill(lightGreen); |
3f8be614 MS |
326 | arc(xPos + knobSize/2, yPos + knobSize/2, knobSize, knobSize, HALF_PI + knobIndent, endArc); |
327 | ||
3f8be614 MS |
328 | // Mask notch out of knob |
329 | fill(color(0, 0, 30)); | |
330 | beginShape(); | |
4eae387e MS |
331 | vertex(xPos + knobSize/2, yPos + knobSize/2.); |
332 | vertex(xPos + knobSize/2 - 6, yPos + knobSize); | |
333 | vertex(xPos + knobSize/2 + 6, yPos + knobSize); | |
3f8be614 | 334 | endShape(); |
4eae387e MS |
335 | |
336 | // Center circle of knob | |
337 | fill(#333333); | |
338 | ellipse(xPos + knobSize/2, yPos + knobSize/2, knobSize/2, knobSize/2); | |
49815cc0 MS |
339 | |
340 | fill(0); | |
341 | rect(xPos, yPos + knobSize + 2, knobSize, knobLabelHeight - 2); | |
342 | fill(#999999); | |
343 | textAlign(CENTER); | |
344 | textFont(knobFont); | |
345 | text(knobLabel, xPos + knobSize/2, yPos + knobSize + knobLabelHeight - 2); | |
49815cc0 | 346 | } |
3f8be614 | 347 | |
809f3518 MS |
348 | class VirtualPatternKnob extends LXVirtualParameter { |
349 | private final int index; | |
350 | ||
351 | VirtualPatternKnob(int index) { | |
352 | this.index = index; | |
353 | } | |
354 | ||
355 | public LXParameter getRealParameter() { | |
356 | List<LXParameter> parameters = glucose.getPattern().getParameters(); | |
357 | if (index < parameters.size()) { | |
358 | return parameters.get(index); | |
359 | } | |
360 | return null; | |
361 | } | |
362 | } | |
363 | ||
3f8be614 MS |
364 | class VirtualTransitionKnob extends LXVirtualParameter { |
365 | private final int index; | |
366 | ||
367 | VirtualTransitionKnob(int index) { | |
368 | this.index = index; | |
369 | } | |
370 | ||
371 | public LXParameter getRealParameter() { | |
372 | List<LXParameter> parameters = transitions[activeTransitionIndex].getParameters(); | |
373 | if (index < parameters.size()) { | |
374 | return parameters.get(index); | |
375 | } | |
376 | return null; | |
377 | } | |
378 | } | |
379 | ||
380 | class VirtualEffectKnob extends LXVirtualParameter { | |
381 | private final int index; | |
382 | ||
383 | VirtualEffectKnob(int index) { | |
384 | this.index = index; | |
385 | } | |
386 | ||
387 | public LXParameter getRealParameter() { | |
388 | List<LXParameter> parameters = effects[activeEffectIndex].getParameters(); | |
389 | if (index < parameters.size()) { | |
390 | return parameters.get(index); | |
391 | } | |
392 | return null; | |
393 | } | |
394 | } | |
395 | ||
396 | private int patternKnobIndex = -1; | |
397 | private int transitionKnobIndex = -1; | |
398 | private int effectKnobIndex = -1; | |
49815cc0 | 399 | |
49815cc0 MS |
400 | private int lastY; |
401 | private int releaseEffect = -1; | |
402 | private boolean tempoDown = false; | |
403 | ||
404 | public void mousePressed() { | |
405 | lastY = mouseY; | |
3f8be614 | 406 | patternKnobIndex = transitionKnobIndex = effectKnobIndex = -1; |
49815cc0 MS |
407 | releaseEffect = -1; |
408 | if (mouseY > tempoY) { | |
409 | if (mouseY - tempoY < tempoHeight) { | |
410 | lx.tempo.tap(); | |
411 | tempoDown = true; | |
412 | } | |
3f8be614 MS |
413 | } else if ((mouseY >= firstEffectKnobY) && (mouseY < firstEffectKnobY + knobSize + knobLabelHeight)) { |
414 | effectKnobIndex = (mouseX - leftTextPos) / (knobSize + knobSpacing); | |
49815cc0 | 415 | } else if (mouseY > firstEffectY) { |
bf551144 | 416 | int effectIndex = objectClickIndex(firstEffectY); |
49815cc0 | 417 | if (effectIndex < effects.length) { |
3f8be614 | 418 | if (activeEffectIndex == effectIndex) { |
49815cc0 MS |
419 | effects[effectIndex].enable(); |
420 | releaseEffect = effectIndex; | |
49815cc0 | 421 | } |
3f8be614 | 422 | activeEffectIndex = effectIndex; |
49815cc0 | 423 | } |
3f8be614 MS |
424 | } else if ((mouseY >= firstTransitionKnobY) && (mouseY < firstTransitionKnobY + knobSize + knobLabelHeight)) { |
425 | transitionKnobIndex = (mouseX - leftTextPos) / (knobSize + knobSpacing); | |
49815cc0 | 426 | } else if (mouseY > firstTransitionY) { |
bf551144 | 427 | int transitionIndex = objectClickIndex(firstTransitionY); |
49815cc0 MS |
428 | if (transitionIndex < transitions.length) { |
429 | activeTransitionIndex = transitionIndex; | |
430 | } | |
3f8be614 MS |
431 | } else if ((mouseY >= firstPatternKnobY) && (mouseY < firstPatternKnobY + 2*(knobSize+knobLabelHeight) + knobSpacing)) { |
432 | patternKnobIndex = (mouseX - leftTextPos) / (knobSize + knobSpacing); | |
433 | if (mouseY >= firstPatternKnobY + knobSize + knobLabelHeight + knobSpacing) { | |
809f3518 | 434 | patternKnobIndex += NUM_PATTERN_KNOBS / 2; |
49815cc0 MS |
435 | } |
436 | } else if (mouseY > firstPatternY) { | |
bf551144 | 437 | int patternIndex = objectClickIndex(firstPatternY); |
49815cc0 MS |
438 | if (patternIndex < patterns.length) { |
439 | patterns[patternIndex].setTransition(transitions[activeTransitionIndex]); | |
440 | lx.goIndex(patternIndex); | |
441 | } | |
442 | } | |
443 | } | |
444 | ||
445 | public void mouseDragged() { | |
446 | int dy = lastY - mouseY; | |
447 | lastY = mouseY; | |
809f3518 MS |
448 | if (patternKnobIndex >= 0 && patternKnobIndex < NUM_PATTERN_KNOBS) { |
449 | LXParameter p = patternKnobs[patternKnobIndex]; | |
3f8be614 MS |
450 | p.setValue(constrain(p.getValuef() + dy*.01, 0, 1)); |
451 | } else if (effectKnobIndex >= 0 && effectKnobIndex < NUM_EFFECT_KNOBS) { | |
452 | LXParameter p = effectKnobs[effectKnobIndex]; | |
453 | p.setValue(constrain(p.getValuef() + dy*.01, 0, 1)); | |
454 | } else if (transitionKnobIndex >= 0 && transitionKnobIndex < NUM_TRANSITION_KNOBS) { | |
455 | LXParameter p = transitionKnobs[transitionKnobIndex]; | |
456 | p.setValue(constrain(p.getValuef() + dy*.01, 0, 1)); | |
49815cc0 MS |
457 | } |
458 | } | |
459 | ||
460 | public void mouseReleased() { | |
461 | tempoDown = false; | |
462 | if (releaseEffect >= 0) { | |
463 | effects[releaseEffect].trigger(); | |
464 | releaseEffect = -1; | |
465 | } | |
466 | } | |
3f8be614 | 467 | |
49815cc0 MS |
468 | } |
469 | ||
bf551144 MS |
470 | /** |
471 | * UI for control of mapping. | |
472 | */ | |
473 | class MappingUI extends OverlayUI { | |
474 | ||
475 | private MappingTool mappingTool; | |
476 | ||
477 | private final String MAPPING_MODE_ALL = "All On"; | |
2bae07c9 | 478 | private final String MAPPING_MODE_CHANNEL = "Channel"; |
bf551144 | 479 | private final String MAPPING_MODE_SINGLE_CUBE = "Single Cube"; |
2bae07c9 | 480 | |
bf551144 MS |
481 | private final String[] mappingModes = { |
482 | MAPPING_MODE_ALL, | |
2bae07c9 MS |
483 | MAPPING_MODE_CHANNEL, |
484 | MAPPING_MODE_SINGLE_CUBE | |
bf551144 MS |
485 | }; |
486 | private final Method mappingModeStateMethod; | |
487 | ||
488 | private final String CUBE_MODE_ALL = "All Strips"; | |
489 | private final String CUBE_MODE_SINGLE_STRIP = "Single Strip"; | |
490 | private final String CUBE_MODE_STRIP_PATTERN = "Strip Pattern"; | |
491 | private final String[] cubeModes = { | |
492 | CUBE_MODE_ALL, | |
493 | CUBE_MODE_SINGLE_STRIP, | |
494 | CUBE_MODE_STRIP_PATTERN | |
495 | }; | |
496 | private final Method cubeModeStateMethod; | |
497 | ||
498 | private final String CHANNEL_MODE_RED = "Red"; | |
499 | private final String CHANNEL_MODE_GREEN = "Green"; | |
500 | private final String CHANNEL_MODE_BLUE = "Blue"; | |
501 | private final String[] channelModes = { | |
502 | CHANNEL_MODE_RED, | |
503 | CHANNEL_MODE_GREEN, | |
504 | CHANNEL_MODE_BLUE, | |
505 | }; | |
506 | private final Method channelModeStateMethod; | |
507 | ||
508 | private int firstMappingY; | |
509 | private int firstCubeY; | |
510 | private int firstChannelY; | |
2bae07c9 | 511 | private int channelFieldY; |
bf551144 MS |
512 | private int cubeFieldY; |
513 | private int stripFieldY; | |
514 | ||
515 | private boolean dragCube; | |
516 | private boolean dragStrip; | |
2bae07c9 | 517 | private boolean dragChannel; |
bf551144 MS |
518 | |
519 | MappingUI(MappingTool mappingTool) { | |
520 | this.mappingTool = mappingTool; | |
521 | try { | |
522 | mappingModeStateMethod = getClass().getMethod("getMappingState", Object.class); | |
523 | channelModeStateMethod = getClass().getMethod("getChannelState", Object.class); | |
524 | cubeModeStateMethod = getClass().getMethod("getCubeState", Object.class); | |
525 | } catch (Exception x) { | |
526 | throw new RuntimeException(x); | |
527 | } | |
528 | } | |
529 | ||
530 | public int getMappingState(Object mappingMode) { | |
2bae07c9 MS |
531 | boolean active = false; |
532 | if (mappingMode == MAPPING_MODE_ALL) { | |
533 | active = mappingTool.mappingMode == mappingTool.MAPPING_MODE_ALL; | |
534 | } else if (mappingMode == MAPPING_MODE_CHANNEL) { | |
535 | active = mappingTool.mappingMode == mappingTool.MAPPING_MODE_CHANNEL; | |
536 | } else if (mappingMode == MAPPING_MODE_SINGLE_CUBE) { | |
537 | active = mappingTool.mappingMode == mappingTool.MAPPING_MODE_SINGLE_CUBE; | |
538 | } | |
bf551144 MS |
539 | return active ? STATE_ACTIVE : STATE_DEFAULT; |
540 | } | |
541 | ||
542 | public int getChannelState(Object channelMode) { | |
543 | boolean active = false; | |
544 | if (channelMode == CHANNEL_MODE_RED) { | |
545 | active = mappingTool.channelModeRed; | |
546 | } else if (channelMode == CHANNEL_MODE_GREEN) { | |
547 | active = mappingTool.channelModeGreen; | |
548 | } else if (channelMode == CHANNEL_MODE_BLUE) { | |
549 | active = mappingTool.channelModeBlue; | |
550 | } | |
551 | return active ? STATE_ACTIVE : STATE_DEFAULT; | |
552 | } | |
553 | ||
554 | public int getCubeState(Object cubeMode) { | |
555 | boolean active = false; | |
556 | if (cubeMode == CUBE_MODE_ALL) { | |
557 | active = mappingTool.cubeMode == mappingTool.CUBE_MODE_ALL; | |
558 | } else if (cubeMode == CUBE_MODE_SINGLE_STRIP) { | |
559 | active = mappingTool.cubeMode == mappingTool.CUBE_MODE_SINGLE_STRIP; | |
560 | } else if (cubeMode == CUBE_MODE_STRIP_PATTERN) { | |
561 | active = mappingTool.cubeMode == mappingTool.CUBE_MODE_STRIP_PATTERN; | |
562 | } | |
563 | return active ? STATE_ACTIVE : STATE_DEFAULT; | |
564 | } | |
565 | ||
566 | public void draw() { | |
567 | drawLogoAndBackground(); | |
568 | int yPos = 0; | |
569 | firstMappingY = yPos + lineHeight + 6; | |
570 | yPos = drawObjectList(yPos, "MAPPING MODE", mappingModes, mappingModes, mappingModeStateMethod); | |
571 | yPos += sectionSpacing; | |
572 | ||
573 | firstCubeY = yPos + lineHeight + 6; | |
574 | yPos = drawObjectList(yPos, "CUBE MODE", cubeModes, cubeModes, cubeModeStateMethod); | |
575 | yPos += sectionSpacing; | |
576 | ||
577 | firstChannelY = yPos + lineHeight + 6; | |
578 | yPos = drawObjectList(yPos, "CHANNELS", channelModes, channelModes, channelModeStateMethod); | |
579 | yPos += sectionSpacing; | |
2bae07c9 MS |
580 | |
581 | channelFieldY = yPos + lineHeight + 6; | |
582 | yPos = drawValueField(yPos, "CHANNEL ID", mappingTool.channelIndex + 1); | |
583 | yPos += sectionSpacing; | |
bf551144 MS |
584 | |
585 | cubeFieldY = yPos + lineHeight + 6; | |
586 | yPos = drawValueField(yPos, "CUBE ID", glucose.model.getRawIndexForCube(mappingTool.cubeIndex)); | |
587 | yPos += sectionSpacing; | |
588 | ||
589 | stripFieldY = yPos + lineHeight + 6; | |
590 | yPos = drawValueField(yPos, "STRIP ID", mappingTool.stripIndex + 1); | |
591 | ||
592 | drawToggleTip("Tap 'm' to return"); | |
593 | } | |
594 | ||
595 | private int drawValueField(int yPos, String label, int value) { | |
596 | yPos += lineHeight; | |
597 | textAlign(LEFT); | |
598 | textFont(titleFont); | |
599 | fill(titleColor); | |
600 | text(label, leftTextPos, yPos); | |
601 | fill(0); | |
602 | yPos += 6; | |
603 | rect(leftTextPos, yPos, w-8, lineHeight); | |
604 | yPos += lineHeight; | |
605 | ||
606 | fill(#999999); | |
607 | textAlign(CENTER); | |
608 | textFont(itemFont); | |
609 | text("" + value, leftTextPos + (w-8)/2, yPos - 5); | |
610 | ||
611 | return yPos; | |
612 | } | |
613 | ||
614 | private int lastY; | |
615 | ||
616 | public void mousePressed() { | |
2bae07c9 | 617 | dragCube = dragStrip = dragChannel = false; |
bf551144 MS |
618 | lastY = mouseY; |
619 | if (mouseY >= stripFieldY) { | |
620 | if (mouseY < stripFieldY + lineHeight) { | |
621 | dragStrip = true; | |
622 | } | |
623 | } else if (mouseY >= cubeFieldY) { | |
624 | if (mouseY < cubeFieldY + lineHeight) { | |
625 | dragCube = true; | |
626 | } | |
2bae07c9 MS |
627 | } else if (mouseY >= channelFieldY) { |
628 | if (mouseY < channelFieldY + lineHeight) { | |
629 | dragChannel = true; | |
630 | } | |
bf551144 MS |
631 | } else if (mouseY >= firstChannelY) { |
632 | int index = objectClickIndex(firstChannelY); | |
633 | switch (index) { | |
634 | case 0: mappingTool.channelModeRed = !mappingTool.channelModeRed; break; | |
635 | case 1: mappingTool.channelModeGreen = !mappingTool.channelModeGreen; break; | |
636 | case 2: mappingTool.channelModeBlue = !mappingTool.channelModeBlue; break; | |
637 | } | |
638 | } else if (mouseY >= firstCubeY) { | |
639 | int index = objectClickIndex(firstCubeY); | |
640 | switch (index) { | |
641 | case 0: mappingTool.cubeMode = mappingTool.CUBE_MODE_ALL; break; | |
642 | case 1: mappingTool.cubeMode = mappingTool.CUBE_MODE_SINGLE_STRIP; break; | |
643 | case 2: mappingTool.cubeMode = mappingTool.CUBE_MODE_STRIP_PATTERN; break; | |
644 | } | |
645 | } else if (mouseY >= firstMappingY) { | |
646 | int index = objectClickIndex(firstMappingY); | |
2bae07c9 MS |
647 | switch (index) { |
648 | case 0: mappingTool.mappingMode = mappingTool.MAPPING_MODE_ALL; break; | |
649 | case 1: mappingTool.mappingMode = mappingTool.MAPPING_MODE_CHANNEL; break; | |
650 | case 2: mappingTool.mappingMode = mappingTool.MAPPING_MODE_SINGLE_CUBE; break; | |
bf551144 MS |
651 | } |
652 | } | |
653 | } | |
654 | ||
655 | public void mouseReleased() { | |
656 | } | |
657 | ||
658 | public void mouseDragged() { | |
659 | final int DRAG_THRESHOLD = 5; | |
660 | int dy = lastY - mouseY; | |
661 | if (abs(dy) >= DRAG_THRESHOLD) { | |
662 | lastY = mouseY; | |
663 | if (dragCube) { | |
664 | if (dy < 0) { | |
665 | mappingTool.decCube(); | |
666 | } else { | |
667 | mappingTool.incCube(); | |
668 | } | |
669 | } else if (dragStrip) { | |
670 | if (dy < 0) { | |
671 | mappingTool.decStrip(); | |
672 | } else { | |
673 | mappingTool.incStrip(); | |
674 | } | |
2bae07c9 MS |
675 | } else if (dragChannel) { |
676 | if (dy < 0) { | |
677 | mappingTool.decChannel(); | |
678 | } else { | |
679 | mappingTool.incChannel(); | |
680 | } | |
bf551144 MS |
681 | } |
682 | } | |
683 | ||
684 | } | |
685 | ||
686 | ||
687 | } | |
688 | ||
49815cc0 MS |
689 | void mousePressed() { |
690 | if (mouseX > ui.leftPos) { | |
691 | ui.mousePressed(); | |
692 | } | |
693 | } | |
694 | ||
695 | void mouseReleased() { | |
696 | if (mouseX > ui.leftPos) { | |
697 | ui.mouseReleased(); | |
698 | } | |
699 | } | |
700 | ||
701 | void mouseDragged() { | |
702 | if (mouseX > ui.leftPos) { | |
703 | ui.mouseDragged(); | |
704 | } | |
705 | } | |
706 |