Dropping Alex's anim in master
[SugarCubes.git] / _Overlay.pde
index 2ff364dc8060c9c20dc9b2626615b7614ba1fb59..0950b91c03b93e61beb8fafc545143bddf738b0f 100644 (file)
@@ -33,6 +33,7 @@ abstract class OverlayUI {
   protected final int scrollWidth = 14;
   protected final color lightBlue = #666699;
   protected final color lightGreen = #669966;
+  protected final int toggleButtonSize = 10;
   
   private PImage logo;
 
@@ -40,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 = 64;
+  protected final int pandaHeight = 13;
+  protected final int pandaTop = height-16;
+  
+  protected int eligibleLeft;
+  
   protected OverlayUI() {
     leftPos = width - w;
     leftTextPos = leftPos + 4;
@@ -71,17 +79,31 @@ abstract class OverlayUI {
     textFont(titleFont);
     textAlign(LEFT);
     fill(#666666);
-    text("FPS: " + (((int)(frameRate * 10)) / 10.), 4, height-6);
-    text("Target (-/+):", 50, height-6);
-    fill(#000000);
-    rect(104, height-16, 20, 12);
-    fill(#666666);
-    text("" + targetFramerate, 108, height-6);
-    text("PandaOutput (p):", 134, height-6);
+    int lPos = 4;
+    String fps = "FPS: " + (((int)(frameRate * 10)) / 10.);
+    text(fps, lPos, height-6);
+    lPos += 48;
+    
+    String target = "Target (-/+):";
+    text(target, lPos, height-6);
     fill(#000000);
-    rect(214, height-16, 26, 12);
+    lPos += textWidth(target) + 4;
+    rect(lPos, height-16, 24, 13);
     fill(#666666);
-    text(pandaBoardsEnabled ? "ON" : "OFF", 218, height-6);
+    text("" + targetFramerate, lPos + (24 - textWidth("" + targetFramerate))/2, height-6);
+    lPos += 32;
+    String pandaOutput = "PandaOutput (p):";
+    text(pandaOutput, lPos, height-6);
+    lPos += textWidth(pandaOutput)+4;
+    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 + (pandaWidth - textWidth(p.ip)) / 2, height-6);
+      lPos += pandaWidth + 8;
+    }
 
   }
 
@@ -99,6 +121,17 @@ abstract class OverlayUI {
     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);
@@ -106,6 +139,7 @@ abstract class OverlayUI {
     textAlign(LEFT);
     text(title, leftTextPos, yPos += lineHeight);    
     if (items != null) {
+      boolean hasScroll = (scrollPos > 0) || (scrollLength < items.length);
       textFont(itemFont);
       color textColor;      
       boolean even = true;
@@ -132,12 +166,18 @@ abstract class OverlayUI {
             fill(even ? #666666 : #777777);
             break;
         }
+        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 ((scrollPos > 0) || (scrollLength < items.length)) {
+      if (hasScroll) {
         int yHere = yPos+6;
         noStroke();
         fill(color(0, 0, 0, 50));
@@ -203,6 +243,9 @@ class ControlUI extends OverlayUI {
   private int firstEffectY;
   private int firstEffectKnobY;
   
+  private int autoRotateX;
+  private int autoRotateY;
+  
   private final int PATTERN_LIST_LENGTH = 8;
   private int patternScrollPos = 0;
 
@@ -229,6 +272,11 @@ 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, PATTERN_LIST_LENGTH, patternScrollPos);
     yPos += controlSpacing;
@@ -370,6 +418,35 @@ class ControlUI extends OverlayUI {
     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();
@@ -404,7 +481,11 @@ class ControlUI extends OverlayUI {
       } else {
         int patternIndex = objectClickIndex(firstPatternY);
         if (patternIndex < patterns.length) {
-          lx.goIndex(patternIndex + patternScrollPos);
+          if (lx.isAutoTransitionEnabled() && (mouseX > eligibleLeft)) {
+            patterns[patternIndex + patternScrollPos].toggleEligible();
+          } else { 
+            lx.goIndex(patternIndex + patternScrollPos);
+          }
         }
       }
     }
@@ -600,6 +681,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;
@@ -670,7 +756,7 @@ class MappingUI extends OverlayUI {
 
 class DebugUI {
   
-  final int[][] channelList;
+  final ChannelMapping[] channelList;
   final int debugX = 10;
   final int debugY = 42;
   final int debugXSpacing = 28;
@@ -681,14 +767,14 @@ class DebugUI {
   final int DEBUG_STATE_WHITE = 1;
   final int DEBUG_STATE_OFF = 2;
   
-  DebugUI(int[][] frontChannels, int[][] rearChannels) {
-    channelList = new int[frontChannels.length + rearChannels.length][];
+  DebugUI(PandaMapping[] pandaMappings) {
+    int totalChannels = pandaMappings.length * PandaMapping.CHANNELS_PER_BOARD;
+    channelList = new ChannelMapping[totalChannels];
     int channelIndex = 0;
-    for (int[] channel : frontChannels) {
-      channelList[channelIndex++] = channel;
-    }
-    for (int[] channel : rearChannels) {    
-      channelList[channelIndex++] = channel;
+    for (PandaMapping pm : pandaMappings) {
+      for (ChannelMapping channel : pm.channelList) {
+        channelList[channelIndex++] = channel;
+      }
     }
     for (int i = 0; i < debugState.length; ++i) {
       for (int j = 0; j < debugState[i].length; ++j) {
@@ -697,7 +783,7 @@ class DebugUI {
     }
   }
   
-  void draw() {
+  void draw() {    
     noStroke();
     int xBase = debugX;
     int yPos = debugY;
@@ -706,26 +792,44 @@ class DebugUI {
     rect(4, 32, 172, 388);
     
     int channelNum = 0;
-    for (int[] channel : channelList) {
+    for (ChannelMapping channel : channelList) {
       int xPos = xBase;
       drawNumBox(xPos, yPos, channelNum+1, debugState[channelNum][0]);
+      xPos += debugXSpacing;
       
-      boolean first = true;
-      int cubeNum = 0;
-      for (int cube : channel) {
-        if (cube == 0) {
+      switch (channel.mode) {
+        case ChannelMapping.MODE_CUBES:
+          int stateIndex = 0;
+          boolean first = true;
+          for (int rawCubeIndex : channel.objectIndices) {
+            if (rawCubeIndex < 0) {
+              break;
+            }
+            if (first) {
+              first = false;
+            } else {
+              stroke(#999999);          
+              line(xPos - 12, yPos + 8, xPos, yPos + 8);
+            }
+            drawNumBox(xPos, yPos, rawCubeIndex, debugState[channelNum][stateIndex+1]);
+            ++stateIndex;
+            xPos += debugXSpacing;            
+          }
           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;
-      }
+        case ChannelMapping.MODE_BASS:
+          drawNumBox(xPos, yPos, "B", debugState[channelNum][1]);
+          break;
+        case ChannelMapping.MODE_SPEAKER:
+          drawNumBox(xPos, yPos, "S" + channel.objectIndices[0], debugState[channelNum][1]);
+          break;
+        case ChannelMapping.MODE_FLOOR:
+          drawNumBox(xPos, yPos, "F", debugState[channelNum][1]);
+          break;
+        case ChannelMapping.MODE_NULL:
+          break;
+        default:
+          throw new RuntimeException("Unhandled channel mapping mode: " + channel.mode);
+      }          
       
       yPos += debugYSpacing;
       ++channelNum;
@@ -773,20 +877,61 @@ class DebugUI {
     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;
+    int state;
+    for (ChannelMapping channel : channelList) {
+      switch (channel.mode) {
+        case ChannelMapping.MODE_CUBES:
+          int cubeIndex = 1;
+          for (int rawCubeIndex : channel.objectIndices) {
+            if (rawCubeIndex >= 0) {
+              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;
           }
-        }
-        ++cubeIndex;
+          break;
+            
+         case ChannelMapping.MODE_BASS:
+           state = debugState[channelIndex][1];
+           if (state != DEBUG_STATE_ANIM) {
+              color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
+              for (Point p : glucose.model.bassBox.points) {
+                colors[p.index] = debugColor;
+              }
+           }
+           break;
+
+         case ChannelMapping.MODE_FLOOR:
+           state = debugState[channelIndex][1];
+           if (state != DEBUG_STATE_ANIM) {
+              color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
+              for (Point p : glucose.model.boothFloor.points) {
+                colors[p.index] = debugColor;
+              }
+           }
+           break;
+           
+         case ChannelMapping.MODE_SPEAKER:
+           state = debugState[channelIndex][1];
+           if (state != DEBUG_STATE_ANIM) {
+              color debugColor = (state == DEBUG_STATE_WHITE) ? white : off;
+              for (Point p : glucose.model.speakers.get(channel.objectIndices[0]).points) {
+                colors[p.index] = debugColor;
+              }
+           }
+           break;
+           
+         case ChannelMapping.MODE_NULL:
+           break;
+           
+        default:
+          throw new RuntimeException("Unhandled channel mapping mode: " + channel.mode);           
       }
       ++channelIndex;
     }