view src/uk/ac/qmul/eecs/depic/daw/gui/MainFrame.java @ 2:c0412c81d274

Added documentation
author Fiore Martin <f.martin@qmul.ac.uk>
date Thu, 18 Feb 2016 18:35:26 +0000
parents 3074a84ef81e
children
line wrap: on
line source
/*  
 Cross-Modal DAW Prototype - Prototype of a simple Cross-Modal Digital Audio Workstation.

 Copyright (C) 2015  Queen Mary University of London (http://depic.eecs.qmul.ac.uk/)
	
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package uk.ac.qmul.eecs.depic.daw.gui;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;

import javax.swing.Action;
import javax.swing.Box;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.UnsupportedLookAndFeelException;

import uk.ac.qmul.eecs.depic.daw.Daw;
import uk.ac.qmul.eecs.depic.daw.gui.actions.Actions;

/**
 * 
 * The main frame of this program.
 *
 */
public class MainFrame extends JFrame {
	private static final long serialVersionUID = 1L;
	private Actions actions;
	private ArrangeWindow arrangeWindow;
	private JToolBar transportBar;

	public MainFrame(){	
		super("Cross-Modal DAW Prototype");
		/* makes the overwritten getContentPane() correct */
		setContentPane(new JPanel());

		/* try and set system look and feel */

		try {
			for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
		        if ("Nimbus".equals(info.getName())) {
		            UIManager.setLookAndFeel(info.getClassName());
		            break;
		        }
		    }
		} catch (Exception e) {
			    // If Nimbus is not available, you can set the GUI to another look and feel.
			try {
				UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
				SwingUtilities.updateComponentTreeUI(this);
			} catch (ClassNotFoundException|InstantiationException|IllegalAccessException|UnsupportedLookAndFeelException e1) {
				// do nothing and stick with java look&feel
			} 
		}
		
		setDefaultCloseOperation(EXIT_ON_CLOSE); // FIXME make own close operation
		
		JPanel contentPane = (JPanel)getContentPane();
		contentPane.setLayout(new BorderLayout());
		
		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

		int screenWidth = (int)screenSize.getWidth();
		int screenHeight = (int)screenSize.getHeight();

		setLocation(screenWidth / 16, screenHeight / 16);
		contentPane.setPreferredSize(new Dimension(
				screenWidth * 5 / 8, screenHeight * 5 / 8));
		
