Add Fabric basic tutorial
[SugarCubes.git] / _Overlay.pde
index 244b891d7d515e88416723966f755417f55119db..08e0befa89606f9d7ccfb8aaebd0e6682b822cca 100644 (file)
@@ -70,7 +70,12 @@ abstract class OverlayUI {
     textFont(titleFont);
     textAlign(LEFT);
     fill(#666666);
-    text("FPS: " + (((int)(frameRate * 10)) / 10.), 4, height-6);     
+    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);
   }
 
   protected int drawObjectList(int yPos, String title, Object[] items, Method stateMethod) {
@@ -148,7 +153,7 @@ abstract class OverlayUI {
     return (mouseY - firstItemY) / lineHeight;
   }
   
-  abstract public void draw();
+  abstract public void draw();  
   abstract public void mousePressed();
   abstract public void mouseDragged();
   abstract public void mouseReleased();
@@ -174,38 +179,12 @@ class ControlUI extends OverlayUI {
   private Method patternStateMethod;
   private Method transitionStateMethod;
   private Method effectStateMethod;
-  
-  private final int NUM_PATTERN_KNOBS = 8;
-  private final int NUM_TRANSITION_KNOBS = 4;
-  private final int NUM_EFFECT_KNOBS = 4;
-  
-  private int activeTransitionIndex = 0;
-  private int activeEffectIndex = 0;
-  
-  public final VirtualPatternKnob[] patternKnobs;
-  public final VirtualTransitionKnob[] transitionKnobs;
-  public final VirtualEffectKnob[] effectKnobs;
-      
+
   ControlUI() {    
     patternNames = classNameArray(patterns, "Pattern");
     transitionNames = classNameArray(transitions, "Transition");
     effectNames = classNameArray(effects, "Effect");
 
-    patternKnobs = new VirtualPatternKnob[NUM_PATTERN_KNOBS];
-    for (int i = 0; i < patternKnobs.length; ++i) {
-      patternKnobs[i] = new VirtualPatternKnob(i);
-    }
-
-    transitionKnobs = new VirtualTransitionKnob[NUM_TRANSITION_KNOBS];
-    for (int i = 0; i < transitionKnobs.length; ++i) {
-      transitionKnobs[i] = new VirtualTransitionKnob(i);
-    }
-
-    effectKnobs = new VirtualEffectKnob[NUM_EFFECT_KNOBS];
-    for (int i = 0; i < effectKnobs.length; ++i) {
-      effectKnobs[i] = new VirtualEffectKnob(i);
-    }
-
     try {
       patternStateMethod = getClass().getMethod("getState", LXPattern.class);
       effectStateMethod = getClass().getMethod("getState", LXEffect.class);
@@ -223,9 +202,9 @@ class ControlUI extends OverlayUI {
     yPos += controlSpacing;
     firstPatternKnobY = yPos;
     int xPos = leftTextPos;
-    for (int i = 0; i < NUM_PATTERN_KNOBS/2; ++i) {
-      drawKnob(xPos, yPos, knobSize, patternKnobs[i]);
-      drawKnob(xPos, yPos + knobSize + knobSpacing + knobLabelHeight, knobSize, patternKnobs[NUM_PATTERN_KNOBS/2 + i]);
+    for (int i = 0; i < glucose.NUM_PATTERN_KNOBS/2; ++i) {
+      drawKnob(xPos, yPos, knobSize, glucose.patternKnobs.get(i));
+      drawKnob(xPos, yPos + knobSize + knobSpacing + knobLabelHeight, knobSize, glucose.patternKnobs.get(glucose.NUM_PATTERN_KNOBS/2 + i));
       xPos += knobSize + knobSpacing;
     }
     yPos += 2*(knobSize + knobLabelHeight) + knobSpacing;
@@ -236,8 +215,8 @@ class ControlUI extends OverlayUI {
     yPos += controlSpacing;
     firstTransitionKnobY = yPos;
     xPos = leftTextPos;
-    for (int i = 0; i < transitionKnobs.length; ++i) {
-      drawKnob(xPos, yPos, knobSize, transitionKnobs[i]);
+    for (VirtualTransitionKnob knob : glucose.transitionKnobs) {
+      drawKnob(xPos, yPos, knobSize, knob);
       xPos += knobSize + knobSpacing;
     }
     yPos += knobSize + knobLabelHeight;
@@ -248,8 +227,8 @@ class ControlUI extends OverlayUI {
     yPos += controlSpacing;
     firstEffectKnobY = yPos;    
     xPos = leftTextPos;
-    for (int i = 0; i < effectKnobs.length; ++i) {
-      drawKnob(xPos, yPos, knobSize, effectKnobs[i]);
+    for (VirtualEffectKnob knob : glucose.effectKnobs) {    
+      drawKnob(xPos, yPos, knobSize, knob);
       xPos += knobSize + knobSpacing;
     }
     yPos += knobSize + knobLabelHeight;
@@ -288,7 +267,7 @@ class ControlUI extends OverlayUI {
   public int getState(LXEffect e) {
     if (e.isEnabled()) {
       return STATE_PENDING;
-    } else if (effects[activeEffectIndex] == e) {
+    } else if (e == glucose.getSelectedEffect()) {
       return STATE_ACTIVE;
     }
     return STATE_DEFAULT;
@@ -297,7 +276,7 @@ class ControlUI extends OverlayUI {
   public int getState(LXTransition t) {
     if (t == lx.getTransition()) {
       return STATE_PENDING;
-    } else if (t == transitions[activeTransitionIndex]) {
+    } else if (t == glucose.getSelectedTransition()) {
       return STATE_ACTIVE;
     }
     return STATE_DEFAULT;
@@ -344,54 +323,6 @@ class ControlUI extends OverlayUI {
     textFont(knobFont);
     text(knobLabel, xPos + knobSize/2, yPos + knobSize + knobLabelHeight - 2);
   }
-
-  class VirtualPatternKnob extends LXVirtualParameter {
-    private final int index;
-    
-    VirtualPatternKnob(int index) {
-      this.index = index;
-    }
-    
-    public LXParameter getRealParameter() {
-      List<LXParameter> parameters = glucose.getPattern().getParameters();
-      if (index < parameters.size()) {
-        return parameters.get(index);
-      }
-      return null;
-    }
-  }
-
-  class VirtualTransitionKnob extends LXVirtualParameter {
-    private final int index;
-    
-    VirtualTransitionKnob(int index) {
-      this.index = index;
-    }
-    
-    public LXParameter getRealParameter() {
-      List<LXParameter> parameters = transitions[activeTransitionIndex].getParameters();
-      if (index < parameters.size()) {
-        return parameters.get(index);
-      }
-      return null;
-    }
-  }
-
-  class VirtualEffectKnob extends LXVirtualParameter {
-    private final int index;
-    
-    VirtualEffectKnob(int index) {
-      this.index = index;
-    }
-    
-    public LXParameter getRealParameter() {
-      List<LXParameter> parameters = effects[activeEffectIndex].getParameters();
-      if (index < parameters.size()) {
-        return parameters.get(index);
-      }
-      return null;
-    }
-  }
   
   private int patternKnobIndex = -1;
   private int transitionKnobIndex = -1;
@@ -415,28 +346,27 @@ class ControlUI extends OverlayUI {
     } else if (mouseY > firstEffectY) {
       int effectIndex = objectClickIndex(firstEffectY);
       if (effectIndex < effects.length) {
-        if (activeEffectIndex == effectIndex) {
+        if (effects[effectIndex] == glucose.getSelectedEffect()) {
           effects[effectIndex].enable();
           releaseEffect = effectIndex;
         }
-        activeEffectIndex = effectIndex;        
+        glucose.setSelectedEffect(effectIndex);
       }
     } else if ((mouseY >= firstTransitionKnobY) && (mouseY < firstTransitionKnobY + knobSize + knobLabelHeight)) {
       transitionKnobIndex = (mouseX - leftTextPos) / (knobSize + knobSpacing);
     } else if (mouseY > firstTransitionY) {
       int transitionIndex = objectClickIndex(firstTransitionY);
       if (transitionIndex < transitions.length) {
-        activeTransitionIndex = transitionIndex;
+        glucose.setSelectedTransition(transitionIndex);
       }
     } else if ((mouseY >= firstPatternKnobY) && (mouseY < firstPatternKnobY + 2*(knobSize+knobLabelHeight) + knobSpacing)) {
       patternKnobIndex = (mouseX - leftTextPos) / (knobSize + knobSpacing);
       if (mouseY >= firstPatternKnobY + knobSize + knobLabelHeight + knobSpacing) {
-        patternKnobIndex += NUM_PATTERN_KNOBS / 2;
+        patternKnobIndex += glucose.NUM_PATTERN_KNOBS / 2;
       }      
     } else if (mouseY > firstPatternY) {
       int patternIndex = objectClickIndex(firstPatternY);
       if (patternIndex < patterns.length) {
-        patterns[patternIndex].setTransition(transitions[activeTransitionIndex]);
         lx.goIndex(patternIndex);
       }
     }
@@ -445,14 +375,14 @@ class ControlUI extends OverlayUI {
   public void mouseDragged() {
     int dy = lastY - mouseY;
     lastY = mouseY;
-    if (patternKnobIndex >= 0 && patternKnobIndex < NUM_PATTERN_KNOBS) {
-      LXParameter p = patternKnobs[patternKnobIndex];
+    if (patternKnobIndex >= 0 && patternKnobIndex < glucose.NUM_PATTERN_KNOBS) {
+      LXParameter p = glucose.patternKnobs.get(patternKnobIndex);
       p.setValue(constrain(p.getValuef() + dy*.01, 0, 1));
-    } else if (effectKnobIndex >= 0 && effectKnobIndex < NUM_EFFECT_KNOBS) {
-      LXParameter p = effectKnobs[effectKnobIndex];
+    } else if (effectKnobIndex >= 0 && effectKnobIndex < glucose.NUM_EFFECT_KNOBS) {
+      LXParameter p = glucose.effectKnobs.get(effectKnobIndex);
       p.setValue(constrain(p.getValuef() + dy*.01, 0, 1));
-    } else if (transitionKnobIndex >= 0 && transitionKnobIndex < NUM_TRANSITION_KNOBS) {
-      LXParameter p = transitionKnobs[transitionKnobIndex];
+    } else if (transitionKnobIndex >= 0 && transitionKnobIndex < glucose.NUM_TRANSITION_KNOBS) {
+      LXParameter p = glucose.transitionKnobs.get(transitionKnobIndex);
       p.setValue(constrain(p.getValuef() + dy*.01, 0, 1));
     }
   }
@@ -475,10 +405,13 @@ class MappingUI extends OverlayUI {
   private MappingTool mappingTool;
   
   private final String MAPPING_MODE_ALL = "All On";
+  private final String MAPPING_MODE_CHANNEL = "Channel";
   private final String MAPPING_MODE_SINGLE_CUBE = "Single Cube";
+  
   private final String[] mappingModes = {
     MAPPING_MODE_ALL,
-    MAPPING_MODE_SINGLE_CUBE,
+    MAPPING_MODE_CHANNEL,
+    MAPPING_MODE_SINGLE_CUBE
   };
   private final Method mappingModeStateMethod;
   
@@ -505,11 +438,13 @@ class MappingUI extends OverlayUI {
   private int firstMappingY;
   private int firstCubeY;
   private int firstChannelY;
+  private int channelFieldY;
   private int cubeFieldY;
   private int stripFieldY;
   
   private boolean dragCube;
   private boolean dragStrip;
+  private boolean dragChannel;
 
   MappingUI(MappingTool mappingTool) {
     this.mappingTool = mappingTool;
@@ -523,7 +458,14 @@ class MappingUI extends OverlayUI {
   }
   
   public int getMappingState(Object mappingMode) {
-    boolean active = (mappingMode == MAPPING_MODE_SINGLE_CUBE) == mappingTool.mappingModeSingleCube;
+    boolean active = false;
+    if (mappingMode == MAPPING_MODE_ALL) {
+      active = mappingTool.mappingMode == mappingTool.MAPPING_MODE_ALL;
+    } else if (mappingMode == MAPPING_MODE_CHANNEL) {
+      active = mappingTool.mappingMode == mappingTool.MAPPING_MODE_CHANNEL;
+    } else if (mappingMode == MAPPING_MODE_SINGLE_CUBE) {
+      active = mappingTool.mappingMode == mappingTool.MAPPING_MODE_SINGLE_CUBE;
+    }
     return active ? STATE_ACTIVE : STATE_DEFAULT;
   }
   
@@ -565,6 +507,10 @@ class MappingUI extends OverlayUI {
     firstChannelY = yPos + lineHeight + 6;    
     yPos = drawObjectList(yPos, "CHANNELS", channelModes, channelModes, channelModeStateMethod);    
     yPos += sectionSpacing;
+    
+    channelFieldY = yPos + lineHeight + 6;
+    yPos = drawValueField(yPos, "CHANNEL ID", mappingTool.channelIndex + 1);
+    yPos += sectionSpacing;
 
     cubeFieldY = yPos + lineHeight + 6;
     yPos = drawValueField(yPos, "CUBE ID", glucose.model.getRawIndexForCube(mappingTool.cubeIndex));
@@ -598,7 +544,7 @@ class MappingUI extends OverlayUI {
   private int lastY;
   
   public void mousePressed() {
-    dragCube = dragStrip = false;
+    dragCube = dragStrip = dragChannel = false;
     lastY = mouseY;
     if (mouseY >= stripFieldY) {
       if (mouseY < stripFieldY + lineHeight) {
@@ -608,6 +554,10 @@ class MappingUI extends OverlayUI {
       if (mouseY < cubeFieldY + lineHeight) {
         dragCube = true;
       }
+    } else if (mouseY >= channelFieldY) {
+      if (mouseY < channelFieldY + lineHeight) {
+        dragChannel = true;
+      }
     } else if (mouseY >= firstChannelY) {
       int index = objectClickIndex(firstChannelY);
       switch (index) {
@@ -624,8 +574,10 @@ class MappingUI extends OverlayUI {
       }
     } else if (mouseY >= firstMappingY) {
       int index = objectClickIndex(firstMappingY);
-      if (index < 2) {
-        mappingTool.mappingModeSingleCube = (index > 0);
+      switch (index) {
+        case 0: mappingTool.mappingMode = mappingTool.MAPPING_MODE_ALL; break;
+        case 1: mappingTool.mappingMode = mappingTool.MAPPING_MODE_CHANNEL; break;
+        case 2: mappingTool.mappingMode = mappingTool.MAPPING_MODE_SINGLE_CUBE; break;
       }
     }
   }
@@ -650,29 +602,160 @@ class MappingUI extends OverlayUI {
         } else {
           mappingTool.incStrip();
         }
+      } else if (dragChannel) {
+        if (dy < 0) {
+          mappingTool.decChannel();
+        } else {
+          mappingTool.incChannel();
+        }
       }
     }
     
   }
-
-
 }
 
-void mousePressed() {
-  if (mouseX > ui.leftPos) {
-    ui.mousePressed();
-  }
-}
-
-void mouseReleased() {
-  if (mouseX > ui.leftPos) {
-    ui.mouseReleased();
+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(int[][] frontChannels, int[][] rearChannels) {
+    channelList = new int[frontChannels.length + rearChannels.length][];
+    int channelIndex = 0;
+    for (int[] channel : frontChannels) {
+      channelList[channelIndex++] = channel;
+    }
+    for (int[] channel : rearChannels) {    
+      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 mouseDragged() {
-  if (mouseX > ui.leftPos) {
-    ui.mouseDragged();
+  
+  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 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;
+          }
+        }
+      }
+    }
+  }    
 }
-