--- jsampler/trunk/src/org/jsampler/view/fantasia/Channel.java 2006/08/07 18:34:40 912 +++ jsampler/trunk/src/org/jsampler/view/fantasia/Channel.java 2008/05/04 18:40:13 1734 @@ -1,7 +1,7 @@ /* * JSampler - a java front-end for LinuxSampler * - * Copyright (C) 2005, 2006 Grigor Kirilov Iliev + * Copyright (C) 2005-2008 Grigor Iliev * * This file is part of JSampler. * @@ -22,77 +22,92 @@ package org.jsampler.view.fantasia; -import java.awt.Cursor; +import java.awt.Container; import java.awt.Dimension; -import java.awt.Insets; +import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; -import java.util.logging.Level; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; -import javax.swing.BorderFactory; -import javax.swing.Box; +import java.text.NumberFormat; + +import javax.swing.AbstractAction; +import javax.swing.Action; import javax.swing.BoxLayout; +import javax.swing.ButtonGroup; import javax.swing.DefaultListCellRenderer; +import javax.swing.ImageIcon; import javax.swing.JButton; -import javax.swing.JComboBox; +import javax.swing.JComponent; import javax.swing.JLabel; +import javax.swing.JMenuItem; import javax.swing.JPanel; +import javax.swing.JPopupMenu; +import javax.swing.JRadioButtonMenuItem; +import javax.swing.JScrollPane; import javax.swing.JToggleButton; -import javax.swing.SwingConstants; - -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; +import javax.swing.JToolBar; -import net.sf.juife.Dial; -import net.sf.juife.JuifeUtils; +import net.sf.juife.InformationDialog; import net.sf.juife.TitleBar; -import org.jsampler.AudioDeviceModel; +import org.jdesktop.swingx.JXCollapsiblePane; + import org.jsampler.CC; -import org.jsampler.MidiDeviceModel; +import org.jsampler.HF; import org.jsampler.SamplerChannelModel; -import org.jsampler.SamplerModel; -import org.jsampler.event.AudioDeviceListEvent; -import org.jsampler.event.AudioDeviceListListener; -import org.jsampler.event.MidiDeviceListEvent; -import org.jsampler.event.MidiDeviceListListener; -import org.jsampler.event.SamplerChannelAdapter; import org.jsampler.event.SamplerChannelEvent; +import org.jsampler.event.SamplerChannelListEvent; +import org.jsampler.event.SamplerChannelListListener; import org.jsampler.event.SamplerChannelListener; -import org.jsampler.task.RemoveChannel; +import org.jsampler.view.JSChannel; + +import org.jsampler.view.std.JSChannelOutputRoutingDlg; +import org.jsampler.view.std.JSFxSendsPane; +import org.jsampler.view.std.JSInstrumentChooser; +import org.jsampler.view.std.JSVolumeEditorPopup; -import org.linuxsampler.lscp.AudioOutputDevice; -import org.linuxsampler.lscp.MidiInputDevice; -import org.linuxsampler.lscp.MidiPort; import org.linuxsampler.lscp.SamplerChannel; -import org.linuxsampler.lscp.SamplerEngine; import static org.jsampler.view.fantasia.FantasiaI18n.i18n; +import static org.jsampler.view.fantasia.FantasiaPrefs.*; +import static org.jsampler.view.fantasia.FantasiaUtils.*; +import static org.jsampler.view.std.JSVolumeEditorPopup.VolumeType; /** * * @author Grigor Iliev */ -public class Channel extends org.jsampler.view.JSChannel { - private final ChannelScreen screen = new ChannelScreen(this); - private final ChannelOptions optionsPane = new ChannelOptions(this); - - private final PowerButton btnPower = new PowerButton(); - private final MuteButton btnMute = new MuteButton(); - private final SoloButton btnSolo = new SoloButton(); - private final OptionsButton btnOptions = new OptionsButton(); +public class Channel extends JSChannel { + private final JXCollapsiblePane mainPane; + private ChannelOptionsView channelOptionsView; + private final ChannelOptionsPane optionsPane = new ChannelOptionsPane(); - private final EnhancedDial dialVolume = new EnhancedDial(); + private final ViewTracker viewTracker; + + private InformationDialog fxSendsDlg = null; + + private final ContextMenu contextMenu = new ContextMenu(); private boolean selected = false; + private AnimatedPorpetyListener animatedPorpetyListener = new AnimatedPorpetyListener(); + + class AnimatedPorpetyListener implements PropertyChangeListener { + public void + propertyChange(PropertyChangeEvent e) { + mainPane.setAnimated(preferences().getBoolProperty(ANIMATED)); + } + } + /** * Creates a new instance of Channel using the specified * non-null channel model. @@ -101,118 +116,97 @@ */ public Channel(SamplerChannelModel model) { + this(model, null); + } + + /** + * Creates a new instance of Channel using the specified + * non-null channel model. + * @param model The model to be used by this channel. + * @param listener A listener which is notified when the newly created + * channel is fully expanded on the screen. + * @throws IllegalArgumentException If the model is null. + */ + public + Channel(SamplerChannelModel model, final ActionListener listener) { super(model); setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); - JPanel p = new JPanel(); - p.setName("Channel"); - p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); - - //p.add(Box.createRigidArea(new Dimension(3, 0))); - - btnPower.setAlignmentY(JPanel.TOP_ALIGNMENT); - - TitleBar tb = new TitleBar(); - tb.setBorder(BorderFactory.createEmptyBorder(3, 3, 0, 4)); - tb.setLayout(new BoxLayout(tb, BoxLayout.X_AXIS)); - tb.setOpaque(false); - tb.setAlignmentY(JPanel.TOP_ALIGNMENT); - tb.add(btnPower); - tb.setPreferredSize(new Dimension(tb.getPreferredSize().width, 58)); - tb.setMinimumSize(tb.getPreferredSize()); - tb.setMaximumSize(tb.getPreferredSize()); - p.add(tb); - - //p.add(Box.createRigidArea(new Dimension(4, 0))); - - p.add(createVSeparator()); - - //p.add(Box.createRigidArea(new Dimension(3, 0))); - - JPanel p2 = new JPanel(); - p2.setOpaque(false); - p2.setLayout(new BoxLayout(p2, BoxLayout.Y_AXIS)); - p2.setAlignmentY(JPanel.TOP_ALIGNMENT); - p2.setBorder(BorderFactory.createEmptyBorder(5, 3, 0, 2)); - p2.add(screen); - p.add(p2); - - p.add(createVSeparator()); - - p2 = new JPanel(); - p2.setOpaque(false); - p2.setLayout(new BoxLayout(p2, BoxLayout.Y_AXIS)); - p2.setAlignmentY(JPanel.TOP_ALIGNMENT); - p2.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0)); - p2.add(new JLabel(Res.iconMuteTitle)); - p2.add(btnMute); - p2.add(new JLabel(Res.iconSoloTitle)); - p2.add(btnSolo); - - p.add(p2); - - p.add(createVSeparator()); - - p2 = new JPanel(); - p2.setOpaque(false); - p2.setLayout(new BoxLayout(p2, BoxLayout.Y_AXIS)); - p2.setAlignmentY(JPanel.TOP_ALIGNMENT); - p2.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0)); - JLabel l = new JLabel(Res.iconVolumeTitle); - l.setAlignmentX(JPanel.CENTER_ALIGNMENT); - l.setBorder(BorderFactory.createEmptyBorder(0, 0, 2, 0)); - p2.add(l); - dialVolume.setDialPixmap(Res.iconVolumeDial, 30, 330); - dialVolume.setAlignmentX(JPanel.CENTER_ALIGNMENT); - p2.add(dialVolume); - p.add(p2); - - p.add(createVSeparator()); - - p2 = new JPanel(); - p2.setOpaque(false); - p2.setLayout(new BoxLayout(p2, BoxLayout.Y_AXIS)); - p2.setAlignmentY(JPanel.TOP_ALIGNMENT); - p2.setBorder(BorderFactory.createEmptyBorder(27, 0, 0, 0)); - l = new JLabel(Res.iconOptionsTitle); - l.setAlignmentX(JPanel.CENTER_ALIGNMENT); - l.setBorder(BorderFactory.createEmptyBorder(0, 0, 2, 0)); - p2.add(l); - - p2.add(Box.createRigidArea(new Dimension(0, 3))); - - btnOptions.setAlignmentX(JPanel.CENTER_ALIGNMENT); - p2.add(btnOptions); - p.add(p2); - - - p.setPreferredSize(new Dimension(420, 60)); - p.setMinimumSize(p.getPreferredSize()); - p.setMaximumSize(p.getPreferredSize()); - //p.setBorder(BorderFactory.createEmptyBorder(1, 0, 1, 0)); - - p.setAlignmentX(JPanel.CENTER_ALIGNMENT); optionsPane.setAlignmentX(JPanel.CENTER_ALIGNMENT); - add(p); - add(optionsPane); - setOpaque(true); + mainPane = new JXCollapsiblePane(); + viewTracker = new ViewTracker(); + + mainPane.getContentPane().setLayout ( + new BoxLayout(mainPane.getContentPane(), BoxLayout.Y_AXIS) + ); + + int viewIdx = preferences().getIntProperty(DEFAULT_CHANNEL_VIEW); + if(viewIdx == 0) { + contextMenu.rbmiSmallView.doClick(0); + } else if(viewIdx == 1) { + contextMenu.rbmiNormalView.doClick(0); + } else { + contextMenu.rbmiNormalView.doClick(0); + } + + setOpaque(false); getModel().addSamplerChannelListener(getHandler()); updateChannelInfo(); + + add(mainPane); + + if(listener != null) { + final String s = JXCollapsiblePane.ANIMATION_STATE_KEY; + mainPane.addPropertyChangeListener(s, new PropertyChangeListener() { + public void + propertyChange(PropertyChangeEvent e) { + if(e.getNewValue() == "expanded") { + // TODO: this should be done regardles the listener != null? + mainPane.removePropertyChangeListener(s, this); + /////// + listener.actionPerformed(null); + ensureChannelIsVisible(); + } else if(e.getNewValue() == "expanding/collapsing") { + ensureChannelIsVisible(); + } + } + }); + } + + mainPane.setAnimated(false); + mainPane.setCollapsed(true); + mainPane.setAnimated(preferences().getBoolProperty(ANIMATED)); + mainPane.setCollapsed(false); + + preferences().addPropertyChangeListener(ANIMATED, animatedPorpetyListener); + + if(listener != null) { + javax.swing.SwingUtilities.invokeLater(new Runnable() { + public void + run() { listener.actionPerformed(null); } + }); + } + + CC.getSamplerModel().addSamplerChannelListListener(getHandler()); } - private JPanel - createVSeparator() { - JPanel p = new JPanel(); - p.setName("VSeparator"); - p.setOpaque(false); - p.setAlignmentY(JPanel.TOP_ALIGNMENT); - p.setPreferredSize(new Dimension(2, 60)); - p.setMinimumSize(p.getPreferredSize()); - p.setMaximumSize(p.getPreferredSize()); - return p; + private void + ensureChannelIsVisible() { + Container p = getParent(); + JScrollPane sp = null; + while(p != null) { + if(p instanceof JScrollPane) { + sp = (JScrollPane)p; + break; + } + p = p.getParent(); + } + if(sp == null) return; + int h = sp.getViewport().getView().getHeight(); + sp.getViewport().scrollRectToVisible(new Rectangle(0, h - 2, 1, 1)); } /** @@ -235,29 +229,15 @@ /** Shows the channel properties. */ public void - expandChannel() { if(!btnOptions.isSelected()) btnOptions.doClick(); } + expandChannel() { expandChannel(optionsPane.isAnimated()); } - - /** Invoked when the user changes the volume */ - private void - setVolume() { - screen.updateVolumeInfo(dialVolume.getValue()); - - if(dialVolume.getValueIsAdjusting()) return; - - int vol = (int)(getChannelInfo().getVolume() * 100); - - if(vol == dialVolume.getValue()) return; - - - /* - * If the model's volume is not equal to the dial knob - * value we assume that the change is due to user input. - * So we must update the volume at the backend too. - */ - float volume = dialVolume.getValue(); - volume /= 100; - getModel().setVolume(volume); + /** Shows the channel properties. */ + public void + expandChannel(boolean animated) { + boolean b = optionsPane.isAnimated(); + optionsPane.setAnimated(animated); + viewTracker.getCurrentView().expandChannel(); + optionsPane.setAnimated(b); } /** @@ -266,61 +246,67 @@ */ private void updateChannelInfo() { - SamplerChannel sc = getChannelInfo(); + viewTracker.getCurrentView().updateChannelInfo(); + viewTracker.getCurrentView().getChannelOptionsView().updateChannelInfo(); + } + + public void + loadInstrument() { + JSInstrumentChooser dlg = FantasiaUtils.createInstrumentChooser(CC.getMainFrame()); + dlg.setVisible(true); - screen.updateScreenInfo(sc); - updateMuteIcon(sc); + if(!dlg.isCancelled()) { + SamplerChannelModel m = getModel(); + m.loadBackendInstrument(dlg.getInstrumentFile(), dlg.getInstrumentIndex()); + } + } + + public void + fallbackToOriginalView() { + viewTracker.fallbackToOriginalView(); + } + + public boolean + isUsingOriginalView() { + return viewTracker.isUsingOriginalView(); + } + + protected void + onDestroy() { + CC.getSamplerModel().removeSamplerChannelListListener(getHandler()); + preferences().removePropertyChangeListener(ANIMATED, animatedPorpetyListener); - if(sc.isSoloChannel()) btnSolo.setIcon(Res.iconSoloOn); - else btnSolo.setIcon(Res.iconSoloOff); + viewTracker.onDestroy(); + } - dialVolume.setValue((int)(sc.getVolume() * 100)); + public void + remove() { + if(!mainPane.isAnimated()) { + CC.getSamplerModel().removeBackendChannel(getChannelId()); + return; + } - boolean b = sc.getEngine() != null; - dialVolume.setEnabled(b); - btnSolo.setEnabled(b); - btnMute.setEnabled(b); + String s = JXCollapsiblePane.ANIMATION_STATE_KEY; + mainPane.addPropertyChangeListener(s, getHandler()); + mainPane.setCollapsed(true); } - /** - * 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.iconMutedBySolo); - else if(channel.isMuted()) btnMute.setIcon(Res.iconMuteOn); - else btnMute.setIcon(Res.iconMuteOff); - } + public void + showOptionsPane(boolean show) { optionsPane.showOptionsPane(show); } - private class EnhancedDial extends Dial { - EnhancedDial() { - super(0, 100); - - setMouseHandlerMode(MouseHandlerMode.LEFT_TO_RIGHT_AND_DOWN_TO_UP); - - addMouseListener(new MouseAdapter() { - public void - mouseClicked(MouseEvent e) { - if(e.getButton() == e.BUTTON3) { - setValue(getMaximum() / 2); - return; - } - - if(e.getButton() != e.BUTTON1) return; - - if(e.getClickCount() < 2) return; - setValue(getValueByPoint(e.getPoint())); - } - }); - - addChangeListener(new ChangeListener() { - public void - stateChanged(ChangeEvent e) { setVolume(); } - }); + public void + showFxSendsDialog() { + if(fxSendsDlg != null && fxSendsDlg.isVisible()) { + fxSendsDlg.toFront(); + return; } + FxSendsPane p = new FxSendsPane(getModel()); + int id = getModel().getChannelId(); + fxSendsDlg = new InformationDialog(CC.getMainFrame(), p); + fxSendsDlg.setTitle(i18n.getLabel("FxSendsDlg.title", id)); + fxSendsDlg.setModal(false); + fxSendsDlg.showCloseButton(false); + fxSendsDlg.setVisible(true); } private final EventHandler eventHandler = new EventHandler(); @@ -328,7 +314,8 @@ private EventHandler getHandler() { return eventHandler; } - private class EventHandler implements SamplerChannelListener { + private class EventHandler implements SamplerChannelListener, + SamplerChannelListListener, PropertyChangeListener { /** * Invoked when changes are made to a sampler channel. * @param e A SamplerChannelEvent instance @@ -344,7 +331,7 @@ */ public void streamCountChanged(SamplerChannelEvent e) { - screen.updateStreamCount(getModel().getStreamCount()); + viewTracker.getCurrentView().updateStreamCount(getModel().getStreamCount()); } /** @@ -354,643 +341,648 @@ */ public void voiceCountChanged(SamplerChannelEvent e) { - screen.updateVoiceCount(getModel().getVoiceCount()); + viewTracker.getCurrentView().updateVoiceCount(getModel().getVoiceCount()); } - } - - - private class PowerButton extends PixmapToggleButton implements ActionListener { - PowerButton() { - super(Res.iconPowerOff, Res.iconPowerOn); - setSelected(true); - addActionListener(this); + /** + * Invoked when a new sampler channel is created. + * @param e A SamplerChannelListEvent + * instance providing the event information. + */ + public void + channelAdded(SamplerChannelListEvent e) { } + + /** + * Invoked when a sampler channel is removed. + * @param e A SamplerChannelListEvent + * instance providing the event information. + */ + public void + channelRemoved(SamplerChannelListEvent e) { + // Some cleanup when the channel is removed. + if(e.getChannelModel().getChannelId() == getChannelId()) { + onDestroy(); + } } public void - actionPerformed(ActionEvent e) { - CC.getTaskQueue().add(new RemoveChannel(getChannelID())); + propertyChange(PropertyChangeEvent e) { + if(e.getNewValue() == "collapsed") { + CC.getSamplerModel().removeBackendChannel(getChannelId()); + } } - - public boolean - contains(int x, int y) { return (x - 11)*(x - 11) + (y - 11)*(y - 11) < 71; } } - private class MuteButton extends PixmapButton implements ActionListener { - MuteButton() { - super(Res.iconMuteOff); - addActionListener(this); - } + private static boolean viewTrackerMousePressed = false; + + class ViewTracker extends MouseAdapter implements PropertyChangeListener { + private ChannelView originalView; + private ChannelView mouseOverView; + private ChannelView currentView; - public void - actionPerformed(ActionEvent e) { - SamplerChannel sc = 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.iconMuteOff); - else setIcon(Res.iconMutedBySolo); - } else setIcon(Res.iconMuteOn); + private boolean mouseOver = false; + + private final ActionListener guiListener; + + ViewTracker() { + guiListener = new ActionListener() { + public void + actionPerformed(ActionEvent e) { + if(viewTrackerMousePressed) return; + + if(mainPane.getMousePosition(true) != null) { + mouseEntered(null); + } else { + mouseExited(null); + } + } + }; + + updateMouseOverViewType(); - Channel.this.getModel().setMute(b); + String s = DIFFERENT_CHANNEL_VIEW_ON_MOUSE_OVER; + preferences().addPropertyChangeListener(s, this); + + s = CHANNEL_VIEW_ON_MOUSE_OVER; + preferences().addPropertyChangeListener(s, this); } 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.iconSoloOff); - addActionListener(this); + isUsingOriginalView() { + return currentView == originalView; } - public void - actionPerformed(ActionEvent e) { - SamplerChannel sc = getChannelInfo(); - boolean b = !sc.isSoloChannel(); + private void + installListeners() { + ((MainFrame)CC.getMainFrame()).getGuiTimer().addActionListener(guiListener); + } - /* - * Changing the solo button icon (and related) now instead of - * leaving the work to the notification mechanism of the LinuxSampler. - */ - if(b) { - setIcon(Res.iconSoloOn); - if(sc.isMutedBySolo()) btnMute.setIcon(Res.iconMuteOff); - } else { - setIcon(Res.iconSoloOff); - if(!sc.isMuted() && CC.getSamplerModel().getSoloChannelCount() > 1) - btnMute.setIcon(Res.iconMutedBySolo); - } + private void + uninstallListeners() { + ((MainFrame)CC.getMainFrame()).getGuiTimer().removeActionListener(guiListener); + } - Channel.this.getModel().setSolo(b); + private void + updateMouseOverViewType() { + if(mouseOverView != null) { + mouseOverView.removeEnhancedMouseListener(this); + } + + boolean b; + b = preferences().getBoolProperty(DIFFERENT_CHANNEL_VIEW_ON_MOUSE_OVER); + if(!b) { + mouseOverView = null; + uninstallListeners(); + return; + } + + Channel channel = Channel.this; + int i = preferences().getIntProperty(CHANNEL_VIEW_ON_MOUSE_OVER); + + switch(i) { + case 0: mouseOverView = new SmallChannelView(channel); break; + case 1: mouseOverView = new NormalChannelView(channel); break; + default:mouseOverView = null; + } + + if(mouseOverView != null) { + installListeners(); + mouseOverView.addEnhancedMouseListener(this); + } } - public boolean - contains(int x, int y) { return (x > 5 && x < 23) && (y > 5 && y < 16); } - } - - private class OptionsButton extends PixmapToggleButton implements ActionListener { - OptionsButton() { - super(Res.iconOptionsOff, Res.iconOptionsOn); - addActionListener(this); + public ChannelView + getCurrentView() { return currentView; } + + public void + setView(ChannelView view) { + setView(view, true); } public void - actionPerformed(ActionEvent e) { - showOptionsPane(isSelected()); + setView(ChannelView view, boolean manual) { + boolean selected = false; + if(currentView != null) selected = currentView.isOptionsButtonSelected(); - String s; - if(isSelected()) s = i18n.getButtonLabel("OptionsButton.ttHideOptions"); - else s = i18n.getButtonLabel("OptionsButton.ttShowOptions"); + if(manual) { + if(originalView != null) { + originalView.removeEnhancedMouseListener(this); + } + + if(originalView != currentView) destroyOriginalView(); + if(currentView != null && currentView.getType() == view.getType()) { + originalView = currentView; + originalView.addEnhancedMouseListener(this); + destroyView(view); + return; + } + + removeCurrentView(); + + originalView = view; + originalView.addEnhancedMouseListener(this); + currentView = view; + } else { + if(view.getType() == getCurrentView().getType()) { + destroyView(view); + return; + } + + removeCurrentView(); + currentView = view; + } - setToolTipText(s); + currentView.setOptionsButtonSelected(selected); + + updateView(); } private void - showOptionsPane(boolean show) { - optionsPane.setVisible(show); - MainFrame.repack(CC.getMainFrame()); + updateView() { + JComponent c = getCurrentView().getChannelOptionsView().getComponent(); + optionsPane.setContentPane(c); + + updateChannelInfo(); + + mainPane.add(getCurrentView().getComponent()); + mainPane.add(optionsPane); + mainPane.validate(); + mainPane.revalidate(); + mainPane.repaint(); } - public boolean - contains(int x, int y) { return y < 13; } - } -} - -class ChannelScreen extends JPanel { - private final Channel channel; - private JButton btnInstr = new ScreenButton(i18n.getButtonLabel("ChannelScreen.btnInstr")); - private JButton btnReset = new ScreenButton(i18n.getButtonLabel("ChannelScreen.btnReset")); - private JButton btnDuplicate = - new ScreenButton(i18n.getButtonLabel("ChannelScreen.btnDuplicate")); - - private final JLabel lVolume = new JLabel(); - private final JLabel lStreams = new JLabel("--"); - private final JLabel lVoices = new JLabel("--"); - - ChannelScreen(Channel channel) { - this.channel = channel; + public void + fallbackToOriginalView() { + if(currentView == originalView) return; + + boolean selected = false; + if(currentView != null) selected = currentView.isOptionsButtonSelected(); + + removeCurrentView(); + currentView = originalView; + currentView.setOptionsButtonSelected(selected); + + updateView(); + } - setName("ChannelScreen"); - setOpaque(true); + private void + removeCurrentView() { removeView(currentView); } - setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + private void + destroyCurrentView() { destroyView(currentView); } - btnInstr.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); - btnInstr.setAlignmentX(CENTER_ALIGNMENT); + private void + removeOriginalView() { removeView(originalView); } - add(btnInstr); + private void + destroyOriginalView() { destroyView(originalView); } - JPanel p = new JPanel(); - p.setOpaque(false); - p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); - p.setAlignmentX(CENTER_ALIGNMENT); - p.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); - //lVolume.setFont(lVolume.getFont().deriveFont(java.awt.Font.PLAIN)); + private void + removeView(ChannelView view) { + if(view == null) return; + + mainPane.remove(view.getComponent()); + mainPane.remove(optionsPane); + + destroyView(view); + } - p.add(btnDuplicate); + private void + destroyView(ChannelView view) { + if(view == null) return; + + view.uninstallView(); + view.getChannelOptionsView().uninstallView(); + + view = null; + } - p.add(Box.createRigidArea(new Dimension(6, 0))); + private void + mouseEntered() { + if(mouseOverView == null) return; + if(getCurrentView().getType() == mouseOverView.getType()) return; + + JSChannel[] channels = CC.getMainFrame().getChannelsPane(0).getChannels(); + for(JSChannel c : channels) { + if(c == Channel.this) continue; + + Channel chn = (Channel)c; + if(!(chn).isUsingOriginalView()) chn.fallbackToOriginalView(); + } + + setView(mouseOverView, false); + } - p.add(new JLabel("|")); + private void + mouseExited() { + if(mouseOverView == null) return; + if(getCurrentView().getType() == originalView.getType()) return; + + fallbackToOriginalView(); + } - p.add(Box.createRigidArea(new Dimension(6, 0))); + public void + mouseEntered(MouseEvent e) { + if(viewTrackerMousePressed) return; + + if(mouseOver) return; + mouseOver = true; + mouseEntered(); + } - p.add(btnReset); + public void + mouseExited(MouseEvent e) { + if(viewTrackerMousePressed) return; + + if(mainPane.getMousePosition(true) != null) return; + if(!mouseOver) return; + mouseOver = false; + mouseExited(); + } - p.add(Box.createGlue()); + public void + mousePressed(MouseEvent e) { + viewTrackerMousePressed = true; + } - p.add(lStreams); - p.add(new JLabel("/")); - p.add(lVoices); + public void + mouseReleased(MouseEvent e) { + viewTrackerMousePressed = false; + } - p.add(Box.createRigidArea(new Dimension(12, 0))); + public void + onDestroy() { + destroyCurrentView(); + destroyOriginalView(); + + uninstallListeners(); + + if(currentView != null) { + currentView.removeEnhancedMouseListener(this); + } + + if(mouseOverView != null) { + mouseOverView.removeEnhancedMouseListener(this); + } + + String s = DIFFERENT_CHANNEL_VIEW_ON_MOUSE_OVER; + preferences().removePropertyChangeListener(s, this); + + s = CHANNEL_VIEW_ON_MOUSE_OVER; + preferences().removePropertyChangeListener(s, this); + } - lVolume.setAlignmentX(RIGHT_ALIGNMENT); - p.add(lVolume); - p.setPreferredSize(new Dimension(250, p.getPreferredSize().height)); - p.setMinimumSize(p.getPreferredSize()); - p.setMaximumSize(p.getPreferredSize()); + public void + propertyChange(PropertyChangeEvent e) { + updateMouseOverViewType(); + } + } + + class EditInstrumentAction extends AbstractAction implements SamplerChannelListener { + EditInstrumentAction() { + super(i18n.getMenuLabel("channels.editInstrument")); + channelChanged(null); + getModel().addSamplerChannelListener(this); + } - add(p); + public void + actionPerformed(ActionEvent e) { + CC.getSamplerModel().editBackendInstrument(getChannelId()); + } + public void + channelChanged(SamplerChannelEvent e) { + boolean b = getChannelInfo().getInstrumentStatus() == 100; + setEnabled(b); + } - setPreferredSize(new Dimension(270, 48)); - setMinimumSize(getPreferredSize()); - setMaximumSize(getPreferredSize()); + public void + streamCountChanged(SamplerChannelEvent e) { } - installListeners(); + public void + voiceCountChanged(SamplerChannelEvent e) { } } - private void - installListeners() { - btnInstr.addActionListener(new ActionListener() { - public void - actionPerformed(ActionEvent e) { loadInstrument(); } - }); - - btnReset.addActionListener(new ActionListener() { - public void - actionPerformed(ActionEvent e) { channel.getModel().resetChannel(); } - }); - - btnDuplicate.addActionListener(new ActionListener() { - public void - actionPerformed(ActionEvent e) { channel.getModel().duplicateChannel(); } - }); - } - - private void - loadInstrument() { - InstrumentChooser dlg = new InstrumentChooser(CC.getMainFrame()); - dlg.setVisible(true); + class FxSendsAction extends AbstractAction { + FxSendsAction() { + super(i18n.getMenuLabel("channels.fxSends")); + } - if(!dlg.isCancelled()) { - SamplerChannelModel m = channel.getModel(); - m.loadInstrument(dlg.getFileName(), dlg.getInstrumentIndex()); + public void + actionPerformed(ActionEvent e) { + showFxSendsDialog(); } } - protected void - updateScreenInfo(SamplerChannel sc) { - int status = sc.getInstrumentStatus(); - if(status >= 0 && status < 100) { - btnInstr.setText(i18n.getLabel("ChannelScreen.loadingInstrument", status)); - } else if(status == -1) { - btnInstr.setText(i18n.getButtonLabel("ChannelScreen.btnInstr")); - } else if(status < -1) { - btnInstr.setText(i18n.getLabel("ChannelScreen.errorLoadingInstrument")); - } else { - if(sc.getInstrumentName() != null) btnInstr.setText(sc.getInstrumentName()); - else btnInstr.setText(i18n.getButtonLabel("ChannelScreen.btnInstr")); + class ChannelRoutingAction extends AbstractAction implements SamplerChannelListener { + ChannelRoutingAction() { + super(i18n.getMenuLabel("channels.channelRouting")); + channelChanged(null); + getModel().addSamplerChannelListener(this); } - + public void + actionPerformed(ActionEvent e) { + SamplerChannel c = getChannelInfo(); + new JSChannelOutputRoutingDlg(CC.getMainFrame(), c).setVisible(true); + } - } - - protected void - updateVolumeInfo(int volume) { - lVolume.setText(i18n.getLabel("ChannelScreen.volume", volume)); + public void + channelChanged(SamplerChannelEvent e) { + boolean b = getChannelInfo().getAudioOutputDevice() != -1; + setEnabled(b); + } + public void + streamCountChanged(SamplerChannelEvent e) { } + + public void + voiceCountChanged(SamplerChannelEvent e) { } } - /** - * Updates the number of active disk streams. - * @param count The new number of active disk streams. - */ - protected void - updateStreamCount(int count) { - Dimension d = lStreams.getPreferredSize(); - lStreams.setText(count == 0 ? "--" : String.valueOf(count)); - d = JuifeUtils.getUnionSize(d, lStreams.getPreferredSize()); - lStreams.setMinimumSize(d); - lStreams.setPreferredSize(d); - lStreams.setMaximumSize(d); - } - - /** - * Updates the number of active voices. - * @param count The new number of active voices. - */ - protected void - updateVoiceCount(int count) { - Dimension d = lVoices.getPreferredSize(); - lVoices.setText(count == 0 ? "--" : String.valueOf(count)); - d = JuifeUtils.getUnionSize(d, lVoices.getPreferredSize()); - lVoices.setMinimumSize(d); - lVoices.setPreferredSize(d); - lVoices.setMaximumSize(d); - } - - static class ScreenButton extends JButton { - ScreenButton(String s) { - super(s); - setContentAreaFilled(false); - setFocusPainted(false); - setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0)); - setMargin(new Insets(0, 0, 0, 0)); - setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + class SetSmallViewAction extends AbstractAction { + SetSmallViewAction() { + super(i18n.getMenuLabel("channels.smallView")); + } + + public void + actionPerformed(ActionEvent e) { + viewTracker.setView(new SmallChannelView(Channel.this)); } } -} - -class ChannelOptions extends JPanel { - private final Channel channel; - private final JComboBox cbMidiDevice = new JComboBox(); - private final JComboBox cbMidiPort = new JComboBox(); - private final JComboBox cbMidiChannel = new JComboBox(); - private final JComboBox cbEngine = new JComboBox(); - private final JComboBox cbAudioDevice = new JComboBox(); - - private boolean update = false; - - ChannelOptions(Channel channel) { - this.channel = channel; - - setName("ChannelOptions"); - setVisible(false); - setBorder(BorderFactory.createEmptyBorder(5, 4, 5, 4)); - setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); - - setPreferredSize(new Dimension(420, 44)); - setMinimumSize(getPreferredSize()); - setMaximumSize(getPreferredSize()); - - JPanel p = new JPanel(); - p.setOpaque(true); - p.setBorder(BorderFactory.createEmptyBorder(3, 4, 3, 4)); - p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); - JLabel l = new JLabel(Res.iconMidiInputTitle); - l.setAlignmentX(LEFT_ALIGNMENT); - p.add(l); - - JPanel p2 = new JPanel(); - p2.setBorder(BorderFactory.createEmptyBorder(3, 0, 0, 0)); - p2.setLayout(new BoxLayout(p2, BoxLayout.X_AXIS)); - - Object o = cbMidiDevice.getRenderer(); - if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.CENTER); - - cbMidiDevice.setPreferredSize(new Dimension(40, 18)); - cbMidiDevice.setMinimumSize(cbMidiDevice.getPreferredSize()); - cbMidiDevice.setMaximumSize(cbMidiDevice.getPreferredSize()); - p2.add(cbMidiDevice); - - p2.add(Box.createRigidArea(new Dimension(3, 0))); - - o = cbMidiPort.getRenderer(); - if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.CENTER); - - cbMidiPort.setPreferredSize(new Dimension(67, 18)); - cbMidiPort.setMinimumSize(cbMidiPort.getPreferredSize()); - cbMidiPort.setMaximumSize(cbMidiPort.getPreferredSize()); - p2.add(cbMidiPort); - - p2.add(Box.createRigidArea(new Dimension(3, 0))); - - o = cbMidiChannel.getRenderer(); - if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.CENTER); - - cbMidiChannel.addItem("All"); - for(int i = 1; i <= 16; i++) cbMidiChannel.addItem("Channel " + String.valueOf(i)); - cbMidiChannel.setPreferredSize(new Dimension(80, 18)); - cbMidiChannel.setMinimumSize(cbMidiChannel.getPreferredSize()); - cbMidiChannel.setMaximumSize(cbMidiChannel.getPreferredSize()); - - p2.add(cbMidiChannel); - p2.setAlignmentX(LEFT_ALIGNMENT); - p.add(p2); - - add(p); - - add(Box.createRigidArea(new Dimension(4, 0))); - - p = new JPanel(); - p.setOpaque(true); - p.setBorder(BorderFactory.createEmptyBorder(3, 4, 3, 4)); - p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); - l = new JLabel(Res.iconEngineTitle); - l.setAlignmentX(LEFT_ALIGNMENT); - l.setAlignmentX(LEFT_ALIGNMENT); - p.add(l); - - p.add(Box.createRigidArea(new Dimension(0, 3))); - - o = cbEngine.getRenderer(); - if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.CENTER); - - for(SamplerEngine e : CC.getSamplerModel().getEngines()) cbEngine.addItem(e); - cbEngine.setPreferredSize(new Dimension(125, 18)); - cbEngine.setMinimumSize(cbEngine.getPreferredSize()); - cbEngine.setMaximumSize(cbEngine.getPreferredSize()); - cbEngine.setAlignmentX(LEFT_ALIGNMENT); - p.add(cbEngine); - - add(p); - - add(Box.createRigidArea(new Dimension(4, 0))); - - p = new JPanel(); - p.setOpaque(true); - p.setBorder(BorderFactory.createEmptyBorder(3, 4, 3, 4)); - p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS)); - l = new JLabel(Res.iconAudioOutputTitle); - l.setAlignmentX(LEFT_ALIGNMENT); - l.setAlignmentX(LEFT_ALIGNMENT); - p.add(l); - - p.add(Box.createRigidArea(new Dimension(0, 3))); - - o = cbAudioDevice.getRenderer(); - if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.RIGHT); - - cbAudioDevice.setPreferredSize(new Dimension(61, 18)); - cbAudioDevice.setMinimumSize(cbAudioDevice.getPreferredSize()); - cbAudioDevice.setMaximumSize(cbAudioDevice.getPreferredSize()); - cbAudioDevice.setAlignmentX(LEFT_ALIGNMENT); - p.add(cbAudioDevice); - - add(p); - - cbMidiDevice.addActionListener(new ActionListener() { - public void - actionPerformed(ActionEvent e) { setMidiDevice(); } - }); - - cbMidiPort.addActionListener(new ActionListener() { - public void - actionPerformed(ActionEvent e) { setMidiPort(); } - }); - - cbMidiChannel.addActionListener(new ActionListener() { - public void - actionPerformed(ActionEvent e) { setMidiChannel(); } - }); - - cbEngine.addActionListener(new ActionListener() { - public void - actionPerformed(ActionEvent e) { setEngineType(); } - }); - - cbAudioDevice.addActionListener(new ActionListener() { - public void - actionPerformed(ActionEvent e) { setAudioDevice(); } - }); - - channel.getModel().addSamplerChannelListener(new SamplerChannelAdapter() { - public void - channelChanged(SamplerChannelEvent e) { updateChannelProperties(); } - }); - - CC.getSamplerModel().addMidiDeviceListListener(getHandler()); - CC.getSamplerModel().addAudioDeviceListListener(getHandler()); + class SetNormalViewAction extends AbstractAction { + SetNormalViewAction() { + super(i18n.getMenuLabel("channels.normalView")); + } - updateMidiDevices(); - updateAudioDevices(); - updateChannelProperties(); + public void + actionPerformed(ActionEvent e) { + viewTracker.setView(new NormalChannelView(Channel.this)); + } } - /** - * Updates the channel settings. This method is invoked when changes to the - * channel were made. - */ - private void - updateChannelProperties() { - SamplerModel sm = CC.getSamplerModel(); - SamplerChannel sc = channel.getModel().getChannelInfo(); - - MidiDeviceModel mm = sm.getMidiDeviceModel(sc.getMidiInputDevice()); - AudioDeviceModel am = sm.getAudioDeviceModel(sc.getAudioOutputDevice()); - - if(isUpdate()) CC.getLogger().warning("Unexpected update state!"); + public ContextMenu + getContextMenu() { return contextMenu; } + + class ContextMenu extends MouseAdapter { + private final JPopupMenu menu = new JPopupMenu(); - setUpdate(true); + protected final JRadioButtonMenuItem rbmiSmallView; + protected final JRadioButtonMenuItem rbmiNormalView; - try { - cbMidiDevice.setSelectedItem(mm == null ? null : mm.getDeviceInfo()); + ContextMenu() { + menu.add(new JMenuItem(new EditInstrumentAction())); + menu.addSeparator(); + + rbmiSmallView = new JRadioButtonMenuItem(new SetSmallViewAction()); + rbmiNormalView = new JRadioButtonMenuItem(new SetNormalViewAction()); - cbEngine.setSelectedItem(sc.getEngine()); + ButtonGroup group = new ButtonGroup(); + group.add(rbmiSmallView); + group.add(rbmiNormalView); - cbAudioDevice.setSelectedItem(am == null ? null : am.getDeviceInfo()); - } catch(Exception x) { - CC.getLogger().log(Level.WARNING, "Unkown error", x); + menu.add(rbmiSmallView); + menu.add(rbmiNormalView); + + menu.addSeparator(); + menu.add(new JMenuItem(new FxSendsAction())); + menu.add(new JMenuItem(new ChannelRoutingAction())); } - setUpdate(false); + public void + mousePressed(MouseEvent e) { + if(e.isPopupTrigger()) show(e); + } + + public void + mouseReleased(MouseEvent e) { + if(e.isPopupTrigger()) show(e); + } + + void + show(MouseEvent e) { + menu.show(e.getComponent(), e.getX(), e.getY()); + } } - /** - * Updates the MIDI device list. - */ - private void - updateMidiDevices() { - SamplerModel sm = CC.getSamplerModel(); - SamplerChannel sc = channel.getModel().getChannelInfo(); - - setUpdate(true); - - try { - cbMidiDevice.removeAllItems(); + class FxSendsPane extends JSFxSendsPane { + FxSendsPane(SamplerChannelModel model) { + super(model); + + actionAddFxSend.putValue(Action.SMALL_ICON, Res.iconNew16); + actionRemoveFxSend.putValue(Action.SMALL_ICON, Res.iconDelete16); + } - for(MidiDeviceModel m : sm.getMidiDeviceModels()) - cbMidiDevice.addItem(m.getDeviceInfo()); + protected JToolBar + createToolBar() { + JToolBar tb = new JToolBar(); + Dimension d = new Dimension(Short.MAX_VALUE, tb.getPreferredSize().height); + tb.setMaximumSize(d); + tb.setFloatable(false); + tb.setAlignmentX(JPanel.RIGHT_ALIGNMENT); + + tb.add(new ToolbarButton(actionAddFxSend)); + tb.add(new ToolbarButton(actionRemoveFxSend)); - MidiDeviceModel mm = sm.getMidiDeviceModel(sc.getMidiInputDevice()); - cbMidiDevice.setSelectedItem(mm == null ? null : mm.getDeviceInfo()); - } catch(Exception x) { - CC.getLogger().log(Level.WARNING, "Unkown error", x); + return tb; } - - setUpdate(false); } - /** - * Updates the audio device list. - */ - private void - updateAudioDevices() { - SamplerModel sm = CC.getSamplerModel(); - SamplerChannel sc = channel.getModel().getChannelInfo(); - - setUpdate(true); + public static class StreamVoiceCountPane extends JPanel { + private final Channel channel; - try { - cbAudioDevice.removeAllItems(); + private final JLabel lStreams = createScreenLabel(" --"); + private final JLabel lSlash = createScreenLabel("/"); + private final JLabel lVoices = createScreenLabel("-- "); - for(AudioDeviceModel m : sm.getAudioDeviceModels()) - cbAudioDevice.addItem(m.getDeviceInfo()); + public + StreamVoiceCountPane(Channel channel) { + this.channel = channel; + + setOpaque(false); + setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); + lStreams.setFont(Res.fontScreenMono); + lStreams.setHorizontalAlignment(JLabel.RIGHT); + lStreams.setToolTipText(i18n.getLabel("Channel.streamVoiceCount")); + + Dimension d = lStreams.getPreferredSize(); + lStreams.setMinimumSize(d); + lStreams.setPreferredSize(d); + lStreams.setMaximumSize(d); + add(lStreams); + + lSlash.setFont(Res.fontScreenMono); + lSlash.setToolTipText(i18n.getLabel("Channel.streamVoiceCount")); + add(lSlash); + + lVoices.setFont(Res.fontScreenMono); + lVoices.setToolTipText(i18n.getLabel("Channel.streamVoiceCount")); + + d = lStreams.getPreferredSize(); + lVoices.setMinimumSize(d); + lVoices.setPreferredSize(d); + lVoices.setMaximumSize(d); + add(lVoices); + + lStreams.addMouseListener(channel.getContextMenu()); + lSlash.addMouseListener(channel.getContextMenu()); + lVoices.addMouseListener(channel.getContextMenu()); + } - AudioDeviceModel am = sm.getAudioDeviceModel(sc.getAudioOutputDevice()); - cbAudioDevice.setSelectedItem(am == null ? null : am.getDeviceInfo()); - } catch(Exception x) { - CC.getLogger().log(Level.WARNING, "Unkown error", x); + public void + updateStreamCount(int count) { + lStreams.setText(count == 0 ? " --" : String.valueOf(count)); } - setUpdate(false); + public void + updateVoiceCount(int count) { + lVoices.setText(count == 0 ? "-- " : String.valueOf(count)); + } } - private void - setMidiDevice() { - MidiInputDevice mid = (MidiInputDevice)cbMidiDevice.getSelectedItem(); + public static class VolumePane extends JPanel { + private final Channel channel; + private final JButton btnVolume = createScreenButton(""); + private JSVolumeEditorPopup popupVolume; - if(!isUpdate()) { - if(mid != null) channel.getModel().setMidiInputDevice(mid.getDeviceID()); - return; - } + private static NumberFormat numberFormat = NumberFormat.getInstance(); + static { numberFormat.setMaximumFractionDigits(1); } - cbMidiPort.removeAllItems(); - - if(mid == null) { - cbMidiPort.setEnabled(false); + public + VolumePane(final Channel channel) { + this.channel = channel; + setOpaque(false); + setLayout(new BoxLayout(this, BoxLayout.X_AXIS)); - cbMidiChannel.setSelectedItem(null); - cbMidiChannel.setEnabled(false); - } else { - cbMidiPort.setEnabled(true); + btnVolume.setIcon(Res.iconVolume14); + btnVolume.setIconTextGap(2); + btnVolume.setAlignmentX(RIGHT_ALIGNMENT); + btnVolume.setHorizontalAlignment(btnVolume.LEFT); + updateVolumeInfo(100); + Dimension d = btnVolume.getPreferredSize(); + d.width = 57; + btnVolume.setPreferredSize(d); + btnVolume.setMinimumSize(d); - MidiPort[] ports = mid.getMidiPorts(); - for(MidiPort port : ports) cbMidiPort.addItem(port); + add(btnVolume); - int p = channel.getModel().getChannelInfo().getMidiInputPort(); - cbMidiPort.setSelectedItem(p >= 0 && p < ports.length ? ports[p] : null); + btnVolume.addActionListener(new ActionListener() { + public void + actionPerformed(ActionEvent e) { + if(popupVolume.isVisible()) { + popupVolume.commit(); + popupVolume.hide(); + } else { + float vol = channel.getModel().getChannelInfo().getVolume(); + popupVolume.setCurrentVolume(vol); + popupVolume.show(); + } + } + }); + + popupVolume = new JSVolumeEditorPopup(btnVolume, VolumeType.CHANNEL); + + popupVolume.addActionListener(new ActionListener() { + public void + actionPerformed(ActionEvent e) { + channel.getModel().setBackendVolume(popupVolume.getVolumeFactor()); + } + }); - cbMidiChannel.setEnabled(true); - int c = channel.getModel().getChannelInfo().getMidiInputChannel(); - cbMidiChannel.setSelectedItem(c == -1 ? "All" : "Channel " + (c + 1)); + btnVolume.addMouseListener(channel.getContextMenu()); } - } - - private void - setMidiPort() { - if(isUpdate()) return; - channel.getModel().setMidiInputPort(cbMidiPort.getSelectedIndex()); + public void + updateVolumeInfo(int volume) { + if(CC.getViewConfig().isMeasurementUnitDecibel()) { + String s = numberFormat.format(HF.percentsToDecibels(volume)); + btnVolume.setText(s + "dB"); + } else { + btnVolume.setText(String.valueOf(volume) + "%"); + } + } } - private void - setMidiChannel() { - if(isUpdate()) return; + public static class PowerButton extends PixmapToggleButton implements ActionListener { + private final Channel channel; - Object o = cbMidiChannel.getSelectedItem(); - if(o == null) return; - String s = o.toString(); - - int c = s.equals("All") ? -1 : Integer.parseInt(s.substring(8)) - 1; - - channel.getModel().setMidiInputChannel(c); - } - - /** Invoked when the user selects an engine. */ - private void - setEngineType() { - Object oldEngine = channel.getModel().getChannelInfo().getEngine(); - SamplerEngine newEngine = (SamplerEngine)cbEngine.getSelectedItem(); + PowerButton(Channel channel) { + this(channel, Res.gfxPowerOff, Res.gfxPowerOn); + } - if(oldEngine != null) { if(oldEngine.equals(newEngine)) return; } - else if(newEngine == null) return; + PowerButton(Channel channel, ImageIcon defaultIcon, ImageIcon selectedIcon) { + super(defaultIcon, selectedIcon); + + this.channel = channel; - channel.getModel().setEngineType(newEngine.getName()); + setSelected(true); + addActionListener(this); + setToolTipText(i18n.getButtonLabel("Channel.ttRemoveChannel")); + } - } - - private void - setAudioDevice() { - if(isUpdate()) return; - AudioOutputDevice dev = (AudioOutputDevice)cbAudioDevice.getSelectedItem(); - if(dev != null) channel.getModel().setAudioOutputDevice(dev.getDeviceID()); - } - - /** - * Determines whether the currently processed changes are due to update. - * @return true if the currently processed changes are due to update and - * false if the currently processed changes are due to user input. - */ - private boolean - isUpdate() { return update; } - - /** - * Sets whether the currently processed changes are due to update. - * @param b Specify true to indicate that the currently - * processed changes are due to update; false - * indicates that the currently processed changes are due to user input. - */ - private void - setUpdate(boolean b) { update = b; } - - private final Handler handler = new Handler(); - - private Handler - getHandler() { return handler; } - - private class Handler implements MidiDeviceListListener, AudioDeviceListListener { - /** - * Invoked when a new MIDI device is created. - * @param e A MidiDeviceListEvent - * instance providing the event information. - */ public void - deviceAdded(MidiDeviceListEvent e) { - cbMidiDevice.addItem(e.getMidiDeviceModel().getDeviceInfo()); + actionPerformed(ActionEvent e) { + boolean b = preferences().getBoolProperty(CONFIRM_CHANNEL_REMOVAL); + if(b) { + String s = i18n.getMessage("Channel.remove?", channel.getChannelId()); + if(!HF.showYesNoDialog(channel, s)) { + setSelected(true); + return; + } + } + channel.remove(); } + + public boolean + contains(int x, int y) { return (x - 11)*(x - 11) + (y - 11)*(y - 11) < 71; } + } - /** - * Invoked when a MIDI device is removed. - * @param e A MidiDeviceListEvent - * instance providing the event information. - */ - public void - deviceRemoved(MidiDeviceListEvent e) { - cbMidiDevice.removeItem(e.getMidiDeviceModel().getDeviceInfo()); - } + public static class OptionsButton extends PixmapToggleButton implements ActionListener { + private final Channel channel; - /** - * Invoked when a new audio device is created. - * @param e An AudioDeviceListEvent - * instance providing the event information. - */ - public void - deviceAdded(AudioDeviceListEvent e) { - cbAudioDevice.addItem(e.getAudioDeviceModel().getDeviceInfo()); + OptionsButton(Channel channel) { + super(Res.gfxOptionsOff, Res.gfxOptionsOn); + + this.channel = channel; + + setRolloverIcon(Res.gfxOptionsOffRO); + this.setRolloverSelectedIcon(Res.gfxOptionsOnRO); + addActionListener(this); + setToolTipText(i18n.getButtonLabel("Channel.ttShowOptions")); } - - /** - * Invoked when an audio device is removed. - * @param e An AudioDeviceListEvent - * instance providing the event information. - */ + public void - deviceRemoved(AudioDeviceListEvent e) { - cbAudioDevice.removeItem(e.getAudioDeviceModel().getDeviceInfo()); + actionPerformed(ActionEvent e) { + channel.showOptionsPane(isSelected()); + + String s; + if(isSelected()) s = i18n.getButtonLabel("Channel.ttHideOptions"); + else s = i18n.getButtonLabel("Channel.ttShowOptions"); + + setToolTipText(s); } + + public boolean + contains(int x, int y) { return super.contains(x, y) & y < 13; } } } + +class ChannelOptionsPane extends JXCollapsiblePane { + ChannelOptionsPane() { + setAnimated(false); + setCollapsed(true); + setAnimated(preferences().getBoolProperty(ANIMATED)); + + preferences().addPropertyChangeListener(ANIMATED, new PropertyChangeListener() { + public void + propertyChange(PropertyChangeEvent e) { + setAnimated(preferences().getBoolProperty(ANIMATED)); + } + }); + } + + public void + showOptionsPane(boolean show) { setCollapsed(!show); } +}