X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=UIImplementation.pde;fp=UIImplementation.pde;h=0ea8073ddb57d6701a6a0a1b55df6fc88c89bbe8;hb=cc9e8c8be45767207e09c434bad100b0156877e6;hp=0000000000000000000000000000000000000000;hpb=fdb2c3cbacdba5d9527712ef7f75decea919ab32;p=SugarCubes.git diff --git a/UIImplementation.pde b/UIImplementation.pde new file mode 100644 index 0000000..0ea8073 --- /dev/null +++ b/UIImplementation.pde @@ -0,0 +1,551 @@ +/** + * DOUBLE BLACK DIAMOND DOUBLE BLACK DIAMOND + * + * //\\ //\\ //\\ //\\ + * ///\\\ ///\\\ ///\\\ ///\\\ + * \\\/// \\\/// \\\/// \\\/// + * \\// \\// \\// \\// + * + * EXPERTS ONLY!! EXPERTS ONLY!! + * + * Custom UI components using the framework. + */ + +class UIPatternDeck extends UIWindow { + + LXDeck deck; + + public UIPatternDeck(LXDeck deck, String label, float x, float y, float w, float h) { + super(label, x, y, w, h); + this.deck = deck; + int yp = titleHeight; + + List items = new ArrayList(); + for (LXPattern p : deck.getPatterns()) { + items.add(new PatternScrollItem(p)); + } + final UIScrollList patternList = new UIScrollList(1, yp, w-2, 140).setItems(items); + patternList.addToContainer(this); + yp += patternList.h + 10; + + final UIParameterKnob[] parameterKnobs = new UIParameterKnob[12]; + for (int ki = 0; ki < parameterKnobs.length; ++ki) { + parameterKnobs[ki] = new UIParameterKnob(5 + 34*(ki % 4), yp + (ki/4) * 48); + parameterKnobs[ki].addToContainer(this); + } + + LXDeck.Listener lxListener = new LXDeck.AbstractListener() { + public void patternWillChange(LXDeck deck, LXPattern pattern, LXPattern nextPattern) { + patternList.redraw(); + } + public void patternDidChange(LXDeck deck, LXPattern pattern) { + patternList.redraw(); + int pi = 0; + for (LXParameter parameter : pattern.getParameters()) { + if (pi >= parameterKnobs.length) { + break; + } + parameterKnobs[pi++].setParameter(parameter); + } + while (pi < parameterKnobs.length) { + parameterKnobs[pi++].setParameter(null); + } + } + }; + + deck.addListener(lxListener); + lxListener.patternDidChange(deck, deck.getActivePattern()); + + } + + class PatternScrollItem extends AbstractScrollItem { + + private LXPattern pattern; + private String label; + + PatternScrollItem(LXPattern pattern) { + this.pattern = pattern; + label = className(pattern, "Pattern"); + } + + public String getLabel() { + return label; + } + + public boolean isSelected() { + return deck.getActivePattern() == pattern; + } + + public boolean isPending() { + return deck.getNextPattern() == pattern; + } + + public void onMousePressed() { + deck.goPattern(pattern); + } + } +} + +class UIBlendMode extends UIWindow { + public UIBlendMode(float x, float y, float w, float h) { + super("BLEND MODE", x, y, w, h); + List items = new ArrayList(); + for (LXTransition t : glucose.getTransitions()) { + items.add(new TransitionScrollItem(t)); + } + final UIScrollList tList; + (tList = new UIScrollList(1, titleHeight, w-2, 60)).setItems(items).addToContainer(this); + + lx.engine.getDeck(GLucose.RIGHT_DECK).addListener(new LXDeck.AbstractListener() { + public void faderTransitionDidChange(LXDeck deck, LXTransition transition) { + tList.redraw(); + } + }); + } + + class TransitionScrollItem extends AbstractScrollItem { + private final LXTransition transition; + private String label; + + TransitionScrollItem(LXTransition transition) { + this.transition = transition; + label = className(transition, "Transition"); + } + + public String getLabel() { + return label; + } + + public boolean isSelected() { + return transition == glucose.getSelectedTransition(); + } + + public boolean isPending() { + return false; + } + + public void onMousePressed() { + glucose.setSelectedTransition(transition); + } + } + +} + +class UICrossfader extends UIWindow { + + private final UIToggleSet displayMode; + + public UICrossfader(float x, float y, float w, float h) { + super("CROSSFADER", x, y, w, h); + + new UIParameterSlider(4, titleHeight, w-9, 32).setParameter(lx.engine.getDeck(GLucose.RIGHT_DECK).getFader()).addToContainer(this); + (displayMode = new UIToggleSet(4, titleHeight + 36, w-9, 20)).setOptions(new String[] { "A", "COMP", "B" }).setValue("COMP").addToContainer(this); + } + + public UICrossfader setDisplayMode(String value) { + displayMode.setValue(value); + return this; + } + + public String getDisplayMode() { + return displayMode.getValue(); + } +} + +class UIEffects extends UIWindow { + UIEffects(float x, float y, float w, float h) { + super("FX", x, y, w, h); + + int yp = titleHeight; + List items = new ArrayList(); + for (LXEffect fx : glucose.lx.getEffects()) { + items.add(new FXScrollItem(fx)); + } + final UIScrollList effectsList = new UIScrollList(1, yp, w-2, 60).setItems(items); + effectsList.addToContainer(this); + yp += effectsList.h + 10; + + final UIParameterKnob[] parameterKnobs = new UIParameterKnob[4]; + for (int ki = 0; ki < parameterKnobs.length; ++ki) { + parameterKnobs[ki] = new UIParameterKnob(5 + 34*(ki % 4), yp + (ki/4) * 48); + parameterKnobs[ki].addToContainer(this); + } + + GLucose.EffectListener fxListener = new GLucose.EffectListener() { + public void effectSelected(LXEffect effect) { + int i = 0; + for (LXParameter p : effect.getParameters()) { + if (i >= parameterKnobs.length) { + break; + } + parameterKnobs[i++].setParameter(p); + } + while (i < parameterKnobs.length) { + parameterKnobs[i++].setParameter(null); + } + } + }; + + glucose.addEffectListener(fxListener); + fxListener.effectSelected(glucose.getSelectedEffect()); + + } + + class FXScrollItem extends AbstractScrollItem { + + private LXEffect effect; + private String label; + + FXScrollItem(LXEffect effect) { + this.effect = effect; + label = className(effect, "Effect"); + } + + public String getLabel() { + return label; + } + + public boolean isSelected() { + return !effect.isEnabled() && (glucose.getSelectedEffect() == effect); + } + + public boolean isPending() { + return effect.isEnabled(); + } + + public void onMousePressed() { + if (glucose.getSelectedEffect() == effect) { + if (effect.isMomentary()) { + effect.enable(); + } else { + effect.toggle(); + } + } else { + glucose.setSelectedEffect(effect); + } + } + + public void onMouseReleased() { + if (effect.isMomentary()) { + effect.disable(); + } + } + + } + +} + +class UIOutput extends UIWindow { + public UIOutput(float x, float y, float w, float h) { + super("OUTPUT", x, y, w, h); + float yp = titleHeight; + + final UIScrollList outputs = new UIScrollList(1, titleHeight, w-2, 80); + + List items = new ArrayList(); + for (final PandaDriver panda : pandaBoards) { + items.add(new PandaScrollItem(panda)); + panda.setListener(new PandaDriver.Listener() { + public void onToggle(boolean active) { + outputs.redraw(); + } + }); + } + outputs.setItems(items).addToContainer(this); + } + + class PandaScrollItem extends AbstractScrollItem { + final PandaDriver panda; + PandaScrollItem(PandaDriver panda) { + this.panda = panda; + } + + public String getLabel() { + return panda.ip; + } + + public boolean isSelected() { + return panda.isEnabled(); + } + + public void onMousePressed() { + panda.toggle(); + } + } +} + +class UITempo extends UIWindow { + + private final UIButton tempoButton; + + UITempo(float x, float y, float w, float h) { + super("TEMPO", x, y, w, h); + tempoButton = new UIButton(4, titleHeight, w-10, 20) { + protected void onToggle(boolean active) { + if (active) { + lx.tempo.tap(); + } + } + }.setMomentary(true); + tempoButton.addToContainer(this); + } + + public void draw() { + tempoButton.setLabel("" + ((int)(lx.tempo.bpm() * 10)) / 10.); + super.draw(); + + // Overlay tempo thing with openGL, redraw faster than button UI + fill(color(0, 0, 24 - 8*lx.tempo.rampf())); + noStroke(); + rect(x + 8, y + titleHeight + 5, 12, 12); + } +} + +class UIMapping extends UIWindow { + + private static final String MAP_MODE_ALL = "ALL"; + private static final String MAP_MODE_CHANNEL = "CHNL"; + private static final String MAP_MODE_CUBE = "CUBE"; + + private static final String CUBE_MODE_ALL = "ALL"; + private static final String CUBE_MODE_STRIP = "SNGL"; + private static final String CUBE_MODE_PATTERN = "PTRN"; + + private final MappingTool mappingTool; + + private final UIIntegerBox channelBox; + private final UIIntegerBox cubeBox; + private final UIIntegerBox stripBox; + + UIMapping(MappingTool tool, float x, float y, float w, float h) { + super("MAPPING", x, y, w, h); + mappingTool = tool; + + int yp = titleHeight; + new UIToggleSet(4, yp, w-10, 20) { + protected void onToggle(String value) { + if (value == MAP_MODE_ALL) mappingTool.mappingMode = mappingTool.MAPPING_MODE_ALL; + else if (value == MAP_MODE_CHANNEL) mappingTool.mappingMode = mappingTool.MAPPING_MODE_CHANNEL; + else if (value == MAP_MODE_CUBE) mappingTool.mappingMode = mappingTool.MAPPING_MODE_SINGLE_CUBE; + } + }.setOptions(new String[] { MAP_MODE_ALL, MAP_MODE_CHANNEL, MAP_MODE_CUBE }).addToContainer(this); + yp += 24; + new UILabel(4, yp+8, w-10, 20).setLabel("CHANNEL ID").addToContainer(this); + yp += 24; + (channelBox = new UIIntegerBox(4, yp, w-10, 20) { + protected void onValueChange(int value) { + mappingTool.setChannel(value-1); + } + }).setRange(1, mappingTool.numChannels()).addToContainer(this); + yp += 24; + + new UILabel(4, yp+8, w-10, 20).setLabel("CUBE ID").addToContainer(this); + yp += 24; + (cubeBox = new UIIntegerBox(4, yp, w-10, 20) { + protected void onValueChange(int value) { + mappingTool.setCube(value-1); + } + }).setRange(1, glucose.model.cubes.size()).addToContainer(this); + yp += 24; + + yp += 10; + + new UIScrollList(1, yp, w-2, 60).setItems(Arrays.asList(new ScrollItem[] { + new ColorScrollItem(ColorScrollItem.COLOR_RED), + new ColorScrollItem(ColorScrollItem.COLOR_GREEN), + new ColorScrollItem(ColorScrollItem.COLOR_BLUE), + })).addToContainer(this); + yp += 64; + + new UILabel(4, yp+8, w-10, 20).setLabel("STRIP MODE").addToContainer(this); + yp += 24; + + new UIToggleSet(4, yp, w-10, 20) { + protected void onToggle(String value) { + if (value == CUBE_MODE_ALL) mappingTool.cubeMode = mappingTool.CUBE_MODE_ALL; + else if (value == CUBE_MODE_STRIP) mappingTool.cubeMode = mappingTool.CUBE_MODE_SINGLE_STRIP; + else if (value == CUBE_MODE_PATTERN) mappingTool.cubeMode = mappingTool.CUBE_MODE_STRIP_PATTERN; + } + }.setOptions(new String[] { CUBE_MODE_ALL, CUBE_MODE_STRIP, CUBE_MODE_PATTERN }).addToContainer(this); + + yp += 24; + new UILabel(4, yp+8, w-10, 20).setLabel("STRIP ID").addToContainer(this); + + yp += 24; + (stripBox = new UIIntegerBox(4, yp, w-10, 20) { + protected void onValueChange(int value) { + mappingTool.setStrip(value-1); + } + }).setRange(1, Cube.STRIPS_PER_CUBE).addToContainer(this); + + } + + public void setChannelID(int value) { + channelBox.setValue(value); + } + + public void setCubeID(int value) { + cubeBox.setValue(value); + } + + public void setStripID(int value) { + stripBox.setValue(value); + } + + class ColorScrollItem extends AbstractScrollItem { + + public static final int COLOR_RED = 1; + public static final int COLOR_GREEN = 2; + public static final int COLOR_BLUE = 3; + + private final int colorChannel; + + ColorScrollItem(int colorChannel) { + this.colorChannel = colorChannel; + } + + public String getLabel() { + switch (colorChannel) { + case COLOR_RED: return "Red"; + case COLOR_GREEN: return "Green"; + case COLOR_BLUE: return "Blue"; + } + return ""; + } + + public boolean isSelected() { + switch (colorChannel) { + case COLOR_RED: return mappingTool.channelModeRed; + case COLOR_GREEN: return mappingTool.channelModeGreen; + case COLOR_BLUE: return mappingTool.channelModeBlue; + } + return false; + } + + public void onMousePressed() { + switch (colorChannel) { + case COLOR_RED: mappingTool.channelModeRed = !mappingTool.channelModeRed; break; + case COLOR_GREEN: mappingTool.channelModeGreen = !mappingTool.channelModeGreen; break; + case COLOR_BLUE: mappingTool.channelModeBlue = !mappingTool.channelModeBlue; break; + } + } + } +} + +class UIDebugText extends UIContext { + + private String line1 = ""; + private String line2 = ""; + + UIDebugText(float x, float y, float w, float h) { + super(x, y, w, h); + } + + public UIDebugText setText(String line1) { + return setText(line1, ""); + } + + public UIDebugText setText(String line1, String line2) { + if (!line1.equals(this.line1) || !line2.equals(this.line2)) { + this.line1 = line1; + this.line2 = line2; + setVisible(line1.length() + line2.length() > 0); + redraw(); + } + return this; + } + + protected void onDraw(PGraphics pg) { + super.onDraw(pg); + if (line1.length() + line2.length() > 0) { + pg.noStroke(); + pg.fill(#444444); + pg.rect(0, 0, w, h); + pg.textFont(defaultItemFont); + pg.textSize(10); + pg.textAlign(LEFT, TOP); + pg.fill(#cccccc); + pg.text(line1, 4, 4); + pg.text(line2, 4, 24); + } + } +} + +class UISpeed extends UIWindow { + + final BasicParameter speed; + + UISpeed(float x, float y, float w, float h) { + super("SPEED", x, y, w, h); + speed = new BasicParameter("SPEED", 0.5); + new UIParameterSlider(4, titleHeight, w-10, 20) + .setParameter(speed.addListener(new LXParameterListener() { + public void onParameterChanged(LXParameter parameter) { + lx.setSpeed(parameter.getValuef() * 2); + } + })).addToContainer(this); + } +} + +class UIMidi extends UIWindow { + + private final UIToggleSet deckMode; + private final UIButton logMode; + + UIMidi(final MidiEngine midiEngine, float x, float y, float w, float h) { + super("MIDI", x, y, w, h); + + // Processing compiler doesn't seem to get that list of class objects also conform to interface + List scrollItems = new ArrayList(); + for (SCMidiInput mc : midiEngine.getControllers()) { + scrollItems.add(mc); + } + final UIScrollList scrollList; + (scrollList = new UIScrollList(1, titleHeight, w-2, 100)).setItems(scrollItems).addToContainer(this); + (deckMode = new UIToggleSet(4, 130, 90, 20) { + protected void onToggle(String value) { + midiEngine.setFocusedDeck(value == "A" ? 0 : 1); + } + }).setOptions(new String[] { "A", "B" }).addToContainer(this); + (logMode = new UIButton(98, 130, w-103, 20)).setLabel("LOG").addToContainer(this); + + SCMidiInputListener listener = new SCMidiInputListener() { + public void onEnabled(SCMidiInput controller, boolean enabled) { + scrollList.redraw(); + } + }; + for (SCMidiInput mc : midiEngine.getControllers()) { + mc.addListener(listener); + } + + midiEngine.addListener(new MidiEngineListener() { + public void onFocusedDeck(int deckIndex) { + deckMode.setValue(deckIndex == 0 ? "A" : "B"); + } + }); + + } + + public boolean logMidi() { + return logMode.isActive(); + } + + public LXDeck getFocusedDeck() { + return lx.engine.getDeck(deckMode.getValue() == "A" ? GLucose.LEFT_DECK : GLucose.RIGHT_DECK); + } +} + +String className(Object p, String suffix) { + String s = p.getClass().getName(); + int li; + if ((li = s.lastIndexOf(".")) > 0) { + s = s.substring(li + 1); + } + if (s.indexOf("SugarCubes$") == 0) { + s = s.substring("SugarCubes$".length()); + } + if ((suffix != null) && ((li = s.indexOf(suffix)) != -1)) { + s = s.substring(0, li); + } + return s; +}