/[svn]/jsampler/trunk/src/org/jsampler/view/fantasia/Channel.java
ViewVC logotype

Annotation of /jsampler/trunk/src/org/jsampler/view/fantasia/Channel.java

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1496 - (hide annotations) (download)
Mon Nov 19 22:22:22 2007 UTC (16 years, 5 months ago) by iliev
File size: 47624 byte(s)
* Added option for turning off the custom window decoration
  (choose Edit/Preferences, then click the `View' tab)
* Added new menu item: Help/Online Tutorial
* Fantasia: first step of implementing a theme manager
* Fantasia: fixed the view of the channel's stream/voice count statistic
* some minor GUI fixes and enhancements

1 iliev 912 /*
2     * JSampler - a java front-end for LinuxSampler
3     *
4 iliev 1285 * Copyright (C) 2005-2007 Grigor Iliev <grigor@grigoriliev.com>
5 iliev 912 *
6     * This file is part of JSampler.
7     *
8     * JSampler is free software; you can redistribute it and/or modify
9     * it under the terms of the GNU General Public License version 2
10     * as published by the Free Software Foundation.
11     *
12     * JSampler is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with JSampler; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20     * MA 02111-1307 USA
21     */
22    
23     package org.jsampler.view.fantasia;
24    
25 iliev 1467 import java.awt.Container;
26 iliev 912 import java.awt.Cursor;
27     import java.awt.Dimension;
28 iliev 1285 import java.awt.Graphics;
29 iliev 1496 import java.awt.Graphics2D;
30 iliev 912 import java.awt.Insets;
31 iliev 1467 import java.awt.Rectangle;
32 iliev 912
33     import java.awt.event.ActionEvent;
34     import java.awt.event.ActionListener;
35 iliev 1341 import java.awt.event.HierarchyEvent;
36     import java.awt.event.HierarchyListener;
37 iliev 912 import java.awt.event.MouseAdapter;
38     import java.awt.event.MouseEvent;
39    
40 iliev 1285 import java.beans.PropertyChangeEvent;
41     import java.beans.PropertyChangeListener;
42    
43 iliev 912 import java.util.logging.Level;
44    
45 iliev 1285 import javax.swing.Action;
46 iliev 912 import javax.swing.BorderFactory;
47     import javax.swing.Box;
48     import javax.swing.BoxLayout;
49     import javax.swing.DefaultListCellRenderer;
50     import javax.swing.JButton;
51     import javax.swing.JComboBox;
52     import javax.swing.JLabel;
53 iliev 1285 import javax.swing.JMenuItem;
54 iliev 912 import javax.swing.JPanel;
55 iliev 1285 import javax.swing.JPopupMenu;
56 iliev 1467 import javax.swing.JScrollPane;
57 iliev 912 import javax.swing.JToggleButton;
58 iliev 1285 import javax.swing.JToolBar;
59 iliev 912 import javax.swing.SwingConstants;
60 iliev 1341 import javax.swing.Timer;
61 iliev 912
62     import javax.swing.event.ChangeEvent;
63     import javax.swing.event.ChangeListener;
64    
65     import net.sf.juife.Dial;
66 iliev 1285 import net.sf.juife.InformationDialog;
67 iliev 912 import net.sf.juife.JuifeUtils;
68     import net.sf.juife.TitleBar;
69    
70 iliev 1285 import org.jdesktop.swingx.JXCollapsiblePane;
71    
72 iliev 912 import org.jsampler.AudioDeviceModel;
73     import org.jsampler.CC;
74     import org.jsampler.MidiDeviceModel;
75 iliev 1285 import org.jsampler.MidiInstrumentMap;
76 iliev 912 import org.jsampler.SamplerChannelModel;
77     import org.jsampler.SamplerModel;
78    
79 iliev 1143 import org.jsampler.event.ListEvent;
80     import org.jsampler.event.ListListener;
81 iliev 1285 import org.jsampler.event.MidiDeviceEvent;
82 iliev 912 import org.jsampler.event.MidiDeviceListEvent;
83     import org.jsampler.event.MidiDeviceListListener;
84 iliev 1285 import org.jsampler.event.MidiDeviceListener;
85     import org.jsampler.event.SamplerAdapter;
86 iliev 912 import org.jsampler.event.SamplerChannelAdapter;
87     import org.jsampler.event.SamplerChannelEvent;
88 iliev 1285 import org.jsampler.event.SamplerChannelListEvent;
89     import org.jsampler.event.SamplerChannelListListener;
90 iliev 912 import org.jsampler.event.SamplerChannelListener;
91 iliev 1285 import org.jsampler.event.SamplerEvent;
92     import org.jsampler.event.SamplerListener;
93 iliev 912
94 iliev 1285 import org.jsampler.view.std.JSChannelOutputRoutingDlg;
95     import org.jsampler.view.std.JSFxSendsPane;
96     import org.jsampler.view.std.JSInstrumentChooser;
97    
98     import org.jvnet.lafwidget.animation.FadeConfigurationManager;
99     import org.jvnet.lafwidget.animation.FadeKind;
100    
101     import org.jvnet.substance.SubstanceImageCreator;
102     import org.jvnet.substance.SubstanceLookAndFeel;
103    
104 iliev 912 import org.linuxsampler.lscp.AudioOutputDevice;
105     import org.linuxsampler.lscp.MidiInputDevice;
106     import org.linuxsampler.lscp.MidiPort;
107     import org.linuxsampler.lscp.SamplerChannel;
108     import org.linuxsampler.lscp.SamplerEngine;
109    
110     import static org.jsampler.view.fantasia.FantasiaI18n.i18n;
111 iliev 1285 import static org.jsampler.view.fantasia.FantasiaPrefs.*;
112 iliev 912
113    
114     /**
115     *
116     * @author Grigor Iliev
117     */
118     public class Channel extends org.jsampler.view.JSChannel {
119 iliev 1285 private final JXCollapsiblePane mainPane;
120 iliev 912 private final ChannelScreen screen = new ChannelScreen(this);
121     private final ChannelOptions optionsPane = new ChannelOptions(this);
122    
123     private final PowerButton btnPower = new PowerButton();
124     private final MuteButton btnMute = new MuteButton();
125     private final SoloButton btnSolo = new SoloButton();
126     private final OptionsButton btnOptions = new OptionsButton();
127    
128     private final EnhancedDial dialVolume = new EnhancedDial();
129    
130     private boolean selected = false;
131    
132     /**
133     * Creates a new instance of <code>Channel</code> using the specified
134     * non-<code>null</code> channel model.
135     * @param model The model to be used by this channel.
136     * @throws IllegalArgumentException If the model is <code>null</code>.
137     */
138     public
139     Channel(SamplerChannelModel model) {
140 iliev 1318 this(model, null);
141     }
142    
143     /**
144     * Creates a new instance of <code>Channel</code> using the specified
145     * non-<code>null</code> channel model.
146     * @param model The model to be used by this channel.
147     * @param listener A listener which is notified when the newly created
148     * channel is fully expanded on the screen.
149     * @throws IllegalArgumentException If the model is <code>null</code>.
150     */
151     public
152     Channel(SamplerChannelModel model, final ActionListener listener) {
153 iliev 912 super(model);
154    
155     setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
156 iliev 1285 ChannelPane p = new ChannelPane();
157 iliev 912 p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
158    
159     //p.add(Box.createRigidArea(new Dimension(3, 0)));
160    
161     btnPower.setAlignmentY(JPanel.TOP_ALIGNMENT);
162    
163 iliev 1285 JPanel tb = new JPanel();
164 iliev 912 tb.setBorder(BorderFactory.createEmptyBorder(3, 3, 0, 4));
165     tb.setLayout(new BoxLayout(tb, BoxLayout.X_AXIS));
166     tb.setOpaque(false);
167     tb.setAlignmentY(JPanel.TOP_ALIGNMENT);
168     tb.add(btnPower);
169     tb.setPreferredSize(new Dimension(tb.getPreferredSize().width, 58));
170     tb.setMinimumSize(tb.getPreferredSize());
171     tb.setMaximumSize(tb.getPreferredSize());
172     p.add(tb);
173    
174     //p.add(Box.createRigidArea(new Dimension(4, 0)));
175    
176     p.add(createVSeparator());
177    
178     //p.add(Box.createRigidArea(new Dimension(3, 0)));
179    
180     JPanel p2 = new JPanel();
181     p2.setOpaque(false);
182     p2.setLayout(new BoxLayout(p2, BoxLayout.Y_AXIS));
183     p2.setAlignmentY(JPanel.TOP_ALIGNMENT);
184     p2.setBorder(BorderFactory.createEmptyBorder(5, 3, 0, 2));
185     p2.add(screen);
186     p.add(p2);
187    
188     p.add(createVSeparator());
189    
190     p2 = new JPanel();
191     p2.setOpaque(false);
192     p2.setLayout(new BoxLayout(p2, BoxLayout.Y_AXIS));
193     p2.setAlignmentY(JPanel.TOP_ALIGNMENT);
194     p2.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0));
195 iliev 1285 p2.add(new JLabel(Res.gfxMuteTitle));
196 iliev 912 p2.add(btnMute);
197 iliev 1285 p2.add(new JLabel(Res.gfxSoloTitle));
198 iliev 912 p2.add(btnSolo);
199    
200     p.add(p2);
201    
202     p.add(createVSeparator());
203    
204     p2 = new JPanel();
205     p2.setOpaque(false);
206     p2.setLayout(new BoxLayout(p2, BoxLayout.Y_AXIS));
207     p2.setAlignmentY(JPanel.TOP_ALIGNMENT);
208     p2.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 0));
209 iliev 1285 JLabel l = new JLabel(Res.gfxVolumeTitle);
210 iliev 912 l.setAlignmentX(JPanel.CENTER_ALIGNMENT);
211     l.setBorder(BorderFactory.createEmptyBorder(0, 0, 2, 0));
212     p2.add(l);
213 iliev 1285 dialVolume.setDialPixmap(Res.gfxVolumeDial, 30, 330);
214 iliev 912 dialVolume.setAlignmentX(JPanel.CENTER_ALIGNMENT);
215     p2.add(dialVolume);
216     p.add(p2);
217    
218     p.add(createVSeparator());
219    
220     p2 = new JPanel();
221     p2.setOpaque(false);
222     p2.setLayout(new BoxLayout(p2, BoxLayout.Y_AXIS));
223     p2.setAlignmentY(JPanel.TOP_ALIGNMENT);
224     p2.setBorder(BorderFactory.createEmptyBorder(27, 0, 0, 0));
225 iliev 1285 l = new JLabel(Res.gfxOptionsTitle);
226 iliev 912 l.setAlignmentX(JPanel.CENTER_ALIGNMENT);
227     l.setBorder(BorderFactory.createEmptyBorder(0, 0, 2, 0));
228     p2.add(l);
229    
230     p2.add(Box.createRigidArea(new Dimension(0, 3)));
231    
232     btnOptions.setAlignmentX(JPanel.CENTER_ALIGNMENT);
233     p2.add(btnOptions);
234     p.add(p2);
235    
236    
237     p.setPreferredSize(new Dimension(420, 60));
238     p.setMinimumSize(p.getPreferredSize());
239     p.setMaximumSize(p.getPreferredSize());
240     //p.setBorder(BorderFactory.createEmptyBorder(1, 0, 1, 0));
241    
242     p.setAlignmentX(JPanel.CENTER_ALIGNMENT);
243     optionsPane.setAlignmentX(JPanel.CENTER_ALIGNMENT);
244    
245 iliev 1285 mainPane = new JXCollapsiblePane();
246     mainPane.getContentPane().setLayout (
247     new BoxLayout(mainPane.getContentPane(), BoxLayout.Y_AXIS)
248     );
249 iliev 912
250 iliev 1285 mainPane.add(p);
251     mainPane.add(optionsPane);
252    
253     setOpaque(false);
254    
255 iliev 1357 int i = preferences().getIntProperty(MAXIMUM_CHANNEL_VOLUME);
256     dialVolume.setMaximum(i);
257     String mcv = MAXIMUM_CHANNEL_VOLUME;
258     preferences().addPropertyChangeListener(mcv, new PropertyChangeListener() {
259     public void
260     propertyChange(PropertyChangeEvent e) {
261     int j = preferences().getIntProperty(MAXIMUM_CHANNEL_VOLUME);
262     dialVolume.setMaximum(j);
263     }
264     });
265    
266 iliev 912 getModel().addSamplerChannelListener(getHandler());
267    
268     updateChannelInfo();
269 iliev 1285
270     add(mainPane);
271    
272 iliev 1318 if(listener != null) {
273     final String s = JXCollapsiblePane.ANIMATION_STATE_KEY;
274     mainPane.addPropertyChangeListener(s, new PropertyChangeListener() {
275     public void
276     propertyChange(PropertyChangeEvent e) {
277     if(e.getNewValue() == "expanded") {
278 iliev 1467 // TODO: this should be done regardles the listener != null?
279 iliev 1318 mainPane.removePropertyChangeListener(s, this);
280 iliev 1467 ///////
281 iliev 1318 listener.actionPerformed(null);
282 iliev 1467 ensureChannelIsVisible();
283     } else if(e.getNewValue() == "expanding/collapsing") {
284     ensureChannelIsVisible();
285 iliev 1318 }
286     }
287     });
288     }
289    
290 iliev 1285 mainPane.setAnimated(false);
291     mainPane.setCollapsed(true);
292     mainPane.setAnimated(preferences().getBoolProperty(ANIMATED));
293     mainPane.setCollapsed(false);
294    
295     preferences().addPropertyChangeListener(ANIMATED, new PropertyChangeListener() {
296     public void
297     propertyChange(PropertyChangeEvent e) {
298     mainPane.setAnimated(preferences().getBoolProperty(ANIMATED));
299     }
300     });
301 iliev 1318
302     if(listener != null) {
303     javax.swing.SwingUtilities.invokeLater(new Runnable() {
304     public void
305     run() { listener.actionPerformed(null); }
306     });
307     }
308 iliev 1341
309     CC.getSamplerModel().addSamplerChannelListListener(getHandler());
310 iliev 912 }
311    
312 iliev 1467 private void
313     ensureChannelIsVisible() {
314     Container p = getParent();
315     JScrollPane sp = null;
316     while(p != null) {
317     if(p instanceof JScrollPane) {
318     sp = (JScrollPane)p;
319     break;
320     }
321     p = p.getParent();
322     }
323     if(sp == null) return;
324     int h = sp.getViewport().getView().getHeight();
325     sp.getViewport().scrollRectToVisible(new Rectangle(0, h - 2, 1, 1));
326     }
327    
328 iliev 912 private JPanel
329     createVSeparator() {
330 iliev 1285 PixmapPane p = new PixmapPane(Res.gfxVLine);
331 iliev 912 p.setAlignmentY(JPanel.TOP_ALIGNMENT);
332     p.setPreferredSize(new Dimension(2, 60));
333     p.setMinimumSize(p.getPreferredSize());
334     p.setMaximumSize(p.getPreferredSize());
335     return p;
336     }
337    
338     /**
339     * Determines whether the channel is selected.
340     * @return <code>true</code> if the channel is selected, <code>false</code> otherwise.
341     */
342     public boolean isSelected() { return selected; }
343    
344     /**
345     * Sets the selection state of this channel.
346     * This method is invoked when the selection state of the channel has changed.
347     * @param select Specifies the new selection state of this channel;
348     * <code>true</code> to select the channel, <code>false</code> otherwise.
349     */
350     public void
351     setSelected(boolean select) {
352    
353     selected = select;
354     }
355    
356     /** Shows the channel properties. */
357     public void
358 iliev 1285 expandChannel() { expandChannel(optionsPane.isAnimated()); }
359 iliev 912
360 iliev 1285 /** Shows the channel properties. */
361     public void
362     expandChannel(boolean animated) {
363     if(btnOptions.isSelected()) return;
364    
365     boolean b = optionsPane.isAnimated();
366     optionsPane.setAnimated(animated);
367     btnOptions.doClick();
368     optionsPane.setAnimated(b);
369     }
370 iliev 912
371 iliev 1285
372 iliev 912 /** Invoked when the user changes the volume */
373     private void
374     setVolume() {
375     screen.updateVolumeInfo(dialVolume.getValue());
376    
377     if(dialVolume.getValueIsAdjusting()) return;
378    
379     int vol = (int)(getChannelInfo().getVolume() * 100);
380    
381     if(vol == dialVolume.getValue()) return;
382    
383    
384     /*
385     * If the model's volume is not equal to the dial knob
386     * value we assume that the change is due to user input.
387     * So we must update the volume at the backend too.
388     */
389     float volume = dialVolume.getValue();
390     volume /= 100;
391 iliev 1143 getModel().setBackendVolume(volume);
392 iliev 912 }
393    
394     /**
395     * Updates the channel settings. This method is invoked when changes to the
396     * channel were made.
397     */
398     private void
399     updateChannelInfo() {
400     SamplerChannel sc = getChannelInfo();
401    
402     screen.updateScreenInfo(sc);
403     updateMuteIcon(sc);
404    
405 iliev 1285 if(sc.isSoloChannel()) btnSolo.setIcon(Res.gfxSoloOn);
406     else btnSolo.setIcon(Res.gfxSoloOff);
407 iliev 912
408     dialVolume.setValue((int)(sc.getVolume() * 100));
409    
410     boolean b = sc.getEngine() != null;
411     dialVolume.setEnabled(b);
412     btnSolo.setEnabled(b);
413     btnMute.setEnabled(b);
414     }
415    
416     /**
417     * Updates the mute button with the proper icon regarding to information obtained
418     * from <code>channel</code>.
419     * @param channel A <code>SamplerChannel</code> instance containing the new settings
420     * for this channel.
421     */
422     private void
423     updateMuteIcon(SamplerChannel channel) {
424 iliev 1285 if(channel.isMutedBySolo()) btnMute.setIcon(Res.gfxMutedBySolo);
425     else if(channel.isMuted()) btnMute.setIcon(Res.gfxMuteOn);
426     else btnMute.setIcon(Res.gfxMuteOff);
427 iliev 912 }
428    
429     private class EnhancedDial extends Dial {
430     EnhancedDial() {
431     super(0, 100);
432    
433     setMouseHandlerMode(MouseHandlerMode.LEFT_TO_RIGHT_AND_DOWN_TO_UP);
434    
435     addMouseListener(new MouseAdapter() {
436     public void
437     mouseClicked(MouseEvent e) {
438     if(e.getButton() == e.BUTTON3) {
439     setValue(getMaximum() / 2);
440     return;
441     }
442    
443     if(e.getButton() != e.BUTTON1) return;
444    
445     if(e.getClickCount() < 2) return;
446     setValue(getValueByPoint(e.getPoint()));
447     }
448     });
449    
450     addChangeListener(new ChangeListener() {
451     public void
452     stateChanged(ChangeEvent e) { setVolume(); }
453     });
454     }
455     }
456    
457 iliev 1341 protected void
458     onDestroy() {
459     CC.getSamplerModel().removeSamplerChannelListListener(getHandler());
460    
461     screen.onDestroy();
462     optionsPane.onDestroy();
463     }
464    
465 iliev 912 private final EventHandler eventHandler = new EventHandler();
466    
467     private EventHandler
468     getHandler() { return eventHandler; }
469    
470 iliev 1341 private class EventHandler implements SamplerChannelListener, SamplerChannelListListener {
471 iliev 912 /**
472     * Invoked when changes are made to a sampler channel.
473     * @param e A <code>SamplerChannelEvent</code> instance
474     * containing event information.
475     */
476     public void
477     channelChanged(SamplerChannelEvent e) { updateChannelInfo(); }
478    
479     /**
480     * Invoked when the number of active disk streams has changed.
481     * @param e A <code>SamplerChannelEvent</code> instance
482     * containing event information.
483     */
484     public void
485     streamCountChanged(SamplerChannelEvent e) {
486     screen.updateStreamCount(getModel().getStreamCount());
487     }
488    
489     /**
490     * Invoked when the number of active voices has changed.
491     * @param e A <code>SamplerChannelEvent</code> instance
492     * containing event information.
493     */
494     public void
495     voiceCountChanged(SamplerChannelEvent e) {
496     screen.updateVoiceCount(getModel().getVoiceCount());
497     }
498 iliev 1341
499     /**
500     * Invoked when a new sampler channel is created.
501     * @param e A <code>SamplerChannelListEvent</code>
502     * instance providing the event information.
503     */
504     public void
505     channelAdded(SamplerChannelListEvent e) { }
506    
507     /**
508     * Invoked when a sampler channel is removed.
509     * @param e A <code>SamplerChannelListEvent</code>
510     * instance providing the event information.
511     */
512     public void
513     channelRemoved(SamplerChannelListEvent e) {
514     // Some cleanup when the channel is removed.
515     if(e.getChannelModel().getChannelId() == getChannelId()) {
516     onDestroy();
517     }
518     }
519 iliev 912 }
520    
521    
522 iliev 1285 private class PowerButton extends PixmapToggleButton
523     implements ActionListener, PropertyChangeListener {
524    
525 iliev 912 PowerButton() {
526 iliev 1285 super(Res.gfxPowerOff, Res.gfxPowerOn);
527 iliev 912
528     setSelected(true);
529     addActionListener(this);
530     }
531    
532     public void
533     actionPerformed(ActionEvent e) {
534 iliev 1285 if(!mainPane.isAnimated()) {
535     CC.getSamplerModel().removeBackendChannel(getChannelId());
536     return;
537     }
538    
539     String s = JXCollapsiblePane.ANIMATION_STATE_KEY;
540     mainPane.addPropertyChangeListener(s, this);
541     mainPane.setCollapsed(true);
542 iliev 912 }
543    
544 iliev 1285 public void
545     propertyChange(PropertyChangeEvent e) {
546     if(e.getNewValue() == "collapsed") {
547     CC.getSamplerModel().removeBackendChannel(getChannelId());
548     }
549     }
550    
551 iliev 912 public boolean
552     contains(int x, int y) { return (x - 11)*(x - 11) + (y - 11)*(y - 11) < 71; }
553     }
554    
555     private class MuteButton extends PixmapButton implements ActionListener {
556     MuteButton() {
557 iliev 1285 super(Res.gfxMuteOff);
558     //setDisabledIcon(Res.gfxMuteSoloDisabled);
559     setDisabledIcon (
560     SubstanceImageCreator.makeTransparent(this, Res.gfxMuteOff, 0.4)
561     );
562 iliev 912 addActionListener(this);
563     }
564    
565     public void
566     actionPerformed(ActionEvent e) {
567     SamplerChannel sc = getChannelInfo();
568     boolean b = true;
569    
570     /*
571     * Changing the mute button icon now instead of
572     * leaving the work to the notification mechanism of the LinuxSampler.
573     */
574     if(sc.isMuted() && !sc.isMutedBySolo()) {
575     b = false;
576     boolean hasSolo = CC.getSamplerModel().hasSoloChannel();
577    
578 iliev 1285 if(sc.isSoloChannel() || !hasSolo) setIcon(Res.gfxMuteOff);
579     else setIcon(Res.gfxMutedBySolo);
580     } else setIcon(Res.gfxMuteOn);
581 iliev 912
582 iliev 1143 Channel.this.getModel().setBackendMute(b);
583 iliev 912 }
584    
585     public boolean
586     contains(int x, int y) { return (x > 5 && x < 23) && (y > 5 && y < 16); }
587     }
588    
589     private class SoloButton extends PixmapButton implements ActionListener {
590     SoloButton() {
591 iliev 1285 super(Res.gfxSoloOff);
592     //setDisabledIcon(Res.gfxMuteSoloDisabled);
593     setDisabledIcon (
594     SubstanceImageCreator.makeTransparent(this, Res.gfxSoloOff, 0.4)
595     );
596 iliev 912 addActionListener(this);
597     }
598    
599     public void
600     actionPerformed(ActionEvent e) {
601     SamplerChannel sc = getChannelInfo();
602     boolean b = !sc.isSoloChannel();
603    
604     /*
605     * Changing the solo button icon (and related) now instead of
606     * leaving the work to the notification mechanism of the LinuxSampler.
607     */
608     if(b) {
609 iliev 1285 setIcon(Res.gfxSoloOn);
610     if(sc.isMutedBySolo()) btnMute.setIcon(Res.gfxMuteOff);
611 iliev 912 } else {
612 iliev 1285 setIcon(Res.gfxSoloOff);
613 iliev 912 if(!sc.isMuted() && CC.getSamplerModel().getSoloChannelCount() > 1)
614 iliev 1285 btnMute.setIcon(Res.gfxMutedBySolo);
615 iliev 912 }
616    
617 iliev 1143 Channel.this.getModel().setBackendSolo(b);
618 iliev 912 }
619    
620     public boolean
621     contains(int x, int y) { return (x > 5 && x < 23) && (y > 5 && y < 16); }
622     }
623    
624     private class OptionsButton extends PixmapToggleButton implements ActionListener {
625     OptionsButton() {
626 iliev 1285 super(Res.gfxOptionsOff, Res.gfxOptionsOn);
627     setRolloverIcon(Res.gfxOptionsOffRO);
628     this.setRolloverSelectedIcon(Res.gfxOptionsOnRO);
629 iliev 912 addActionListener(this);
630     }
631    
632     public void
633     actionPerformed(ActionEvent e) {
634     showOptionsPane(isSelected());
635    
636     String s;
637     if(isSelected()) s = i18n.getButtonLabel("OptionsButton.ttHideOptions");
638     else s = i18n.getButtonLabel("OptionsButton.ttShowOptions");
639    
640     setToolTipText(s);
641     }
642    
643     private void
644     showOptionsPane(boolean show) {
645 iliev 1285 optionsPane.setCollapsed(!show);
646 iliev 912 }
647    
648     public boolean
649 iliev 1143 contains(int x, int y) { return super.contains(x, y) & y < 13; }
650 iliev 912 }
651     }
652    
653 iliev 1285 class ChannelPane extends PixmapPane {
654     ChannelPane() {
655     super(Res.gfxChannel);
656     setPixmapInsets(new Insets(3, 3, 3, 3));
657     }
658     }
659    
660     class ChannelScreen extends PixmapPane {
661 iliev 912 private final Channel channel;
662 iliev 1341
663     private final InstrumentPane instrumentPane;
664 iliev 912 private JButton btnInstr = new ScreenButton(i18n.getButtonLabel("ChannelScreen.btnInstr"));
665    
666 iliev 1341 private final JButton btnEditInstr =
667     new ScreenButton(i18n.getButtonLabel("ChannelScreen.btnEditInstr"));
668     private final ScreenButtonBg sbbEditInstr = new ScreenButtonBg(btnEditInstr);
669    
670 iliev 1285 private final JButton btnFxSends =
671     new ScreenButton(i18n.getButtonLabel("ChannelScreen.btnFxSends"));
672 iliev 912
673 iliev 1285 private final JButton btnEngine
674     = new ScreenButton(i18n.getButtonLabel("ChannelScreen.btnEngine"));
675    
676     private final JPopupMenu menuEngines = new JPopupMenu();
677    
678 iliev 1496 private final JLabel lVolume = new ScreenLabel("");
679     private final JLabel lStreams = new ScreenLabel(" --");
680     private final JLabel lVoices = new ScreenLabel("-- ");
681 iliev 1285
682     private InformationDialog fxSendsDlg = null;
683    
684     private Dimension dimVolume;
685    
686 iliev 1341 private Timer timer;
687    
688 iliev 1285 ChannelScreen(final Channel channel) {
689     super(Res.gfxChannelScreen);
690     setPixmapInsets(new Insets(6, 6, 6, 6));
691 iliev 1496 setBorder(BorderFactory.createEmptyBorder(5, 4, 5, 4));
692 iliev 1285
693 iliev 912 this.channel = channel;
694    
695 iliev 1285 setOpaque(false);
696 iliev 912
697     setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
698    
699     btnInstr.setAlignmentX(CENTER_ALIGNMENT);
700 iliev 1285 btnInstr.setRolloverEnabled(false);
701     btnInstr.setBorder(BorderFactory.createEmptyBorder(3, 0, 0, 0));
702 iliev 912
703 iliev 1341 instrumentPane = new InstrumentPane();
704     add(instrumentPane);
705 iliev 912
706     JPanel p = new JPanel();
707     p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
708     p.setAlignmentX(CENTER_ALIGNMENT);
709 iliev 1285 p.setBorder(BorderFactory.createEmptyBorder(5, 0, 0, 0));
710 iliev 912
711 iliev 1285 btnFxSends.setToolTipText(i18n.getButtonLabel("ChannelScreen.btnFxSends.tt"));
712     btnFxSends.addActionListener(new ActionListener() {
713     public void
714     actionPerformed(ActionEvent e) {
715     if(fxSendsDlg != null && fxSendsDlg.isVisible()) {
716     fxSendsDlg.toFront();
717     return;
718     }
719     FxSendsPane p = new FxSendsPane(channel.getModel());
720     int id = channel.getModel().getChannelId();
721     fxSendsDlg = new InformationDialog(CC.getMainFrame(), p);
722     fxSendsDlg.setTitle(i18n.getLabel("FxSendsDlg.title", id));
723     fxSendsDlg.setModal(false);
724     fxSendsDlg.showCloseButton(false);
725     fxSendsDlg.setVisible(true);
726     }
727     });
728 iliev 912
729 iliev 1285 p.add(btnFxSends);
730    
731 iliev 912 p.add(Box.createRigidArea(new Dimension(6, 0)));
732    
733 iliev 1285 btnEngine.setIcon(Res.iconEngine12);
734     p.add(btnEngine);
735     //p.add(new Label("|"));
736 iliev 912
737 iliev 1285 //p.add(Box.createRigidArea(new Dimension(6, 0)));
738 iliev 912
739 iliev 1285 //p.add(btnReset);
740 iliev 912
741     p.add(Box.createGlue());
742    
743 iliev 1496 lStreams.setFont(Res.fontScreenMono);
744     lStreams.setHorizontalAlignment(JLabel.RIGHT);
745 iliev 912 p.add(lStreams);
746 iliev 1496
747     JLabel l = new ScreenLabel("/");
748     l.setFont(Res.fontScreenMono);
749     p.add(l);
750    
751     lVoices.setFont(Res.fontScreenMono);
752 iliev 912 p.add(lVoices);
753    
754 iliev 1285 lVolume.setIcon(Res.iconVolume14);
755 iliev 912 lVolume.setAlignmentX(RIGHT_ALIGNMENT);
756 iliev 1285 updateVolumeInfo(100);
757     dimVolume = lVolume.getPreferredSize();
758 iliev 912 p.add(lVolume);
759     p.setPreferredSize(new Dimension(250, p.getPreferredSize().height));
760     p.setMinimumSize(p.getPreferredSize());
761     p.setMaximumSize(p.getPreferredSize());
762    
763 iliev 1285 //btnInstr.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
764     p.setOpaque(false);
765 iliev 912 add(p);
766    
767    
768     setPreferredSize(new Dimension(270, 48));
769     setMinimumSize(getPreferredSize());
770     setMaximumSize(getPreferredSize());
771    
772 iliev 1285 createEngineMenu();
773 iliev 912 installListeners();
774     }
775    
776 iliev 1341 protected void
777     onDestroy() { timer.stop(); }
778    
779 iliev 912 private void
780 iliev 1285 createEngineMenu() {
781     for(final SamplerEngine engine : CC.getSamplerModel().getEngines()) {
782     JMenuItem mi = new JMenuItem(engine.getDescription());
783    
784     mi.addActionListener(new ActionListener() {
785     public void
786     actionPerformed(ActionEvent e) {
787     channel.getModel().setBackendEngineType(engine.getName());
788     }
789     });
790    
791     menuEngines.add(mi);
792     }
793     }
794    
795     private void
796 iliev 912 installListeners() {
797     btnInstr.addActionListener(new ActionListener() {
798     public void
799     actionPerformed(ActionEvent e) { loadInstrument(); }
800     });
801    
802 iliev 1341 btnEditInstr.addActionListener(new ActionListener() {
803     public void
804     actionPerformed(ActionEvent e) {
805     CC.getSamplerModel().editBackendInstrument(channel.getChannelId());
806     }
807     });
808    
809 iliev 1285 btnEngine.addActionListener(new ActionListener() {
810 iliev 912 public void
811 iliev 1143 actionPerformed(ActionEvent e) {
812 iliev 1285 int y = btnEngine.getHeight() + 1;
813     menuEngines.show(btnEngine, 0, y);
814 iliev 1143 }
815 iliev 912 });
816 iliev 1341
817     addMouseListener(getHandler());
818     addHierarchyListener(getHandler());
819    
820     ActionListener l = new ActionListener() {
821     public void
822     actionPerformed(ActionEvent e) {
823     if(getMousePosition(true) != null) {
824     getHandler().mouseEntered(null);
825     } else {
826     getHandler().mouseExited(null);
827     }
828     }
829     };
830     timer = new Timer(1000, l);
831     timer.start();
832 iliev 912 }
833 iliev 1285
834 iliev 912 private void
835     loadInstrument() {
836 iliev 1357 JSInstrumentChooser dlg = FantasiaUtils.createInstrumentChooser(CC.getMainFrame());
837 iliev 912 dlg.setVisible(true);
838    
839     if(!dlg.isCancelled()) {
840     SamplerChannelModel m = channel.getModel();
841 iliev 1285 m.loadBackendInstrument(dlg.getInstrumentFile(), dlg.getInstrumentIndex());
842 iliev 912 }
843     }
844    
845     protected void
846     updateScreenInfo(SamplerChannel sc) {
847     int status = sc.getInstrumentStatus();
848     if(status >= 0 && status < 100) {
849     btnInstr.setText(i18n.getLabel("ChannelScreen.loadingInstrument", status));
850     } else if(status == -1) {
851     btnInstr.setText(i18n.getButtonLabel("ChannelScreen.btnInstr"));
852     } else if(status < -1) {
853     btnInstr.setText(i18n.getLabel("ChannelScreen.errorLoadingInstrument"));
854     } else {
855     if(sc.getInstrumentName() != null) btnInstr.setText(sc.getInstrumentName());
856     else btnInstr.setText(i18n.getButtonLabel("ChannelScreen.btnInstr"));
857     }
858 iliev 1341
859     instrumentPane.update();
860 iliev 912
861 iliev 1285 if(sc.getEngine() != null) {
862     String s = sc.getEngine().getDescription();
863     if(!s.equals(btnEngine.getText())) btnEngine.setText(s);
864     }
865 iliev 912
866     }
867    
868     protected void
869     updateVolumeInfo(int volume) {
870     lVolume.setText(i18n.getLabel("ChannelScreen.volume", volume));
871 iliev 1285 lVolume.setMinimumSize(dimVolume);
872     lVolume.setPreferredSize(dimVolume);
873 iliev 912
874     }
875    
876     /**
877     * Updates the number of active disk streams.
878     * @param count The new number of active disk streams.
879     */
880     protected void
881     updateStreamCount(int count) {
882     Dimension d = lStreams.getPreferredSize();
883     lStreams.setText(count == 0 ? "--" : String.valueOf(count));
884     d = JuifeUtils.getUnionSize(d, lStreams.getPreferredSize());
885     lStreams.setMinimumSize(d);
886     lStreams.setPreferredSize(d);
887     lStreams.setMaximumSize(d);
888     }
889    
890     /**
891     * Updates the number of active voices.
892     * @param count The new number of active voices.
893     */
894     protected void
895     updateVoiceCount(int count) {
896     Dimension d = lVoices.getPreferredSize();
897     lVoices.setText(count == 0 ? "--" : String.valueOf(count));
898     d = JuifeUtils.getUnionSize(d, lVoices.getPreferredSize());
899     lVoices.setMinimumSize(d);
900     lVoices.setPreferredSize(d);
901     lVoices.setMaximumSize(d);
902     }
903    
904 iliev 1341 class InstrumentPane extends JPanel {
905     private final JPanel leftPane = new JPanel();
906     private final JPanel rightPane = new JPanel();
907    
908     InstrumentPane() {
909     setOpaque(false);
910     setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
911     add(leftPane);
912     add(btnInstr);
913     add(rightPane);
914     add(sbbEditInstr);
915 iliev 1343 btnEditInstr.setToolTipText(i18n.getLabel("ChannelScreen.btnEditInstr.tt"));
916 iliev 1341 sbbEditInstr.setVisible(false);
917     setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 6));
918    
919     update();
920     }
921    
922     public void
923     update() {
924     int a = btnInstr.getMinimumSize().width;
925     int b = 0;
926     if(sbbEditInstr.isVisible()) b = sbbEditInstr.getPreferredSize().width;
927    
928     int max = 254 - b;
929     if(a > max) a = max;
930    
931     int h = btnInstr.getPreferredSize().height;
932     btnInstr.setPreferredSize(new Dimension(a, h));
933     h = btnInstr.getMaximumSize().height;
934     btnInstr.setMaximumSize(new Dimension(a, h));
935    
936    
937     int i = (254 - btnInstr.getPreferredSize().width) / 2;
938    
939     int j = i;
940     if(sbbEditInstr.isVisible()) j -= sbbEditInstr.getPreferredSize().width;
941     if(i < 0 || j < 0) i = j = 0;
942    
943     Dimension d = new Dimension(i, 1);
944     leftPane.setMinimumSize(d);
945     leftPane.setPreferredSize(d);
946     leftPane.setMaximumSize(d);
947    
948     d = new Dimension(j, 1);
949     rightPane.setMinimumSize(d);
950     rightPane.setPreferredSize(d);
951     rightPane.setMaximumSize(d);
952    
953     validate();
954     }
955     }
956    
957 iliev 1285 class FxSendsPane extends JSFxSendsPane {
958     FxSendsPane(SamplerChannelModel model) {
959     super(model);
960    
961     actionAddFxSend.putValue(Action.SMALL_ICON, Res.iconNew16);
962     actionRemoveFxSend.putValue(Action.SMALL_ICON, Res.iconDelete16);
963     }
964    
965     protected JToolBar
966     createToolBar() {
967     JToolBar tb = new JToolBar();
968     Dimension d = new Dimension(Short.MAX_VALUE, tb.getPreferredSize().height);
969     tb.setMaximumSize(d);
970     tb.setFloatable(false);
971     tb.setAlignmentX(JPanel.RIGHT_ALIGNMENT);
972    
973     tb.add(new ToolbarButton(actionAddFxSend));
974     tb.add(new ToolbarButton(actionRemoveFxSend));
975    
976     return tb;
977     }
978     }
979    
980 iliev 912 static class ScreenButton extends JButton {
981     ScreenButton(String s) {
982     super(s);
983     setContentAreaFilled(false);
984     setFocusPainted(false);
985     setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
986     setMargin(new Insets(0, 0, 0, 0));
987 iliev 1285
988     putClientProperty (
989     SubstanceLookAndFeel.BUTTON_NO_MIN_SIZE_PROPERTY, Boolean.TRUE
990     );
991    
992     putClientProperty (
993     SubstanceLookAndFeel.BUTTON_PAINT_NEVER_PROPERTY, Boolean.TRUE
994     );
995    
996     putClientProperty(SubstanceLookAndFeel.FLAT_PROPERTY, Boolean.TRUE);
997    
998     FadeConfigurationManager.getInstance().disallowFades(FadeKind.ROLLOVER, this);
999    
1000 iliev 912 setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
1001 iliev 1285 setFont(Res.fontScreen);
1002     setForeground(new java.awt.Color(0xFFA300));
1003 iliev 912 }
1004 iliev 1496
1005     protected void
1006     paintComponent(Graphics g) {
1007     Graphics2D g2d = (Graphics2D)g;
1008    
1009     g2d.setRenderingHint (
1010     java.awt.RenderingHints.KEY_TEXT_ANTIALIASING,
1011     java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_ON
1012     );
1013    
1014     super.paintComponent(g2d);
1015     }
1016 iliev 912 }
1017 iliev 1341
1018     static class ScreenButtonBg extends PixmapPane {
1019     ScreenButtonBg(JButton btn) {
1020     super(Res.gfxScreenBtnBg);
1021     setPixmapInsets(new Insets(4, 4, 4, 4));
1022     setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
1023     setBorder(BorderFactory.createEmptyBorder(0, 7, 0, 7));
1024     add(btn);
1025     setPreferredSize(new Dimension(getPreferredSize().width, 13));
1026     }
1027    
1028     public Dimension
1029     getPreferredSize() {
1030     return new Dimension(super.getPreferredSize().width, 13);
1031     }
1032     }
1033    
1034 iliev 1496
1035    
1036     static class ScreenLabel extends JLabel {
1037     ScreenLabel() { this(""); }
1038    
1039     ScreenLabel(String s) {
1040     super(s);
1041     setFont(Res.fontScreen);
1042     setForeground(new java.awt.Color(0xFFA300));
1043     }
1044    
1045     protected void
1046     paintComponent(Graphics g) {
1047     Graphics2D g2d = (Graphics2D)g;
1048    
1049     g2d.setRenderingHint (
1050     java.awt.RenderingHints.KEY_TEXT_ANTIALIASING,
1051     java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_ON
1052     );
1053    
1054     super.paintComponent(g2d);
1055     }
1056     }
1057    
1058 iliev 1341 private final EventHandler eventHandler = new EventHandler();
1059    
1060     private EventHandler
1061     getHandler() { return eventHandler; }
1062    
1063     private class EventHandler extends MouseAdapter implements HierarchyListener {
1064     public void
1065     mouseEntered(MouseEvent e) {
1066 iliev 1357 if(channel.getChannelInfo().getInstrumentStatus() != 100) return;
1067    
1068 iliev 1341 if(!sbbEditInstr.isVisible()) {
1069     sbbEditInstr.setVisible(true);
1070     instrumentPane.update();
1071     }
1072     }
1073    
1074     public void
1075     mouseExited(MouseEvent e) {
1076     if(getMousePosition(true) != null) return;
1077     if(sbbEditInstr.isVisible()) {
1078     sbbEditInstr.setVisible(false);
1079     instrumentPane.update();
1080     }
1081     }
1082    
1083     /** Called when the hierarchy has been changed. */
1084     public void
1085     hierarchyChanged(HierarchyEvent e) {
1086     if((e.getChangeFlags() & e.SHOWING_CHANGED) == e.SHOWING_CHANGED) {
1087     if(getMousePosition() == null) mouseExited(null);
1088     else mouseEntered(null);
1089     }
1090     }
1091     }
1092 iliev 912 }
1093    
1094 iliev 1285 class ChannelOptions extends JXCollapsiblePane {
1095 iliev 912 private final Channel channel;
1096 iliev 1285 private MidiDeviceModel midiDevice = null;
1097 iliev 912
1098 iliev 1285 private final JComboBox cbMidiDevice = new FantasiaComboBox();
1099     private final JComboBox cbMidiPort = new FantasiaComboBox();
1100     private final JComboBox cbMidiChannel = new FantasiaComboBox();
1101     private final JComboBox cbInstrumentMap = new FantasiaComboBox();
1102     private final JComboBox cbAudioDevice = new FantasiaComboBox();
1103 iliev 912
1104 iliev 1285 private final PixmapButton btnChannelRouting;
1105    
1106 iliev 912 private boolean update = false;
1107    
1108 iliev 1285 private final SamplerListener samplerListener;
1109     private final MapListListener mapListListener = new MapListListener();
1110    
1111     private class NoMap {
1112     public String
1113     toString() { return "[None]"; }
1114     }
1115    
1116     private NoMap noMap = new NoMap();
1117    
1118     private class DefaultMap {
1119     public String
1120     toString() { return "[Default]"; }
1121     }
1122    
1123     private DefaultMap defaultMap = new DefaultMap();
1124    
1125     ChannelOptions(final Channel channel) {
1126     setAnimated(false);
1127     setCollapsed(true);
1128     setAnimated(preferences().getBoolProperty(ANIMATED));
1129    
1130     preferences().addPropertyChangeListener(ANIMATED, new PropertyChangeListener() {
1131     public void
1132     propertyChange(PropertyChangeEvent e) {
1133     setAnimated(preferences().getBoolProperty(ANIMATED));
1134     }
1135     });
1136    
1137     PixmapPane bgp = new PixmapPane(Res.gfxChannelOptions);
1138     bgp.setPixmapInsets(new Insets(1, 1, 1, 1));
1139    
1140 iliev 912 this.channel = channel;
1141    
1142 iliev 1285 bgp.setBorder(BorderFactory.createEmptyBorder(5, 4, 5, 4));
1143     bgp.setLayout(new BoxLayout(bgp, BoxLayout.X_AXIS));
1144 iliev 912
1145 iliev 1285 bgp.setPreferredSize(new Dimension(420, 44));
1146     bgp.setMinimumSize(getPreferredSize());
1147     bgp.setMaximumSize(getPreferredSize());
1148 iliev 912
1149     JPanel p = new JPanel();
1150     p.setBorder(BorderFactory.createEmptyBorder(3, 4, 3, 4));
1151     p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
1152 iliev 1285 JLabel l = new JLabel(Res.gfxMidiInputTitle);
1153 iliev 912 l.setAlignmentX(LEFT_ALIGNMENT);
1154     p.add(l);
1155    
1156     JPanel p2 = new JPanel();
1157     p2.setBorder(BorderFactory.createEmptyBorder(3, 0, 0, 0));
1158     p2.setLayout(new BoxLayout(p2, BoxLayout.X_AXIS));
1159    
1160     Object o = cbMidiDevice.getRenderer();
1161     if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.CENTER);
1162    
1163     cbMidiDevice.setPreferredSize(new Dimension(40, 18));
1164     cbMidiDevice.setMinimumSize(cbMidiDevice.getPreferredSize());
1165     cbMidiDevice.setMaximumSize(cbMidiDevice.getPreferredSize());
1166     p2.add(cbMidiDevice);
1167    
1168     p2.add(Box.createRigidArea(new Dimension(3, 0)));
1169    
1170     o = cbMidiPort.getRenderer();
1171     if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.CENTER);
1172    
1173 iliev 1285 cbMidiPort.setPreferredSize(new Dimension(62, 18));
1174 iliev 912 cbMidiPort.setMinimumSize(cbMidiPort.getPreferredSize());
1175     cbMidiPort.setMaximumSize(cbMidiPort.getPreferredSize());
1176     p2.add(cbMidiPort);
1177    
1178     p2.add(Box.createRigidArea(new Dimension(3, 0)));
1179    
1180     o = cbMidiChannel.getRenderer();
1181     if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.CENTER);
1182    
1183     cbMidiChannel.addItem("All");
1184     for(int i = 1; i <= 16; i++) cbMidiChannel.addItem("Channel " + String.valueOf(i));
1185     cbMidiChannel.setPreferredSize(new Dimension(80, 18));
1186     cbMidiChannel.setMinimumSize(cbMidiChannel.getPreferredSize());
1187     cbMidiChannel.setMaximumSize(cbMidiChannel.getPreferredSize());
1188    
1189     p2.add(cbMidiChannel);
1190     p2.setAlignmentX(LEFT_ALIGNMENT);
1191 iliev 1285 p2.setOpaque(false);
1192 iliev 912 p.add(p2);
1193 iliev 1285 p.setBackground(new java.awt.Color(0x818181));
1194 iliev 912
1195 iliev 1285 bgp.add(p);
1196 iliev 912
1197 iliev 1285 bgp.add(Box.createRigidArea(new Dimension(4, 0)));
1198 iliev 912
1199     p = new JPanel();
1200     p.setOpaque(true);
1201     p.setBorder(BorderFactory.createEmptyBorder(3, 4, 3, 4));
1202     p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
1203 iliev 1285 l = new JLabel(Res.gfxInstrumentMapTitle);
1204 iliev 912 l.setAlignmentX(LEFT_ALIGNMENT);
1205     l.setAlignmentX(LEFT_ALIGNMENT);
1206     p.add(l);
1207    
1208     p.add(Box.createRigidArea(new Dimension(0, 3)));
1209    
1210 iliev 1285 //o = cbInstrumentMap.getRenderer();
1211     //if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.CENTER);
1212 iliev 912
1213 iliev 1285 cbInstrumentMap.setPreferredSize(new Dimension(126, 18));
1214     cbInstrumentMap.setMinimumSize(cbInstrumentMap.getPreferredSize());
1215     cbInstrumentMap.setMaximumSize(cbInstrumentMap.getPreferredSize());
1216     cbInstrumentMap.setAlignmentX(LEFT_ALIGNMENT);
1217     p.add(cbInstrumentMap);
1218     p.setBackground(new java.awt.Color(0x818181));
1219     bgp.add(p);
1220 iliev 912
1221 iliev 1285 bgp.add(Box.createRigidArea(new Dimension(4, 0)));
1222 iliev 912
1223     p = new JPanel();
1224     p.setOpaque(true);
1225     p.setBorder(BorderFactory.createEmptyBorder(3, 4, 3, 4));
1226     p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
1227 iliev 1285 l = new JLabel(Res.gfxAudioOutputTitle);
1228 iliev 912 l.setAlignmentX(LEFT_ALIGNMENT);
1229     p.add(l);
1230    
1231 iliev 1285 //p.add(Box.createRigidArea(new Dimension(0, 3)));
1232 iliev 912
1233 iliev 1285 p2 = new JPanel();
1234     p2.setBorder(BorderFactory.createEmptyBorder(3, 0, 0, 0));
1235     p2.setLayout(new BoxLayout(p2, BoxLayout.X_AXIS));
1236     p2.setOpaque(false);
1237     p2.setAlignmentX(LEFT_ALIGNMENT);
1238    
1239 iliev 912 o = cbAudioDevice.getRenderer();
1240     if(o instanceof JLabel) ((JLabel )o).setHorizontalAlignment(SwingConstants.RIGHT);
1241    
1242 iliev 1285 cbAudioDevice.setPreferredSize(new Dimension(40, 18));
1243 iliev 912 cbAudioDevice.setMinimumSize(cbAudioDevice.getPreferredSize());
1244     cbAudioDevice.setMaximumSize(cbAudioDevice.getPreferredSize());
1245    
1246 iliev 1285 p2.add(cbAudioDevice);
1247     p2.add(Box.createRigidArea(new Dimension(3, 0)));
1248     btnChannelRouting = new PixmapButton(Res.gfxBtnCr, Res.gfxBtnCrRO);
1249     btnChannelRouting.setPressedIcon(Res.gfxBtnCrRO);
1250     btnChannelRouting.setEnabled(false);
1251     btnChannelRouting.setToolTipText(i18n.getLabel("ChannelOptions.routing"));
1252 iliev 912
1253 iliev 1285 btnChannelRouting.addActionListener(new ActionListener() {
1254     public void
1255     actionPerformed(ActionEvent e) {
1256     SamplerChannel c = channel.getChannelInfo();
1257     new JSChannelOutputRoutingDlg(CC.getMainFrame(), c).setVisible(true);
1258    
1259     }
1260     });
1261    
1262     p2.add(btnChannelRouting);
1263    
1264     p.add(p2);
1265     p.setBackground(new java.awt.Color(0x818181));
1266     p2 = new JPanel();
1267     p2.setLayout(new java.awt.BorderLayout());
1268     p.add(p2);
1269     bgp.add(p);
1270    
1271     setContentPane(bgp);
1272    
1273 iliev 912 cbMidiDevice.addActionListener(new ActionListener() {
1274     public void
1275     actionPerformed(ActionEvent e) { setMidiDevice(); }
1276     });
1277    
1278     cbMidiPort.addActionListener(new ActionListener() {
1279     public void
1280     actionPerformed(ActionEvent e) { setMidiPort(); }
1281     });
1282    
1283     cbMidiChannel.addActionListener(new ActionListener() {
1284     public void
1285     actionPerformed(ActionEvent e) { setMidiChannel(); }
1286     });
1287    
1288 iliev 1285 samplerListener = new SamplerAdapter() {
1289     /** Invoked when the default MIDI instrument map is changed. */
1290 iliev 912 public void
1291 iliev 1285 defaultMapChanged(SamplerEvent e) {
1292     updateCbInstrumentMapToolTipText();
1293    
1294     }
1295     };
1296    
1297     CC.getSamplerModel().addSamplerListener(samplerListener);
1298    
1299     cbInstrumentMap.addItem(noMap);
1300     cbInstrumentMap.addItem(defaultMap);
1301     for(MidiInstrumentMap map : CC.getSamplerModel().getMidiInstrumentMaps()) {
1302     cbInstrumentMap.addItem(map);
1303     }
1304    
1305     int map = channel.getModel().getChannelInfo().getMidiInstrumentMapId();
1306     cbInstrumentMap.setSelectedItem(CC.getSamplerModel().getMidiInstrumentMapById(map));
1307     if(cbInstrumentMap.getSelectedItem() == null) {
1308     if(map == -1) cbInstrumentMap.setSelectedItem(noMap);
1309     else if(map == -2) {
1310     cbInstrumentMap.setSelectedItem(defaultMap);
1311     }
1312     }
1313    
1314     updateCbInstrumentMapToolTipText();
1315    
1316     if(channel.getModel().getChannelInfo().getEngine() == null) {
1317     cbInstrumentMap.setEnabled(false);
1318     }
1319    
1320     cbInstrumentMap.addActionListener(new ActionListener() {
1321     public void
1322     actionPerformed(ActionEvent e) { updateInstrumentMap(); }
1323 iliev 912 });
1324    
1325 iliev 1285 CC.getSamplerModel().addMidiInstrumentMapListListener(mapListListener);
1326    
1327 iliev 912 cbAudioDevice.addActionListener(new ActionListener() {
1328     public void
1329 iliev 1143 actionPerformed(ActionEvent e) { setBackendAudioDevice(); }
1330 iliev 912 });
1331    
1332     channel.getModel().addSamplerChannelListener(new SamplerChannelAdapter() {
1333     public void
1334     channelChanged(SamplerChannelEvent e) { updateChannelProperties(); }
1335     });
1336    
1337     CC.getSamplerModel().addMidiDeviceListListener(getHandler());
1338     CC.getSamplerModel().addAudioDeviceListListener(getHandler());
1339    
1340     updateMidiDevices();
1341     updateAudioDevices();
1342     updateChannelProperties();
1343     }
1344    
1345     /**
1346     * Updates the channel settings. This method is invoked when changes to the
1347     * channel were made.
1348     */
1349     private void
1350     updateChannelProperties() {
1351     SamplerModel sm = CC.getSamplerModel();
1352     SamplerChannel sc = channel.getModel().getChannelInfo();
1353    
1354 iliev 1204 MidiDeviceModel mm = sm.getMidiDeviceById(sc.getMidiInputDevice());
1355     AudioDeviceModel am = sm.getAudioDeviceById(sc.getAudioOutputDevice());
1356 iliev 912
1357     if(isUpdate()) CC.getLogger().warning("Unexpected update state!");
1358    
1359     setUpdate(true);
1360    
1361     try {
1362     cbMidiDevice.setSelectedItem(mm == null ? null : mm.getDeviceInfo());
1363    
1364     cbAudioDevice.setSelectedItem(am == null ? null : am.getDeviceInfo());
1365 iliev 1285 btnChannelRouting.setEnabled(am != null);
1366 iliev 912 } catch(Exception x) {
1367     CC.getLogger().log(Level.WARNING, "Unkown error", x);
1368     }
1369    
1370 iliev 1285 if(sc.getEngine() != null) {
1371     cbInstrumentMap.setEnabled(true);
1372     int id = sc.getMidiInstrumentMapId();
1373     Object o;
1374     if(id == -2) o = defaultMap;
1375     else if(id == -1) o = noMap;
1376     else o = CC.getSamplerModel().getMidiInstrumentMapById(id);
1377    
1378     if(cbInstrumentMap.getSelectedItem() != o) {
1379     cbInstrumentMap.setSelectedItem(o);
1380     }
1381     } else {
1382     cbInstrumentMap.setSelectedItem(noMap);
1383     cbInstrumentMap.setEnabled(false);
1384     }
1385    
1386 iliev 912 setUpdate(false);
1387     }
1388    
1389     /**
1390     * Updates the MIDI device list.
1391     */
1392     private void
1393     updateMidiDevices() {
1394     SamplerModel sm = CC.getSamplerModel();
1395     SamplerChannel sc = channel.getModel().getChannelInfo();
1396    
1397     setUpdate(true);
1398    
1399     try {
1400     cbMidiDevice.removeAllItems();
1401    
1402 iliev 1204 for(MidiDeviceModel m : sm.getMidiDevices())
1403 iliev 912 cbMidiDevice.addItem(m.getDeviceInfo());
1404    
1405 iliev 1204 MidiDeviceModel mm = sm.getMidiDeviceById(sc.getMidiInputDevice());
1406 iliev 912 cbMidiDevice.setSelectedItem(mm == null ? null : mm.getDeviceInfo());
1407     } catch(Exception x) {
1408     CC.getLogger().log(Level.WARNING, "Unkown error", x);
1409     }
1410    
1411     setUpdate(false);
1412     }
1413    
1414 iliev 1285
1415     private void
1416     updateInstrumentMap() {
1417     updateCbInstrumentMapToolTipText();
1418    
1419     int id = channel.getModel().getChannelInfo().getMidiInstrumentMapId();
1420     Object o = cbInstrumentMap.getSelectedItem();
1421     if(o == null && id == -1) return;
1422    
1423     int cbId;
1424     if(o == null || o == noMap) cbId = -1;
1425     else if(o == defaultMap) cbId = -2;
1426     else cbId = ((MidiInstrumentMap)o).getMapId();
1427    
1428     if(cbId == id) return;
1429    
1430     channel.getModel().setBackendMidiInstrumentMap(cbId);
1431     }
1432    
1433     private void
1434     updateCbInstrumentMapToolTipText() {
1435     if(cbInstrumentMap.getSelectedItem() != defaultMap) {
1436     cbInstrumentMap.setToolTipText(null);
1437     return;
1438     }
1439    
1440     MidiInstrumentMap m = CC.getSamplerModel().getDefaultMidiInstrumentMap();
1441     if(m != null) {
1442     String s = i18n.getLabel("Channel.ttDefault", m.getName());
1443     cbInstrumentMap.setToolTipText(s);
1444     } else {
1445     cbInstrumentMap.setToolTipText(null);
1446     }
1447     }
1448    
1449 iliev 912 /**
1450     * Updates the audio device list.
1451     */
1452     private void
1453     updateAudioDevices() {
1454     SamplerModel sm = CC.getSamplerModel();
1455     SamplerChannel sc = channel.getModel().getChannelInfo();
1456    
1457     setUpdate(true);
1458    
1459     try {
1460     cbAudioDevice.removeAllItems();
1461    
1462 iliev 1204 for(AudioDeviceModel m : sm.getAudioDevices())
1463 iliev 912 cbAudioDevice.addItem(m.getDeviceInfo());
1464    
1465 iliev 1204 AudioDeviceModel am = sm.getAudioDeviceById(sc.getAudioOutputDevice());
1466 iliev 912 cbAudioDevice.setSelectedItem(am == null ? null : am.getDeviceInfo());
1467     } catch(Exception x) {
1468     CC.getLogger().log(Level.WARNING, "Unkown error", x);
1469     }
1470    
1471     setUpdate(false);
1472     }
1473    
1474     private void
1475     setMidiDevice() {
1476     MidiInputDevice mid = (MidiInputDevice)cbMidiDevice.getSelectedItem();
1477    
1478     if(!isUpdate()) {
1479 iliev 1143 if(mid != null) {
1480     channel.getModel().setBackendMidiInputDevice(mid.getDeviceId());
1481     }
1482    
1483 iliev 912 return;
1484     }
1485    
1486 iliev 1285 if(midiDevice != null) midiDevice.removeMidiDeviceListener(getHandler());
1487    
1488 iliev 912 cbMidiPort.removeAllItems();
1489    
1490     if(mid == null) {
1491 iliev 1285 midiDevice = null;
1492 iliev 912 cbMidiPort.setEnabled(false);
1493    
1494     cbMidiChannel.setSelectedItem(null);
1495     cbMidiChannel.setEnabled(false);
1496     } else {
1497 iliev 1285 midiDevice = CC.getSamplerModel().getMidiDeviceById(mid.getDeviceId());
1498     if(midiDevice != null) midiDevice.addMidiDeviceListener(getHandler());
1499    
1500 iliev 912 cbMidiPort.setEnabled(true);
1501    
1502     MidiPort[] ports = mid.getMidiPorts();
1503     for(MidiPort port : ports) cbMidiPort.addItem(port);
1504    
1505     int p = channel.getModel().getChannelInfo().getMidiInputPort();
1506     cbMidiPort.setSelectedItem(p >= 0 && p < ports.length ? ports[p] : null);
1507    
1508     cbMidiChannel.setEnabled(true);
1509     int c = channel.getModel().getChannelInfo().getMidiInputChannel();
1510     cbMidiChannel.setSelectedItem(c == -1 ? "All" : "Channel " + (c + 1));
1511     }
1512     }
1513    
1514     private void
1515     setMidiPort() {
1516     if(isUpdate()) return;
1517    
1518 iliev 1143 channel.getModel().setBackendMidiInputPort(cbMidiPort.getSelectedIndex());
1519 iliev 912 }
1520    
1521     private void
1522     setMidiChannel() {
1523     if(isUpdate()) return;
1524    
1525     Object o = cbMidiChannel.getSelectedItem();
1526     if(o == null) return;
1527     String s = o.toString();
1528    
1529     int c = s.equals("All") ? -1 : Integer.parseInt(s.substring(8)) - 1;
1530    
1531 iliev 1143 channel.getModel().setBackendMidiInputChannel(c);
1532 iliev 912 }
1533    
1534     private void
1535 iliev 1143 setBackendAudioDevice() {
1536 iliev 912 if(isUpdate()) return;
1537     AudioOutputDevice dev = (AudioOutputDevice)cbAudioDevice.getSelectedItem();
1538 iliev 1143 if(dev != null) channel.getModel().setBackendAudioOutputDevice(dev.getDeviceId());
1539 iliev 912 }
1540    
1541     /**
1542     * Determines whether the currently processed changes are due to update.
1543     * @return <code>true</code> if the currently processed changes are due to update and
1544     * <code>false</code> if the currently processed changes are due to user input.
1545     */
1546     private boolean
1547     isUpdate() { return update; }
1548    
1549     /**
1550     * Sets whether the currently processed changes are due to update.
1551     * @param b Specify <code>true</code> to indicate that the currently
1552     * processed changes are due to update; <code>false</code>
1553     * indicates that the currently processed changes are due to user input.
1554     */
1555     private void
1556     setUpdate(boolean b) { update = b; }
1557    
1558 iliev 1341 protected void
1559     onDestroy() {
1560     SamplerModel sm = CC.getSamplerModel();
1561    
1562     sm.removeMidiDeviceListListener(getHandler());
1563     sm.removeAudioDeviceListListener(getHandler());
1564     sm.removeMidiInstrumentMapListListener(mapListListener);
1565     sm.removeSamplerListener(samplerListener);
1566    
1567     if(midiDevice != null) {
1568     midiDevice.removeMidiDeviceListener(getHandler());
1569     }
1570     }
1571    
1572 iliev 912 private final Handler handler = new Handler();
1573    
1574     private Handler
1575     getHandler() { return handler; }
1576    
1577 iliev 1285 private class Handler implements MidiDeviceListListener, ListListener<AudioDeviceModel>,
1578 iliev 1341 MidiDeviceListener {
1579 iliev 912 /**
1580     * Invoked when a new MIDI device is created.
1581     * @param e A <code>MidiDeviceListEvent</code>
1582     * instance providing the event information.
1583     */
1584     public void
1585     deviceAdded(MidiDeviceListEvent e) {
1586     cbMidiDevice.addItem(e.getMidiDeviceModel().getDeviceInfo());
1587     }
1588    
1589     /**
1590     * Invoked when a MIDI device is removed.
1591     * @param e A <code>MidiDeviceListEvent</code>
1592     * instance providing the event information.
1593     */
1594     public void
1595     deviceRemoved(MidiDeviceListEvent e) {
1596     cbMidiDevice.removeItem(e.getMidiDeviceModel().getDeviceInfo());
1597     }
1598    
1599     /**
1600     * Invoked when a new audio device is created.
1601     * @param e An <code>AudioDeviceListEvent</code>
1602     * instance providing the event information.
1603     */
1604     public void
1605 iliev 1143 entryAdded(ListEvent<AudioDeviceModel> e) {
1606     cbAudioDevice.addItem(e.getEntry().getDeviceInfo());
1607 iliev 912 }
1608    
1609     /**
1610     * Invoked when an audio device is removed.
1611     * @param e An <code>AudioDeviceListEvent</code>
1612     * instance providing the event information.
1613     */
1614     public void
1615 iliev 1143 entryRemoved(ListEvent<AudioDeviceModel> e) {
1616     cbAudioDevice.removeItem(e.getEntry().getDeviceInfo());
1617 iliev 912 }
1618 iliev 1285
1619     public void
1620     settingsChanged(MidiDeviceEvent e) {
1621     if(isUpdate()) {
1622     CC.getLogger().warning("Invalid update state");
1623     return;
1624     }
1625    
1626     setUpdate(true);
1627     int idx = cbMidiPort.getSelectedIndex();
1628     MidiInputDevice d = e.getMidiDeviceModel().getDeviceInfo();
1629    
1630     cbMidiPort.removeAllItems();
1631     for(MidiPort port : d.getMidiPorts()) cbMidiPort.addItem(port);
1632    
1633     if(idx >= cbMidiPort.getModel().getSize()) idx = 0;
1634    
1635     setUpdate(false);
1636    
1637     if(cbMidiPort.getModel().getSize() > 0) cbMidiPort.setSelectedIndex(idx);
1638     }
1639 iliev 912 }
1640 iliev 1285
1641     private class MapListListener implements ListListener<MidiInstrumentMap> {
1642     /** Invoked when a new MIDI instrument map is added to a list. */
1643     public void
1644     entryAdded(ListEvent<MidiInstrumentMap> e) {
1645     cbInstrumentMap.insertItemAt(e.getEntry(), cbInstrumentMap.getItemCount());
1646     boolean b = channel.getModel().getChannelInfo().getEngine() != null;
1647     if(b && !cbInstrumentMap.isEnabled()) cbInstrumentMap.setEnabled(true);
1648     }
1649    
1650     /** Invoked when a new MIDI instrument map is removed from a list. */
1651     public void
1652     entryRemoved(ListEvent<MidiInstrumentMap> e) {
1653     cbInstrumentMap.removeItem(e.getEntry());
1654     if(cbInstrumentMap.getItemCount() == 0) { // TODO: ?
1655     cbInstrumentMap.setSelectedItem(noMap);
1656     cbInstrumentMap.setEnabled(false);
1657     }
1658     }
1659     }
1660 iliev 912 }

  ViewVC Help
Powered by ViewVC