/* * JSampler - a java front-end for LinuxSampler * * Copyright (C) 2005-2010 Grigor Iliev * * This file is part of JSampler. * * JSampler is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 * as published by the Free Software Foundation. * * JSampler is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with JSampler; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA */ package org.jsampler.view.fantasia; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Vector; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import org.jsampler.CC; import org.jsampler.event.SamplerChannelListEvent; import org.jsampler.event.SamplerChannelListListener; import org.jsampler.view.fantasia.basic.FantasiaPainter; import org.jsampler.view.fantasia.basic.PixmapButton; import org.jsampler.view.fantasia.basic.PixmapPane; import org.pushingpixels.substance.internal.utils.SubstanceImageCreator; import org.linuxsampler.lscp.SamplerChannel; import static org.jsampler.view.fantasia.FantasiaI18n.i18n; import static org.jsampler.view.fantasia.FantasiaPrefs.*; import static org.jsampler.view.fantasia.FantasiaUtils.*; /** * * @author Grigor Iliev */ public class SmallChannelView extends JPanel implements ChannelView { private final Channel channel; private ChannelOptionsView channelOptionsView = null; private final ChannelScreen screen; private final Channel.PowerButton btnPower; private final MuteButton btnMute = new MuteButton(); private final SoloButton btnSolo = new SoloButton(); private final Channel.OptionsButton btnOptions; private final Vector components = new Vector(); /** Creates a new instance of SmallChannelView */ public SmallChannelView(Channel channel) { components.add(this); this.channel = channel; screen = new ChannelScreen(channel); btnPower = new Channel.PowerButton(channel); components.add(btnPower); btnOptions = new Channel.OptionsButton(channel); components.add(btnOptions); setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); setBorder(BorderFactory.createEmptyBorder(1, 3, 0, 11)); add(btnPower); add(Box.createRigidArea(new Dimension(4, 0))); add(createVSeparator()); add(Box.createRigidArea(new Dimension(3, 0))); add(screen); add(Box.createRigidArea(new Dimension(2, 0))); add(createVSeparator()); add(new FxSendsButton()); add(createVSeparator()); add(Box.createRigidArea(new Dimension(1, 0))); components.add(btnMute); components.add(btnSolo); add(btnMute); add(btnSolo); add(Box.createRigidArea(new Dimension(1, 0))); add(createVSeparator()); add(Box.createRigidArea(new Dimension(8, 0))); add(btnOptions); setPreferredSize(new Dimension(420, 22)); setMinimumSize(getPreferredSize()); setMaximumSize(getPreferredSize()); installView(); } @Override protected void paintComponent(Graphics g) { if(isOpaque()) super.paintComponent(g); double h = getSize().getHeight(); double w = getSize().getWidth(); Color c1 = channel.isSelected() ? new Color(0x555555) : new Color(0x888888); Color c2 = channel.isSelected() ? new Color(0x606060) : new Color(0x707070); Graphics2D g2 = (Graphics2D)g; FantasiaPainter.paintGradient(g2, 0, 0, w - 1, h - 1, c1, c2); FantasiaPainter.paintOuterBorder(g2, 0, 0, w - 1, h - 1, false, 0.27f, 0.11f, 0.64f, 0.20f); } ////////////////////////////////////////////// // Implementation of the ChannelView interface ////////////////////////////////////////////// @Override public Type getType() { return Type.SMALL; } @Override public JComponent getComponent() { return this; } @Override public void installView() { String vmud = VOL_MEASUREMENT_UNIT_DECIBEL; preferences().addPropertyChangeListener(vmud, new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent e) { boolean b; b = preferences().getBoolProperty(VOL_MEASUREMENT_UNIT_DECIBEL); screen.updateVolumeInfo(); } }); addEnhancedMouseListener(channel.getContextMenu()); CC.getSamplerModel().addSamplerChannelListListener(getHandler()); addEnhancedMouseListener(getHandler()); } @Override public void uninstallView() { //removeEnhancedMouseListener(channel.getContextMenu()); CC.getSamplerModel().removeSamplerChannelListListener(getHandler()); screen.onDestroy(); btnOptions.onDestroy(); uninstallChannelOptionsView(); removeEnhancedMouseListener(getHandler()); } @Override public void installChannelOptionsView() { if(channelOptionsView != null) return; channelOptionsView = new NormalChannelOptionsView(channel); channelOptionsView.installView(); } @Override public void uninstallChannelOptionsView() { if(channelOptionsView == null) return; channelOptionsView.uninstallView(); channelOptionsView = null; } @Override public ChannelOptionsView getChannelOptionsView() { return channelOptionsView; } @Override public void updateChannelInfo() { SamplerChannel sc = channel.getChannelInfo(); screen.updateScreenInfo(sc); screen.updateVolumeInfo(); updateMuteIcon(sc); if(sc.isSoloChannel()) btnSolo.setIcon(Res.gfxSoloSmallOn); else btnSolo.setIcon(Res.gfxSoloSmallOff); boolean b = sc.getEngine() != null; btnSolo.setEnabled(b); btnMute.setEnabled(b); if(getChannelOptionsView() != null) getChannelOptionsView().updateChannelInfo(); } @Override public void updateStreamCount(int count) { screen.updateStreamCount(count); } @Override public void updateVoiceCount(int count) { screen.updateVoiceCount(count); } @Override public void expandChannel() { if(btnOptions.isSelected()) return; btnOptions.doClick(); } @Override public boolean isOptionsButtonSelected() { return btnOptions.isSelected(); } @Override public void setOptionsButtonSelected(boolean b) { btnOptions.setSelected(b); } @Override public void addEnhancedMouseListener(MouseListener l) { removeEnhancedMouseListener(l); for(JComponent c : components) c.addMouseListener(l); screen.addEnhancedMouseListener(l); } @Override public void removeEnhancedMouseListener(MouseListener l) { for(JComponent c : components) c.removeMouseListener(l); screen.removeEnhancedMouseListener(l); } ////////////////////////////////////////////// /** * Updates the mute button with the proper icon regarding to information obtained * from channel. * @param channel A SamplerChannel instance containing the new settings * for this channel. */ private void updateMuteIcon(SamplerChannel channel) { if(channel.isMutedBySolo()) btnMute.setIcon(Res.gfxMutedBySoloSmall); else if(channel.isMuted()) btnMute.setIcon(Res.gfxMuteSmallOn); else btnMute.setIcon(Res.gfxMuteSmallOff); } protected JPanel createVSeparator() { PixmapPane p = new PixmapPane(Res.gfxVLine); p.setOpaque(false); p.setPreferredSize(new Dimension(2, 22)); p.setMinimumSize(p.getPreferredSize()); p.setMaximumSize(p.getPreferredSize()); return p; } private final EventHandler eventHandler = new EventHandler(); private EventHandler getHandler() { return eventHandler; } private class EventHandler extends MouseAdapter implements SamplerChannelListListener { @Override public void channelAdded(SamplerChannelListEvent e) { if(CC.getSamplerModel().getChannelListIsAdjusting()) return; screen.channelInfoPane.updateChannelIndex(); } @Override public void channelRemoved(SamplerChannelListEvent e) { //if(CC.getSamplerModel().getChannelListIsAdjusting()) return; //TODO: screen.channelInfoPane.updateChannelIndex(); } @Override public void mousePressed(MouseEvent e) { // TAG: channel selection system if(e.getButton() == MouseEvent.BUTTON3 && channel.isSelected()) return; CC.getMainFrame().getSelectedChannelsPane().processChannelSelection ( channel, e.isControlDown(), e.isShiftDown() ); /////// } } private class MuteButton extends PixmapButton implements ActionListener { MuteButton() { super(Res.gfxMuteSmallOff); setDisabledIcon ( SubstanceImageCreator.makeTransparent(this, Res.gfxMuteSmallOff, 0.4) ); addActionListener(this); } @Override public void actionPerformed(ActionEvent e) { SamplerChannel sc = channel.getChannelInfo(); boolean b = true; /* * Changing the mute button icon now instead of * leaving the work to the notification mechanism of the LinuxSampler. */ if(sc.isMuted() && !sc.isMutedBySolo()) { b = false; boolean hasSolo = CC.getSamplerModel().hasSoloChannel(); if(sc.isSoloChannel() || !hasSolo) setIcon(Res.gfxMuteSmallOff); else setIcon(Res.gfxMutedBySoloSmall); } else setIcon(Res.gfxMuteSmallOn); channel.getModel().setBackendMute(b); } //public boolean //contains(int x, int y) { return (x > 5 && x < 23) && (y > 5 && y < 16); } } private class SoloButton extends PixmapButton implements ActionListener { SoloButton() { super(Res.gfxSoloSmallOff); //setDisabledIcon(Res.gfxMuteSoloDisabled); setDisabledIcon ( SubstanceImageCreator.makeTransparent(this, Res.gfxSoloSmallOff, 0.4) ); addActionListener(this); } @Override public void actionPerformed(ActionEvent e) { SamplerChannel sc = channel.getChannelInfo(); boolean b = !sc.isSoloChannel(); /* * Changing the solo button icon (and related) now instead of * leaving the work to the notification mechanism of the LinuxSampler. */ if(b) { setIcon(Res.gfxSoloSmallOn); if(sc.isMutedBySolo()) btnMute.setIcon(Res.gfxMuteSmallOff); } else { setIcon(Res.gfxSoloSmallOff); if(!sc.isMuted() && CC.getSamplerModel().getSoloChannelCount() > 1) btnMute.setIcon(Res.gfxMutedBySoloSmall); } channel.getModel().setBackendSolo(b); } //public boolean //contains(int x, int y) { return (x > 5 && x < 23) && (y > 5 && y < 16); } } static class ChannelScreen extends PixmapPane { private final Channel channel; private final ChannelInfoPane channelInfoPane; private final Channel.StreamVoiceCountPane streamVoiceCountPane; private final Channel.VolumePane volumePane; private JButton btnInstr = createScreenButton(i18n.getButtonLabel("ChannelScreen.btnInstr")); private static Insets pixmapInsets = new Insets(5, 5, 4, 5); private final Vector components = new Vector(); private final PropertyChangeListener chnNumberingListener; private final PropertyChangeListener showMidiInfoListener; private final PropertyChangeListener showStreamVoiceCountListener; private boolean bShowNumbering; private boolean bShowMidiInfo; ChannelScreen(final Channel channel) { super(Res.gfxTextField); components.add(this); this.channel = channel; streamVoiceCountPane = new Channel.StreamVoiceCountPane(channel); components.add(streamVoiceCountPane); channelInfoPane = new ChannelInfoPane(channel); volumePane = new Channel.VolumePane(channel); components.add(volumePane); setPixmapInsets(pixmapInsets); setBorder(BorderFactory.createEmptyBorder(4, 3, 3, 4)); setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); JPanel p = new JPanel(); components.add(p); p.setOpaque(false); p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); p.add(channelInfoPane); btnInstr.setRolloverEnabled(false); btnInstr.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); btnInstr.setHorizontalAlignment(btnInstr.LEFT); int h = btnInstr.getPreferredSize().height; btnInstr.setPreferredSize(new Dimension(100, h)); btnInstr.setMinimumSize(btnInstr.getPreferredSize()); btnInstr.setMaximumSize(new Dimension(Short.MAX_VALUE, h)); components.add(btnInstr); p.add(btnInstr); p.add(streamVoiceCountPane); h = p.getPreferredSize().height; p.setPreferredSize(new Dimension(201, h)); p.setMinimumSize(p.getPreferredSize()); p.setMaximumSize(p.getPreferredSize()); add(p); add(Box.createRigidArea(new Dimension(3, 0))); add(volumePane); setPreferredSize(new Dimension(270, getPreferredSize().height)); setMinimumSize(getPreferredSize()); setMaximumSize(getPreferredSize()); btnInstr.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { channel.loadInstrument(); } }); final String s = "channel.smallView.showChannelNumbering"; chnNumberingListener = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent e) { bShowNumbering = preferences().getBoolProperty(s); channelInfoPane.setShowNumbering(bShowNumbering); } }; preferences().addPropertyChangeListener(s, chnNumberingListener); bShowNumbering = preferences().getBoolProperty(s); channelInfoPane.setShowNumbering(bShowNumbering); final String s2 = "channel.smallView.showMidiInfo"; showMidiInfoListener = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent e) { bShowMidiInfo = preferences().getBoolProperty(s2); channelInfoPane.setShowMidiInfo(bShowMidiInfo); } }; preferences().addPropertyChangeListener(s2, showMidiInfoListener); bShowMidiInfo = preferences().getBoolProperty(s2); channelInfoPane.setShowMidiInfo(bShowMidiInfo); final String s3 = "channel.smallView.showStreamVoiceCount"; showStreamVoiceCountListener = new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent e) { boolean b = preferences().getBoolProperty(s3); streamVoiceCountPane.setVisible(b); } }; preferences().addPropertyChangeListener(s3, showStreamVoiceCountListener); boolean b = preferences().getBoolProperty(s3); streamVoiceCountPane.setVisible(b); } public void addEnhancedMouseListener(MouseListener l) { removeEnhancedMouseListener(l); for(JComponent c : components) c.addMouseListener(l); } public void removeEnhancedMouseListener(MouseListener l) { for(JComponent c : components) c.removeMouseListener(l); } protected void updateVolumeInfo() { float f = channel.getChannelInfo().getVolume() * 100.0f; volumePane.updateVolumeInfo((int)f); } /** * Updates the number of active disk streams. * @param count The new number of active disk streams. */ protected void updateStreamCount(int count) { streamVoiceCountPane.updateStreamCount(count); } /** * Updates the number of active voices. * @param count The new number of active voices. */ protected void updateVoiceCount(int count) { streamVoiceCountPane.updateVoiceCount(count); } protected void updateScreenInfo(SamplerChannel sc) { String s = btnInstr.getToolTipText(); int status = sc.getInstrumentStatus(); if(status >= 0 && status < 100) { btnInstr.setText(i18n.getLabel("ChannelScreen.loadingInstrument", status)); if(s != null) btnInstr.setToolTipText(null); } else if(status == -1) { btnInstr.setText(i18n.getButtonLabel("ChannelScreen.btnInstr")); if(s != null) btnInstr.setToolTipText(null); } else if(status < -1) { btnInstr.setText(i18n.getLabel("ChannelScreen.errorLoadingInstrument")); if(s != null) btnInstr.setToolTipText(null); } else { if(sc.getInstrumentName() != null) btnInstr.setText(sc.getInstrumentName()); else btnInstr.setText(i18n.getButtonLabel("ChannelScreen.btnInstr")); btnInstr.setToolTipText(sc.getInstrumentName()); } channelInfoPane.updateChannelInfo(); } public void onDestroy() { String s = "channel.smallView.showChannelNumbering"; preferences().removePropertyChangeListener(s, chnNumberingListener); s = "channel.smallView.showMidiInfo"; preferences().removePropertyChangeListener(s, showMidiInfoListener); s = "channel.smallView.showStreamVoiceCount"; preferences().removePropertyChangeListener(s, showStreamVoiceCountListener); } } private static class ChannelInfoPane extends JPanel { private final Channel channel; private final JLabel lInfo; private int channelIndex = -1; private boolean showNumbering; private boolean showMidiInfo; ChannelInfoPane(Channel channel) { this.channel = channel; setOpaque(false); setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); lInfo = createScreenLabel(""); lInfo.setFont(Res.fontScreenMono); updateChannelIndex(); updateLabelLength(); add(lInfo); } private void updateLabelLength() { lInfo.setPreferredSize(null); int l = 0; if(getShowNumbering()) l += 4; if(channelIndex > 98) l++; if(getShowMidiInfo()) l += 6; StringBuffer sb = new StringBuffer(); for(int i = 0; i < l; i++) sb.append("0"); lInfo.setText(sb.toString()); lInfo.setPreferredSize(lInfo.getPreferredSize()); // Don't remove this! lInfo.setMinimumSize(lInfo.getPreferredSize()); lInfo.setMaximumSize(lInfo.getPreferredSize()); } protected void updateChannelInfo() { StringBuffer sb = new StringBuffer(); if(getShowNumbering()) { if(channelIndex < 9) sb.append(" "); sb.append(channelIndex + 1).append(": "); } if(getShowMidiInfo()) { SamplerChannel sc = channel.getChannelInfo(); if(sc.getMidiInputDevice() == -1) { sb.append("-/-"); } else { sb.append(sc.getMidiInputPort()).append("/"); if(sc.getMidiInputChannel() == -1) sb.append("All"); else sb.append(sc.getMidiInputChannel() + 1); } } lInfo.setText(sb.toString()); } protected void updateChannelIndex() { int i = CC.getMainFrame().getChannelNumber(channel.getModel()); boolean b = false; if(i > 98 && channelIndex <= 98) b = true; if(i < 99 && channelIndex >= 99) b = true; channelIndex = i; if(b) updateLabelLength(); if(!getShowNumbering()) return; updateChannelInfo(); } protected boolean getShowNumbering() { return showNumbering; } protected void setShowNumbering(boolean b) { if(b == showNumbering) return; showNumbering = b; updateLabelLength(); updateChannelIndex(); } protected boolean getShowMidiInfo() { return showMidiInfo; } protected void setShowMidiInfo(boolean b) { if(b == showMidiInfo) return; showMidiInfo = b; String s = b ? i18n.getLabel("SmallChannelView.ttMidiPortChannel") : null; lInfo.setToolTipText(s); updateLabelLength(); updateChannelInfo(); } } private class FxSendsButton extends PixmapButton implements ActionListener { FxSendsButton() { super(Res.gfxFx); setRolloverIcon(Res.gfxFxRO); addActionListener(this); } @Override public void actionPerformed(ActionEvent e) { channel.showFxSendsDialog(); } @Override public boolean contains(int x, int y) { return (x > 5 && x < 23) && (y > 5 && y < 16); } } }