Change to list clearing
[SugarCubes.git] / _Overlay.pde
index 827223a5e83f89ef70c8be045290c94ea10a1eea..a02aa12fc653111915f22c6d93673ec21d91fc41 100644 (file)
@@ -30,8 +30,10 @@ abstract class OverlayUI {
   protected final float knobIndent = .4;  
   protected final int knobSpacing = 6;
   protected final int knobLabelHeight = 14;
+  protected final int scrollWidth = 14;
   protected final color lightBlue = #666699;
   protected final color lightGreen = #669966;
+  protected final int toggleButtonSize = 10;
   
   private PImage logo;
 
@@ -39,6 +41,13 @@ abstract class OverlayUI {
   protected final int STATE_ACTIVE = 1;
   protected final int STATE_PENDING = 2;
   
+  protected int[] pandaLeft = new int[pandaBoards.length];
+  protected final int pandaWidth = 56;
+  protected final int pandaHeight = 13;
+  protected final int pandaTop = height-16;
+  
+  protected int eligibleLeft;
+  
   protected OverlayUI() {
     leftPos = width - w;
     leftTextPos = leftPos + 4;
@@ -73,26 +82,61 @@ abstract class OverlayUI {
     text("FPS: " + (((int)(frameRate * 10)) / 10.), 4, height-6);
     text("Target (-/+):", 50, height-6);
     fill(#000000);
-    rect(104, height-16, 20, 12);
+    rect(104, height-16, 20, 13);
     fill(#666666);
     text("" + targetFramerate, 108, height-6);
+    text("PandaOutput (p):", 134, height-6);
+    int lPos = 214;
+    int pi = 0;
+    for (PandaDriver p : pandaBoards) {
+      pandaLeft[pi++] = lPos;
+      fill(p.enabled ? #666666 : #000000);
+      rect(lPos, pandaTop, pandaWidth, pandaHeight);
+      fill(p.enabled ? #000000 : #666666);
+      text(p.ip, lPos + 4, height-6);
+      lPos += 60;
+    }
+
   }
 
   protected int drawObjectList(int yPos, String title, Object[] items, Method stateMethod) {
-    return drawObjectList(yPos, title, items, classNameArray(items, null), stateMethod);
+    int sz = (items != null) ? items.length : 0;
+    return drawObjectList(yPos, title, items, stateMethod, sz, 0);
   }
-  
+
+  protected int drawObjectList(int yPos, String title, Object[] items, Method stateMethod, int scrollLength, int scrollPos) {
+    return drawObjectList(yPos, title, items, classNameArray(items, null), stateMethod, scrollLength, scrollPos);
+  }
+
   protected int drawObjectList(int yPos, String title, Object[] items, String[] names, Method stateMethod) {
+    int sz = (items != null) ? items.length : 0;
+    return drawObjectList(yPos, title, items, names, stateMethod, sz, 0);
+  }
+  
+  protected void drawToggleButton(float x, float y, boolean eligible, color textColor) {
+    noFill();
+    stroke(textColor);
+    rect(x, y, toggleButtonSize, toggleButtonSize);
+    if (eligible) {
+      noStroke();
+      fill(textColor);
+      rect(x + 2, y + 2, toggleButtonSize - 4, toggleButtonSize - 4);
+    }
+  }    
+  
+  protected int drawObjectList(int yPos, String title, Object[] items, String[] names, Method stateMethod, int scrollLength, int scrollPos) {
     noStroke();
     fill(titleColor);
     textFont(titleFont);
     textAlign(LEFT);
     text(title, leftTextPos, yPos += lineHeight);    
     if (items != null) {
+      boolean hasScroll = (scrollPos > 0) || (scrollLength < items.length);
       textFont(itemFont);
       color textColor;      
       boolean even = true;
-      for (int i = 0; i < items.length; ++i) {
+      int yTop = yPos+6;
+      for (int i = scrollPos; i < items.length && i < (scrollPos + scrollLength); ++i) {
         Object o = items[i];
         int state = STATE_DEFAULT;
         try {
@@ -114,11 +158,27 @@ abstract class OverlayUI {
             fill(even ? #666666 : #777777);
             break;
         }
-        rect(leftPos, yPos+6, width, lineHeight);
+        noStroke();
+        rect(leftPos, yPos+6, w, lineHeight);
         fill(textColor);
         text(names[i], leftTextPos, yPos += lineHeight);
+        if (lx.isAutoTransitionEnabled() && items[i] instanceof LXPattern) {
+          boolean eligible = ((LXPattern)items[i]).isEligible();
+          eligibleLeft = leftPos + w - (hasScroll ? scrollWidth : 0) - 15;
+          drawToggleButton(eligibleLeft, yPos-8, eligible, textColor);
+        }
         even = !even;       
       }
+      if (hasScroll) {
+        int yHere = yPos+6;
+        noStroke();
+        fill(color(0, 0, 0, 50));
+        rect(leftPos + w - scrollWidth, yTop, scrollWidth, yHere - yTop);
+        fill(#666666);
+        rect(leftPos + w - scrollWidth + 2, yTop + (yHere-yTop) * (scrollPos / (float)items.length), scrollWidth - 4, (yHere - yTop) * (scrollLength / (float)items.length));
+        
+      }
+      
     }
     return yPos;
   }
@@ -157,6 +217,7 @@ abstract class OverlayUI {
   abstract public void mousePressed();
   abstract public void mouseDragged();
   abstract public void mouseReleased();
+  abstract public void mouseWheel(int delta);
 }
 
 /**
@@ -173,6 +234,12 @@ class ControlUI extends OverlayUI {
   private int firstTransitionKnobY;
   private int firstEffectY;
   private int firstEffectKnobY;
+  
+  private int autoRotateX;
+  private int autoRotateY;
+  
+  private final int PATTERN_LIST_LENGTH = 8;
+  private int patternScrollPos = 0;
 
   private int tempoY;
   
@@ -197,8 +264,13 @@ class ControlUI extends OverlayUI {
   public void draw() {    
     drawLogoAndBackground();
     int yPos = 0;
+    autoRotateX = leftPos + w - 29;
+    autoRotateY = yPos + 12;
+    drawToggleButton(autoRotateX, autoRotateY, lx.isAutoTransitionEnabled(), #999999);
+    fill(lx.isAutoTransitionEnabled() ? #222222: #999999);
+    text("A", autoRotateX + 2, autoRotateY + 9);
     firstPatternY = yPos + lineHeight + 6;
-    yPos = drawObjectList(yPos, "PATTERN", patterns, patternNames, patternStateMethod);
+    yPos = drawObjectList(yPos, "PATTERN", patterns, patternNames, patternStateMethod, PATTERN_LIST_LENGTH, patternScrollPos);
     yPos += controlSpacing;
     firstPatternKnobY = yPos;
     int xPos = leftTextPos;
@@ -327,6 +399,7 @@ class ControlUI extends OverlayUI {
   private int patternKnobIndex = -1;
   private int transitionKnobIndex = -1;
   private int effectKnobIndex = -1;
+  private boolean patternScrolling = false;
   
   private int lastY;
   private int releaseEffect = -1;
@@ -336,6 +409,36 @@ class ControlUI extends OverlayUI {
     lastY = mouseY;
     patternKnobIndex = transitionKnobIndex = effectKnobIndex = -1;
     releaseEffect = -1;
+    patternScrolling = false;
+    
+    for (int p = 0; p < pandaLeft.length; ++p) {
+      int xp = pandaLeft[p];
+      if ((mouseX >= xp) &&
+          (mouseX < xp + pandaWidth) &&
+          (mouseY >= pandaTop) &&
+          (mouseY < pandaTop + pandaHeight)) {
+          pandaBoards[p].toggle();
+      }
+    }
+    
+    if (mouseX < leftPos) {
+      return;
+    }
+    
+    if ((mouseX >= autoRotateX) &&
+        (mouseX < autoRotateX + toggleButtonSize) &&
+        (mouseY >= autoRotateY) &&
+        (mouseY < autoRotateY + toggleButtonSize)) {
+      if (lx.isAutoTransitionEnabled()) {
+        lx.disableAutoTransition();
+        println("Auto pattern transition disabled");
+      } else {
+        lx.enableAutoTransition(60000);
+        println("Auto pattern transition enabled");        
+      }
+      return;
+    }
+    
     if (mouseY > tempoY) {
       if (mouseY - tempoY < tempoHeight) {
         lx.tempo.tap();
@@ -365,15 +468,25 @@ class ControlUI extends OverlayUI {
         patternKnobIndex += glucose.NUM_PATTERN_KNOBS / 2;
       }      
     } else if (mouseY > firstPatternY) {
-      int patternIndex = objectClickIndex(firstPatternY);
-      if (patternIndex < patterns.length) {
-        lx.goIndex(patternIndex);
+      if ((patterns.length > PATTERN_LIST_LENGTH) && (mouseX > width - scrollWidth)) {
+        patternScrolling = true;
+      } else {
+        int patternIndex = objectClickIndex(firstPatternY);
+        if (patternIndex < patterns.length) {
+          if (lx.isAutoTransitionEnabled() && (mouseX > eligibleLeft)) {
+            patterns[patternIndex + patternScrollPos].toggleEligible();
+          } else { 
+            lx.goIndex(patternIndex + patternScrollPos);
+          }
+        }
       }
     }
   }
   
+  int scrolldy = 0;
   public void mouseDragged() {
     int dy = lastY - mouseY;
+    scrolldy += dy;
     lastY = mouseY;
     if (patternKnobIndex >= 0 && patternKnobIndex < glucose.NUM_PATTERN_KNOBS) {
       LXParameter p = glucose.patternKnobs.get(patternKnobIndex);
@@ -384,10 +497,15 @@ class ControlUI extends OverlayUI {
     } else if (transitionKnobIndex >= 0 && transitionKnobIndex < glucose.NUM_TRANSITION_KNOBS) {
       LXParameter p = glucose.transitionKnobs.get(transitionKnobIndex);
       p.setValue(constrain(p.getValuef() + dy*.01, 0, 1));
+    } else if (patternScrolling) {
+      int scroll = scrolldy / lineHeight;
+      scrolldy = scrolldy % lineHeight;
+      patternScrollPos = constrain(patternScrollPos - scroll, 0, patterns.length - PATTERN_LIST_LENGTH);
     }
   }
     
   public void mouseReleased() {
+    patternScrolling = false;
     tempoDown = false;
     if (releaseEffect >= 0) {
       effects[releaseEffect].trigger();
@@ -395,6 +513,15 @@ class ControlUI extends OverlayUI {
     }
   }
   
+  public void mouseWheel(int delta) {
+    if (mouseY > firstPatternY) {
+      int patternIndex = objectClickIndex(firstPatternY);
+      if (patternIndex < PATTERN_LIST_LENGTH) {
+        patternScrollPos = constrain(patternScrollPos + delta, 0, patterns.length - PATTERN_LIST_LENGTH);
+      }
+    }
+  }
+  
 }
 
 /**
@@ -546,6 +673,11 @@ class MappingUI extends OverlayUI {
   public void mousePressed() {
     dragCube = dragStrip = dragChannel = false;
     lastY = mouseY;
+    
+    if (mouseX < leftPos) {
+      return;
+    }
+    
     if (mouseY >= stripFieldY) {
       if (mouseY < stripFieldY + lineHeight) {
         dragStrip = true;
@@ -582,8 +714,8 @@ class MappingUI extends OverlayUI {
     }
   }
 
-  public void mouseReleased() {
-  }
+  public void mouseReleased() {}
+  public void mouseWheel(int delta) {}
 
   public void mouseDragged() {
     final int DRAG_THRESHOLD = 5;
@@ -612,25 +744,150 @@ class MappingUI extends OverlayUI {
     }
     
   }
-
-
 }
 
-void mousePressed() {
-  if (mouseX > ui.leftPos) {
-    ui.mousePressed();
+class DebugUI {
+  
+  final int[][] channelList;
+  final int debugX = 10;
+  final int debugY = 42;
+  final int debugXSpacing = 28;
+  final int debugYSpacing = 22;
+  final int[][] debugState = new int[17][6];
+  
+  final int DEBUG_STATE_ANIM = 0;
+  final int DEBUG_STATE_WHITE = 1;
+  final int DEBUG_STATE_OFF = 2;
+  
+  DebugUI(PandaMapping[] pandaMappings) {
+    int totalChannels = pandaMappings.length * PandaMapping.CHANNELS_PER_BOARD;
+    channelList = new int[totalChannels][];
+    int channelIndex = 0;
+    for (PandaMapping pm : pandaMappings) {
+      for (int[] channel : pm.channelList) {
+        channelList[channelIndex++] = channel;
+      }
+    }
+    for (int i = 0; i < debugState.length; ++i) {
+      for (int j = 0; j < debugState[i].length; ++j) {
+        debugState[i][j] = DEBUG_STATE_ANIM;
+      }
+    }
   }
-}
-
-void mouseReleased() {
-  if (mouseX > ui.leftPos) {
-    ui.mouseReleased();
+  
+  void draw() {    
+    noStroke();
+    int xBase = debugX;
+    int yPos = debugY;
+    
+    fill(color(0, 0, 0, 80));
+    rect(4, 32, 172, 388);
+    
+    int channelNum = 0;
+    for (int[] channel : channelList) {
+      int xPos = xBase;
+      drawNumBox(xPos, yPos, channelNum+1, debugState[channelNum][0]);
+      
+      boolean first = true;
+      int cubeNum = 0;
+      for (int cube : channel) {
+        if (cube <= 0) {
+          break;
+        }
+        xPos += debugXSpacing;
+        if (first) {
+          first = false;
+        } else {
+          stroke(#999999);          
+          line(xPos - 12, yPos + 8, xPos, yPos + 8);
+        }
+        drawNumBox(xPos, yPos, cube, debugState[channelNum][cubeNum+1]);
+        ++cubeNum;
+      }
+      
+      yPos += debugYSpacing;
+      ++channelNum;
+    }
+    drawNumBox(xBase, yPos, "A", debugState[channelNum][0]);
   }
-}
-
-void mouseDragged() {
-  if (mouseX > ui.leftPos) {
-    ui.mouseDragged();
+  
+  void drawNumBox(int xPos, int yPos, int label, int state) {
+    drawNumBox(xPos, yPos, "" + label, state);
+  }
+  
+  void drawNumBox(int xPos, int yPos, String label, int state) {
+    noFill();
+    color textColor = #cccccc;
+    switch (state) {
+      case DEBUG_STATE_ANIM:
+        noStroke();
+        fill(#880000);
+        rect(xPos, yPos, 16, 8);
+        fill(#000088);
+        rect(xPos, yPos+8, 16, 8);
+        noFill();
+        stroke(textColor);
+        rect(xPos, yPos, 16, 16); 
+        break;
+      case DEBUG_STATE_WHITE:
+        stroke(textColor);
+        fill(#e9e9e9);
+        rect(xPos, yPos, 16, 16);
+        textColor = #333333;
+        break;
+      case DEBUG_STATE_OFF:
+        stroke(textColor);
+        rect(xPos, yPos, 16, 16);
+        break;
+    }
+    
+    noStroke();
+    fill(textColor);
+    text(label, xPos + 2, yPos + 12);
+  
   }
+  
+  void maskColors(color[] colors) {
+    color white = #FFFFFF;
+    color off = #000000;
+    int channelIndex = 0;
+    for (int[] channel : channelList) {
+      int cubeIndex = 1;
+      for (int rawCubeIndex : channel) {
+        if (rawCubeIndex > 0) {
+          int state = debugState[channelIndex][cubeIndex];
+          if (state != DEBUG_STATE_ANIM) {
+            color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
+            Cube cube = glucose.model.getCubeByRawIndex(rawCubeIndex);
+            for (Point p : cube.points) {
+              colors[p.index] = debugColor;
+            }
+          }
+        }
+        ++cubeIndex;
+      }
+      ++channelIndex;
+    }
+  }
+  
+  void mousePressed() {
+    int dx = (mouseX - debugX) / debugXSpacing;
+    int dy = (mouseY - debugY) / debugYSpacing;
+    if ((dy >= 0) && (dy < debugState.length)) {
+      if ((dx >= 0) && (dx < debugState[dy].length)) {
+        int newState = debugState[dy][dx] = (debugState[dy][dx] + 1) % 3;
+        if (dy == 16) {
+          for (int[] states : debugState) {
+            for (int i = 0; i < states.length; ++i) {
+              states[i] = newState;
+            }
+          }
+        } else if (dx == 0) {
+          for (int i = 0; i < debugState[dy].length; ++i) {
+            debugState[dy][i] = newState;
+          }
+        }
+      }
+    }
+  }    
 }
-