annotate src/uk/ac/qmul/eecs/depic/daw/gui/ArrangeWindow.java @ 4:473da40f3d39 tip

added html formatting to Daw/package-info.java
author Fiore Martin <f.martin@qmul.ac.uk>
date Thu, 25 Feb 2016 17:50:09 +0000
parents 3074a84ef81e
children
rev   line source
f@0 1 /*
f@0 2 Cross-Modal DAW Prototype - Prototype of a simple Cross-Modal Digital Audio Workstation.
f@0 3
f@0 4 Copyright (C) 2015 Queen Mary University of London (http://depic.eecs.qmul.ac.uk/)
f@0 5
f@0 6 This program is free software: you can redistribute it and/or modify
f@0 7 it under the terms of the GNU General Public License as published by
f@0 8 the Free Software Foundation, either version 3 of the License, or
f@0 9 (at your option) any later version.
f@0 10
f@0 11 This program is distributed in the hope that it will be useful,
f@0 12 but WITHOUT ANY WARRANTY; without even the implied warranty of
f@0 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
f@0 14 GNU General Public License for more details.
f@0 15
f@0 16 You should have received a copy of the GNU General Public License
f@0 17 along with this program. If not, see <http://www.gnu.org/licenses/>.
f@0 18 */
f@0 19 package uk.ac.qmul.eecs.depic.daw.gui;
f@0 20
f@0 21 import java.awt.BorderLayout;
f@0 22 import java.awt.Color;
f@0 23 import java.awt.Component;
f@0 24 import java.awt.Dimension;
f@0 25 import java.awt.event.KeyEvent;
f@0 26 import java.awt.event.MouseAdapter;
f@0 27 import java.awt.event.MouseEvent;
f@0 28 import java.beans.PropertyChangeEvent;
f@0 29 import java.beans.PropertyChangeListener;
f@0 30 import java.util.ArrayList;
f@0 31 import java.util.List;
f@0 32
f@0 33 import javax.swing.BorderFactory;
f@0 34 import javax.swing.Box;
f@0 35 import javax.swing.BoxLayout;
f@0 36 import javax.swing.JComponent;
f@0 37 import javax.swing.JPanel;
f@0 38 import javax.swing.JScrollPane;
f@0 39 import javax.swing.KeyStroke;
f@0 40 import javax.swing.border.Border;
f@0 41
f@0 42 import uk.ac.qmul.eecs.depic.daw.Selection;
f@0 43 import uk.ac.qmul.eecs.depic.daw.SoundWave;
f@0 44 import uk.ac.qmul.eecs.depic.daw.SoundWaveEvent;
f@0 45 import uk.ac.qmul.eecs.depic.daw.SoundWaveListener;
f@0 46
f@0 47 /**
f@0 48 *
f@0 49 * The panel containing the audio tracks.
f@0 50 *
f@0 51 * Tracks are arranged in a scrollable BoxLayout.
f@0 52 *
f@0 53 */
f@0 54 public class ArrangeWindow extends JPanel implements PropertyChangeListener, SoundWaveListener {
f@0 55 private static final long serialVersionUID = 1L;
f@0 56 public static final Color BACKGROUND_COLOR = new Color(226,226,226);
f@0 57 public static final int SPACE_BETWEEN_TRACKS = 5;
f@0 58 public static final Border BORDER_UNSELECTED = BorderFactory.createCompoundBorder(
f@0 59 BorderFactory.createEmptyBorder(1, 0, 1, 0), BorderFactory.createMatteBorder(1, 0, 1, 0, Color.GRAY));
f@0 60 public static final Border BORDER_SELECTED = BorderFactory.createCompoundBorder(
f@0 61 BorderFactory.createMatteBorder(1, 0, 1, 0, new Color(214, 193, 99)), BorderFactory.createMatteBorder(1, 0, 1, 0, Color.GRAY));
f@0 62
f@0 63
f@0 64 /* tracks panel contains the rule and audio tracks */
f@0 65 private JScrollPane tracksPanelScroll;
f@0 66 /* view of the trackPanelScroll and panel where all the audio tracks are places */
f@0 67 private JPanel tracksPanel;
f@0 68 /* left panel with AudioTrackParameters */
f@0 69 private JPanel parametersPanel;
f@0 70 private Rule rule;
f@0 71 private int currentTrackIndex;
f@0 72 private List<AudioTrack> tracks;
f@0 73 private List<AudioTrackParameters> audioTrackParameters;
f@0 74 private List<Component> spacesBetweenTracks;
f@0 75 private List<Component> spacesBetweenTrackParameters;
f@0 76 private MouseInteraction mouseInteraction;
f@0 77
f@0 78
f@0 79 public ArrangeWindow(){
f@0 80 tracks = new ArrayList<>();
f@0 81 audioTrackParameters = new ArrayList<>();
f@0 82 spacesBetweenTracks = new ArrayList<>();
f@0 83 spacesBetweenTrackParameters = new ArrayList<>();
f@0 84 mouseInteraction = new MouseInteraction();
f@0 85
f@0 86 setLayout(new BorderLayout());
f@0 87 setBackground(BACKGROUND_COLOR);
f@0 88
f@0 89 /* left panel: header (of the same height as rule) and parameters */
f@0 90 parametersPanel = new JPanel();
f@0 91 parametersPanel.setLayout(new BoxLayout(parametersPanel,BoxLayout.Y_AXIS));
f@0 92 parametersPanel.add(Box.createRigidArea(new Dimension(247,Rule.HEIGHT+3)));
f@0 93 parametersPanel.setBackground(BACKGROUND_COLOR);
f@0 94
f@0 95 add(parametersPanel,BorderLayout.WEST);
f@0 96
f@0 97 /* right panel: scrollable panel with rule and tracks as header*/
f@0 98 tracksPanel = new JPanel();
f@0 99 tracksPanel.setLayout(new BoxLayout(tracksPanel,BoxLayout.Y_AXIS));
f@0 100 tracksPanel.setBackground(BACKGROUND_COLOR);
f@0 101 rule = new Rule();
f@0 102 rule.setBackground(BACKGROUND_COLOR);
f@0 103
f@0 104
f@0 105 tracksPanelScroll = new JScrollPane(tracksPanel,
f@0 106 JScrollPane.VERTICAL_SCROLLBAR_NEVER,
f@0 107 JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
f@0 108
f@0 109 /* disable the scrolling via the left-right keys to let the cursor scrub handler
f@0 110 * take over when the track is focused */
f@0 111 tracksPanelScroll.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "none");
f@0 112 tracksPanelScroll.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "none");
f@0 113 /* setPreferredSize important, otherwise the view port gets resized to the track size *
f@0 114 * as soon as the window is resized and therefore the scroll bar disappear */
f@0 115 tracksPanelScroll.setPreferredSize(new Dimension(500,500));
f@0 116 /* rule is set as the header of the scroll pane with audio tracks */
f@0 117 tracksPanelScroll.setColumnHeaderView(rule);
f@0 118
f@0 119 add(tracksPanelScroll, BorderLayout.CENTER);
f@0 120
f@0 121 currentTrackIndex = -1;
f@0 122 }
f@0 123
f@0 124 /**
f@0 125 * Adds a track to this component. The added track is automatically set as the current track.
f@0 126 *
f@0 127 * Adding a track that's already in the arrange window will have no effect.
f@0 128 *
f@0 129 * @param track the new track to add. It must be a track that is not currently
f@0 130 * contained in this arrange window
f@0 131 */
f@0 132 public void addTrack(AudioTrack track){
f@0 133 if(tracks.contains(track))
f@0 134 return;
f@0 135
f@0 136 AudioTrackParameters trackParameters = new AudioTrackParameters(track,1);
f@0 137
f@0 138 /* install the mouse listener */
f@0 139 track.addMouseListener(mouseInteraction);
f@0 140 trackParameters.addMouseListener(mouseInteraction); // FIXME verify
f@0 141
f@0 142
f@0 143 /* add track and parameters in the respective lists */
f@0 144 tracks.add(track);
f@0 145 audioTrackParameters.add(trackParameters);
f@0 146 Component box1 = Box.createVerticalStrut(SPACE_BETWEEN_TRACKS);
f@0 147 Component box2 = Box.createVerticalStrut(SPACE_BETWEEN_TRACKS);
f@0 148 spacesBetweenTracks.add(box1);
f@0 149 spacesBetweenTrackParameters.add(box2);
f@0 150
f@0 151 /* add track and parameters in the respective panels */
f@0 152 parametersPanel.add(box1);
f@0 153 parametersPanel.add(trackParameters);
f@0 154 tracksPanel.add(box2);
f@0 155 tracksPanel.add(track);
f@0 156 /* set the new track as the current */
f@0 157 setCurrentTrack(getTracksCount()-1);
f@0 158
f@0 159 /* set the label. Users will count starting from 1 and not from 0 */
f@0 160 trackParameters.setLabel("new Track "+(getCurrentTrackIndex()+1));
f@0 161 repaint();
f@0 162 }
f@0 163
f@0 164 public AudioTrack getTrackAt(int index){
f@0 165 return tracks.get(index);
f@0 166 }
f@0 167
f@0 168 public AudioTrackParameters getTrackParametersAt(int index){
f@0 169 return audioTrackParameters.get(index);
f@0 170 }
f@0 171
f@0 172 /**
f@0 173 *
f@0 174 * @return the current track or {@code null} if there are no tracks
f@0 175 * in this arrange window
f@0 176 */
f@0 177 public AudioTrack getCurrentTrack(){
f@0 178 if(currentTrackIndex == -1)
f@0 179 return null;
f@0 180 return tracks.get(currentTrackIndex);
f@0 181 }
f@0 182
f@0 183 /**
f@0 184 * Sets the track at the specified index as current.
f@0 185 *
f@0 186 * @param index the index of the new current track
f@0 187 * @throws ArrayIndexOutOfBoundsException if {@code index} is lower than 0 or greater or equal to {@code getTracksCount()}
f@0 188 *
f@0 189 *
f@0 190 */
f@0 191 public void setCurrentTrack(int index){
f@0 192 /* removes this from the listeners of the previous current track */
f@0 193 if(currentTrackIndex != -1){
f@0 194 AudioTrack previousTrack = getTrackAt(currentTrackIndex);
f@0 195 previousTrack.removePropertyChangeListener(this);
f@0 196 previousTrack.getSoundWave().removeSoundWaveListener(this);
f@0 197 previousTrack.setBorder(BORDER_UNSELECTED);
f@0 198 audioTrackParameters.get(currentTrackIndex).setBorder(BORDER_UNSELECTED);
f@0 199 }
f@0 200 currentTrackIndex = index;
f@0 201
f@0 202 AudioTrack currentTrack = getTrackAt(currentTrackIndex);
f@0 203 /* install listeners in the new audio track */
f@0 204 currentTrack.addPropertyChangeListener(this);
f@0 205 currentTrack.getSoundWave().addSoundWaveListener(this);
f@0 206 /* set the borders */
f@0 207 currentTrack.setBorder(BORDER_SELECTED);
f@0 208 audioTrackParameters.get(currentTrackIndex).setBorder(BORDER_SELECTED);
f@0 209
f@0 210 rule.setAudioTrack(getTrackAt(currentTrackIndex));
f@0 211 }
f@0 212
f@0 213 /**
f@0 214 *
f@0 215 * @return the index of the currently selected track or {@code -1} if no track
f@0 216 * is open in the arrange window
f@0 217 */
f@0 218 public int getCurrentTrackIndex(){
f@0 219 return currentTrackIndex;
f@0 220 }
f@0 221
f@0 222 /**
f@0 223 * Returns the number of tracks in this arrange window.
f@0 224 *
f@0 225 * @return the number of tracks in this arrange window
f@0 226 */
f@0 227 public int getTracksCount(){
f@0 228 return tracks.size();
f@0 229 }
f@0 230
f@0 231 public Rule getRule(){
f@0 232 return rule;
f@0 233 }
f@0 234
f@0 235 /**
f@0 236 *
f@0 237 * On {@code SELECTION_CHANGED} event from the current audio track, updates the other
f@0 238 * tracks accordingly.
f@0 239 *
f@0 240 * This enforces a unique selection and cursor position over the whole arrange window
f@0 241 *
f@0 242 * @param evt the sound wave event
f@0 243 *
f@0 244 */
f@0 245 @Override
f@0 246 public void update(SoundWaveEvent evt) {
f@0 247
f@0 248 if(SoundWaveEvent.SCAN.equals(evt.getType())){
f@0 249 for(int i=0; i< getTracksCount(); i++){
f@0 250 SoundWave wave = getTrackAt(i).getSoundWave();
f@0 251 /* only change selection if it's not the one that triggered the event */
f@0 252 if(!wave.equals(evt.getSource())){
f@0 253 wave.scan((Integer)evt.getArgs());
f@0 254 }
f@0 255 }
f@0 256 }
f@0 257
f@0 258 if(SoundWaveEvent.POSITION_CHANGED.equals(evt.getType()) ){
f@0 259 for(AudioTrack track : tracks){
f@0 260 if(!track.getSoundWave().equals(evt.getSource())){
f@0 261 track.getSoundWave().setPosition((Integer)evt.getArgs());
f@0 262 }
f@0 263 }
f@0 264
f@0 265 /* this is called from the current audio track sound wave. The *
f@0 266 * selection is changed in the other audio tracks accordingly */
f@0 267 //SoundWave currentWave = evt.getSource();
f@0 268
f@0 269 // for(int i=0; i< getTracksCount(); i++){
f@0 270 // SoundWave wave = getTrackAt(i).getSoundWave();
f@0 271 // /* only change selection if it's not the one that triggered the event */
f@0 272 // if(!wave.equals(currentWave)){
f@0 273 // wave.setSelection((Selection)evt.getArgs());
f@0 274 // }
f@0 275 // }
f@0 276 }
f@0 277 }
f@0 278
f@0 279 private class MouseInteraction extends MouseAdapter {
f@0 280 @Override
f@0 281 public void mousePressed(MouseEvent e){
f@0 282 Component c = e.getComponent();
f@0 283 int index = tracks.lastIndexOf(c);
f@0 284
f@0 285 if(index == getCurrentTrackIndex()){
f@0 286 return;
f@0 287 }else if(index != -1){
f@0 288 setCurrentTrack(index);
f@0 289 return;
f@0 290 }
f@0 291
f@0 292 index = audioTrackParameters.lastIndexOf(c);
f@0 293 if(index == getCurrentTrackIndex()){
f@0 294 return;
f@0 295 }else if(index != -1){
f@0 296 setCurrentTrack(index);
f@0 297 return;
f@0 298 }
f@0 299
f@0 300 }
f@0 301 }
f@0 302
f@0 303 @Override
f@0 304 public void propertyChange(PropertyChangeEvent evt) {
f@0 305 switch(evt.getPropertyName()){
f@0 306 case "mouseDragSelection" : {
f@0 307 Selection selection = (Selection)evt.getNewValue();
f@0 308 for(AudioTrack track : tracks){
f@0 309 if(!track.equals(evt.getSource())){
f@0 310 track.trackInteraction.setMouseSelection(
f@0 311 selection.getStart(), selection.getEnd());
f@0 312 }
f@0 313 }
f@0 314 } break;
f@0 315 }
f@0 316 }
f@0 317
f@0 318
f@0 319
f@0 320 }