		arrangeWindow = new ArrangeWindow();
		transportBar = new JToolBar(){
			private static final long serialVersionUID = 1L;

			@Override
			protected JButton createActionComponent(Action a){
				/* add the accessible name to the button using the action name */
				JButton b = super.createActionComponent(a);
				
				
				b.getAccessibleContext().setAccessibleName((String)a.getValue(Action.NAME));
				return b;
			}
		};
		contentPane.add(transportBar,BorderLayout.NORTH);
		/* arrange window scroll contains the tracks and the Track parameters. The * 
		 * scroll bar appears when the number of tracks exceeds the screen size  */
		JScrollPane arrangeWindowScroll = new JScrollPane(arrangeWindow);
		arrangeWindowScroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
		arrangeWindowScroll.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
		contentPane.add(arrangeWindowScroll,BorderLayout.CENTER);

		
		/* remove actions for scrolling left and right: the content of this scroll pane only * 
		 * grows in height when track are added. Moreover this actions conflict with the     *
		 * scrubbing through the audio track with right and left arrow keys                  */
		InputMap im = arrangeWindowScroll.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);  
		im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,0),"none");
		im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT,0),"none");
		
		
		getArrangeWindow().addTrack(new AudioTrack(Daw.getSoundEngineFactory().createSoundWave()));
		
		actions = new Actions(this);
		initMenu(actions);
		initTransportBar(actions);
		initScrubActions();
	}
	
	protected void initMenu(Actions actions){
		JMenuBar menuBar = new JMenuBar();
		this.setJMenuBar(menuBar);
		
		/* -- File Menu -- */
		JMenu fileMenu = new JMenu(actions.getVoidAction("file"));
		menuBar.add(fileMenu);
		
		fileMenu.add( new JMenuItem(actions.open()));
		fileMenu.add(new JMenuItem(actions.close()));
		fileMenu.addSeparator();
		
		fileMenu.add(new JMenuItem(actions.properties()));
		
		fileMenu.addSeparator();
		fileMenu.add(new JMenuItem(actions.exit()));
		
		
		/* -- Edit Menu -- */ 
		JMenu editMenu = new JMenu(actions.getVoidAction("edit"));
		menuBar.add(editMenu);
		
		editMenu.add(new JMenuItem(actions.cut()));
		editMenu.add(new JMenuItem(actions.copy()));
		editMenu.add(new JMenuItem(actions.paste()));
		editMenu.add(new JMenuItem(actions.insert()));
		
		/* -- View Menu -- */
		JMenu viewMenu = new JMenu(actions.getVoidAction("view"));
		menuBar.add(viewMenu);
		
		viewMenu.add(new JMenuItem(actions.zoomIn()));
		viewMenu.add(new JMenuItem(actions.zoomOut()));
		viewMenu.add(new JMenuItem(actions.showDb()));
		viewMenu.add(new JMenuItem(actions.generatePeaks()));
		viewMenu.add(new JMenuItem(actions.findNextPoint()));
		viewMenu.add(new JMenuItem(actions.findPreviousPoint()));
		
		/* -- Track Menu --*/
		JMenu trackMenu = new JMenu(actions.getVoidAction("track"));
		menuBar.add(trackMenu);
		
		trackMenu.add(new JMenuItem(actions.addTrack()));
		trackMenu.add(new JMenuItem(actions.removeSelection()));
		trackMenu.add(new JMenuItem(actions.switchAutomation()));
		
		/* -- Haptics Menu -- */
		JMenu hapticsMenu = new JMenu(actions.getVoidAction("haptics"));
		menuBar.add(hapticsMenu);
		
		hapticsMenu.add(new JMenuItem(actions.startPhantom()));
		hapticsMenu.add(new JMenuItem(actions.showHaptics()));
		hapticsMenu.add(new JMenuItem(actions.toggleScrub()));
	}
	
	protected void initTransportBar(Actions actions){
		/* removes space as a trigger for JButtons when they are focused * 
		 * this way space can be used to play/stop the current track     */

		/* action for play/stop the current track */
		JComponent contentPane = (JComponent)getContentPane(); 
		contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, InputEvent.CTRL_DOWN_MASK), "play");
		contentPane.getActionMap().put("play", actions.play());
		contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, InputEvent.CTRL_DOWN_MASK), "rew");
		contentPane.getActionMap().put("rew", actions.rew());
		
		
		/* remove left and right arrow key from transport bar in order not to conflict with the cursor scrubbing  */
		transportBar.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "none");
		transportBar.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "none");
		transportBar.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "none");
		transportBar.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "none");
		
		/* set up transport bar buttons */
		JToggleButton playButton = new JToggleButton(actions.play());
		playButton.setHideActionText(true);
		playButton.getAccessibleContext().setAccessibleName((String)playButton.getAction().getValue(Action.NAME));
		/* add(Action a) creates a button with the specified action. it is overwritten *  
		 * in order to add a name to the accessible context - see constructor          */
		transportBar.add(playButton);
		transportBar.add(actions.stop());
		transportBar.add(actions.rew());
		transportBar.add(actions.forward());
		
		transportBar.add(Box.createRigidArea(new Dimension(20,0)));
		JToggleButton loopButton = new JToggleButton(actions.loop());
		loopButton.setHideActionText(true);
		loopButton.getAccessibleContext().setAccessibleName((String)loopButton.getAction().getValue(Action.NAME));
		
		transportBar.add(loopButton);
	}
	
	protected void initScrubActions(){
		JComponent contentPane = (JComponent)getContentPane(); 
		
		/* install the keystroke for left and right keys which will be mapperd respectively to scrub left and right */
		contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,0), "scrub forw");
		contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT,0), "scrub backw");
		contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_F4,0), "scrub play");
		contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_F4,0,true), "scrub release");
		

		/* install the keystrokes for stopping the scrub all the modifiers are installed as well to prevent           *
		 * a sequence of actions such as : [press right, press ctrl, release right, release ctrl] to leave the        *
		 * scrubbing on. This would happen because press right will have no modifiers, whereas release right          *
		 * would have ctrl modifier and it would not match a simple KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,0,true)  */
		for(int modifier : new int []{
				0, // no modifiers
				InputEvent.SHIFT_DOWN_MASK,
				InputEvent.SHIFT_DOWN_MASK | InputEvent.CTRL_DOWN_MASK, 
			    InputEvent.META_DOWN_MASK,
			    InputEvent.ALT_DOWN_MASK,
			    InputEvent.ALT_GRAPH_DOWN_MASK,
			    InputEvent.CTRL_DOWN_MASK}){
			contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT,modifier,true), "scrub release");			
			contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT,modifier,true), "scrub release");
		}		

		/* install the actions: scrub left - scrub right - stop scrub release - stop scrub right */
		contentPane.getActionMap().put("scrub backw",actions.scrubAction(Actions.ScrubType.SCRUB_BACKWARDS));
		contentPane.getActionMap().put("scrub forw",actions.scrubAction(Actions.ScrubType.SCRUB_FORWARDS));
		contentPane.getActionMap().put("scrub release" ,actions.scrubAction(Actions.ScrubType.STOP_SCRUB));
		contentPane.getActionMap().put("scrub play" ,actions.scrubAction(Actions.ScrubType.PLAY_SCRUB));
		
	}
	
	@Override
	public JPanel getContentPane(){
		return (JPanel)super.getContentPane();
	}
	
	public ArrangeWindow getArrangeWindow(){
		return arrangeWindow;
	}
	
	public JToolBar getTransportBar(){
		return transportBar;
	}
	
	public Actions getActions(){
		return actions;
	}

}