2 * Overlay UI that indicates pattern control, etc. This will be moved
3 * into the Processing library once it is stabilized and need not be
8 private final PFont titleFont = createFont("Myriad Pro", 10);
9 private final PFont itemFont = createFont("Myriad Pro", 11);
10 private final PFont knobFont = titleFont;
11 private final int w = 140;
12 private final int leftPos;
13 private final int leftTextPos;
14 private final int lineHeight = 20;
15 private final int sectionSpacing = 12;
16 private final int tempoHeight = 20;
17 private final int knobSize = 28;
18 private final int knobSpacing = 6;
19 private final int knobLabelHeight = 14;
20 private final color lightBlue = #666699;
21 private final color lightGreen = #669966;
23 private final String[] patternNames;
24 private final String[] transitionNames;
25 private final String[] effectNames;
29 private int firstPatternY;
30 private int firstTransitionY;
31 private int firstEffectY;
32 private int firstKnobY;
35 private Method patternStateMethod;
36 private Method transitionStateMethod;
37 private Method effectStateMethod;
41 leftTextPos = leftPos + 4;
42 logo = loadImage("logo-sm.png");
44 patternNames = classNameArray(patterns);
45 transitionNames = classNameArray(transitions);
46 effectNames = classNameArray(effects);
49 patternStateMethod = getClass().getMethod("getState", LXPattern.class);
50 effectStateMethod = getClass().getMethod("getState", LXEffect.class);
51 transitionStateMethod = getClass().getMethod("getState", LXTransition.class);
52 } catch (Exception x) {
53 throw new RuntimeException(x);
60 text("Tap 'u' to restore UI", width-4, height-6);
66 stroke(color(0, 0, 100));
67 // fill(color(0, 0, 50, 50)); // alpha is bad for perf
68 fill(color(0, 0, 30));
69 rect(leftPos-1, -1, w+2, height+2);
72 firstPatternY = yPos + lineHeight + 6;
73 yPos = drawObjectList(yPos, "PATTERN", patterns, patternNames, patternStateMethod);
75 yPos += sectionSpacing;
76 yPos = drawObjectList(yPos, "CONTROL", null, null, null);
79 int xPos = leftTextPos;
80 for (int i = 0; i < glucose.NUM_PATTERN_KNOBS/2; ++i) {
81 drawKnob(xPos, yPos, knobSize, glucose.patternKnobs[i]);
82 drawKnob(xPos, yPos + knobSize + knobSpacing + knobLabelHeight, knobSize, glucose.patternKnobs[glucose.NUM_PATTERN_KNOBS/2 + i]);
83 xPos += knobSize + knobSpacing;
85 yPos += 2*(knobSize + knobLabelHeight) + knobSpacing;
87 yPos += sectionSpacing;
88 firstTransitionY = yPos + lineHeight + 6;
89 yPos = drawObjectList(yPos, "TRANSITION", transitions, transitionNames, transitionStateMethod);
91 yPos += sectionSpacing;
92 firstEffectY = yPos + lineHeight + 6;
93 yPos = drawObjectList(yPos, "FX", effects, effectNames, effectStateMethod);
95 yPos += sectionSpacing;
96 yPos = drawObjectList(yPos, "TEMPO", null, null, null);
100 fill(tempoDown ? lightGreen : color(0, 0, 35 - 8*lx.tempo.rampf()));
101 rect(leftPos + 4, yPos, w - 8, tempoHeight);
104 text("" + ((int)(lx.tempo.bpmf() * 100) / 100.), leftPos + w/2., yPos + tempoHeight - 6);
110 text("Tap 'u' to hide UI (~+3FPS)", leftTextPos, height-6);
113 public Knob getOrNull(List<Knob> items, int index) {
114 if (index < items.size()) {
115 return items.get(index);
120 public void drawFPS() {
124 text("FPS: " + (((int)(frameRate * 10)) / 10.), 4, height-6);
127 private final int STATE_DEFAULT = 0;
128 private final int STATE_ACTIVE = 1;
129 private final int STATE_PENDING = 2;
131 public int getState(LXPattern p) {
132 if (p == lx.getPattern()) {
134 } else if (p == lx.getNextPattern()) {
135 return STATE_PENDING;
137 return STATE_DEFAULT;
140 public int getState(LXEffect e) {
141 return e.isEnabled() ? STATE_ACTIVE : STATE_DEFAULT;
144 public int getState(LXTransition t) {
145 if (t == lx.getTransition()) {
146 return STATE_PENDING;
147 } else if (t == transitions[activeTransitionIndex]) {
150 return STATE_DEFAULT;
153 protected int drawObjectList(int yPos, String title, Object[] items, Method stateMethod) {
154 return drawObjectList(yPos, title, items, classNameArray(items), stateMethod);
157 private int drawObjectList(int yPos, String title, Object[] items, String[] names, Method stateMethod) {
162 text(title, leftTextPos, yPos += lineHeight);
167 for (int i = 0; i < items.length; ++i) {
169 int state = STATE_DEFAULT;
171 state = ((Integer) stateMethod.invoke(this, o)).intValue();
172 } catch (Exception x) {
173 throw new RuntimeException(x);
182 textColor = color(0, 0, 75 + 15*sin(millis()/200.));;
186 fill(even ? #666666 : #777777);
189 rect(leftPos, yPos+6, width, lineHeight);
191 text(names[i], leftTextPos, yPos += lineHeight);
198 private void drawKnob(int xPos, int yPos, int knobSize, Knob knob) {
199 final float knobIndent = .4;
200 final float knobValue = knob.getValuef();
201 String knobLabel = knob.getLabel();
202 if (knobLabel.length() > 4) {
203 knobLabel = knobLabel.substring(0, 4);
204 } else if (knobLabel.length() == 0) {
210 arc(xPos + knobSize/2, yPos + knobSize/2, knobSize, knobSize, HALF_PI + knobIndent, HALF_PI + knobIndent + (TWO_PI-2*knobIndent));
213 arc(xPos + knobSize/2, yPos + knobSize/2, knobSize, knobSize, HALF_PI + knobIndent, HALF_PI + knobIndent + (TWO_PI-2*knobIndent)*knobValue);
216 ellipse(xPos + knobSize/2, yPos + knobSize/2, knobSize/2, knobSize/2);
219 rect(xPos, yPos + knobSize + 2, knobSize, knobLabelHeight - 2);
223 text(knobLabel, xPos + knobSize/2, yPos + knobSize + knobLabelHeight - 2);
227 private String[] classNameArray(Object[] objects) {
228 if (objects == null) {
231 String[] names = new String[objects.length];
232 for (int i = 0; i < objects.length; ++i) {
233 names[i] = className(objects[i]);
238 private String className(Object p) {
239 String s = p.getClass().getName();
241 if ((li = s.lastIndexOf(".")) > 0) {
242 s = s.substring(li + 1);
244 if (s.indexOf("SugarCubes$") == 0) {
245 return s.substring("SugarCubes$".length());
250 private int knobIndex = -1;
252 private int releaseEffect = -1;
253 private boolean tempoDown = false;
255 public void mousePressed() {
259 if (mouseY > tempoY) {
260 if (mouseY - tempoY < tempoHeight) {
264 } else if (mouseY > firstEffectY) {
265 int effectIndex = (mouseY - firstEffectY) / lineHeight;
266 if (effectIndex < effects.length) {
267 if (effects[effectIndex].isMomentary()) {
268 effects[effectIndex].enable();
269 releaseEffect = effectIndex;
271 effects[effectIndex].toggle();
274 } else if (mouseY > firstTransitionY) {
275 int transitionIndex = (mouseY - firstTransitionY) / lineHeight;
276 if (transitionIndex < transitions.length) {
277 activeTransitionIndex = transitionIndex;
279 } else if ((mouseY >= firstKnobY) && (mouseY < firstKnobY + 2*(knobSize+knobLabelHeight) + knobSpacing)) {
280 knobIndex = (mouseX - leftTextPos) / (knobSize + knobSpacing);
281 if (mouseY >= firstKnobY + knobSize + knobLabelHeight + knobSpacing) {
282 knobIndex += glucose.NUM_PATTERN_KNOBS / 2;
284 } else if (mouseY > firstPatternY) {
285 int patternIndex = (mouseY - firstPatternY) / lineHeight;
286 if (patternIndex < patterns.length) {
287 patterns[patternIndex].setTransition(transitions[activeTransitionIndex]);
288 lx.goIndex(patternIndex);
293 public void mouseDragged() {
294 int dy = lastY - mouseY;
296 if (knobIndex >= 0 && knobIndex < glucose.NUM_PATTERN_KNOBS) {
297 Knob k = glucose.patternKnobs[knobIndex];
298 k.setValue(k.getValuef() + dy*.01);
302 public void mouseReleased() {
304 if (releaseEffect >= 0) {
305 effects[releaseEffect].trigger();
311 void mousePressed() {
312 if (mouseX > ui.leftPos) {
317 void mouseReleased() {
318 if (mouseX > ui.leftPos) {
323 void mouseDragged() {
324 if (mouseX > ui.leftPos) {