3 import java.awt.event.*;
6 * Graphical representation of a MIDI note.
8 * @author Andersson, Andreen, Lanneskog, Pehrson
12 public class MooNoteElement extends JPanel implements Comparable{
14 private MooTrackView mtv;
16 private JPopupMenu popup;
17 private JMenu popupTranspUp, popupTranspDown;
18 private JMenuItem popupRemove, popupProp;
19 private JMenuItem[] popupTranspUpItems, popupTranspDownItems;
20 private Rectangle pitchRect, veloRect;
21 private String notePitch, noteVelocity;
22 private boolean selected = false, leftMouseButtonPressed = false, mouseIn = false;
23 public Color textColor;
24 public static final Color bgColor = new Color(160, 218, 255);
25 public static final Color invBgColor = new Color(96, 38, 0);
28 * Creates a new note element.
29 * @param parent The MooTrackView that this element will be painted on.
30 * @param mn the note that will be graphically represented
32 public MooNoteElement (MooTrackView parent, MooNote mn) {
36 addMouseListener(new MAdapter());
37 setBorder(BorderFactory.createLineBorder(Color.black));
38 setBackground(bgColor);
39 textColor = Color.black;
41 // Defines coordinates.
42 pitchRect = new Rectangle(0, 0, 15, 10);
43 veloRect = new Rectangle(20, 0, 40, 10);
45 // Creates pop-up menu.
46 popup = new JPopupMenu();
47 popupProp = addMenuItem(popup, "Preferences...");
48 popupRemove = addMenuItem(popup, "Remove");
49 popupTranspUpItems = new JMenuItem[12];
50 popupTranspDownItems = new JMenuItem[12];
51 popupTranspUp = createTransposeMenu(popup, popupTranspUpItems, "note up");
52 popupTranspDown = createTransposeMenu(popup, popupTranspDownItems, "note down");
56 * Returns the note of this element.
59 public MooNote getNote() {
64 * Compares the note of this element to that of another note.
65 * @return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object
67 public int compareTo(Object o) {
68 return note.compareTo(((MooNoteElement)o).getNote());
72 * Selects the current NoteElement.
74 public void select() {
77 setBackground(invBgColor);
78 textColor = Color.white;
83 * Deselects the current NoteElement.
85 public void deselect() {
87 // mtv.deselectNote(this);
88 setBackground(bgColor);
89 textColor = Color.black;
94 * Transposes the current note element the given number of halftones.
95 * @param halftones the number of halftones to transpose - positive for up, negative for down
97 public void transpose(int halftones) {
98 note.transpose(halftones);
103 * Draws the string that shows the note's properties.
104 * @param g The Graphics object used to draw the strings.
106 public void paintComponent(Graphics g)
108 super.paintComponent(g);
109 if (!(g instanceof Graphics2D)) return;
110 Graphics2D g2 = (Graphics2D)g;
111 g2.setColor(textColor);
112 g2.setFont(new Font("Helvetica", Font.PLAIN, 8));
121 g2.drawString(notePitch, 1, 8);
122 g2.drawString("" + noteVelocity, 21, 8);
126 * Calculate what the string that shows the note properties should look like.
128 protected void calculateString(){
132 if(note == null) return;
134 int pitch = note.getPitch();
135 switch (pitch % 12) {
136 case 0: notePitch = "C"; break;
137 case 1: notePitch = "C#"; break;
138 case 2: notePitch = "D"; break;
139 case 3: notePitch = "D#"; break;
140 case 4: notePitch = "E"; break;
141 case 5: notePitch = "F"; break;
142 case 6: notePitch = "F#"; break;
143 case 7: notePitch = "G"; break;
144 case 8: notePitch = "G#"; break;
145 case 9: notePitch = "A"; break;
146 case 10: notePitch = "A#"; break;
147 case 11: notePitch = "B"; break;
149 notePitch += pitch / 12 - 1;
150 noteVelocity = ""+note.getVelocity();
155 * Asks the MooTrackView that the note element is painted on to remove this element and the note.
157 protected void remove(){
158 mtv.removeNote(this);
162 * Updates the graphical content of the element and repaints it.
164 public void update() {
170 * Layout this changed elemnt.
172 protected void newLayout(){
173 mtv.layoutElement(this,true);
177 * Adds a menu item with the given command to the given popup menu.
179 private JMenuItem addMenuItem(JPopupMenu menu, String command) {
180 JMenuItem item = new JMenuItem(command);
181 item.addActionListener(new PopupListener());
187 * Adds a menu item with the given command to the given menu.
189 private JMenuItem addMenuItem(JMenu menu, String command) {
190 JMenuItem item = new JMenuItem(command);
191 item.addActionListener(new PopupListener());
197 * Creates a transpose sub menu with the given title in the given popup menu,
198 * inserting the items into the given array.
200 private JMenu createTransposeMenu(JPopupMenu menu, JMenuItem[] items, String title) {
201 JMenu trans = new JMenu("Transpose " + title);
203 items[0] = addMenuItem(trans, "One octave");
204 for (int i = 1; i < 12; i++) {
205 items[i] = addMenuItem(trans, (i) + " halftones");
211 * Listener that checks the mouse actions on this element.
213 class MAdapter extends MouseAdapter {
216 * Plays the note on double-click.
218 public void mouseClicked(MouseEvent e) {
219 if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2)
220 Moosique.getReceiver().send(note.getMessage(), -1);
224 * Selects the note if mouse entered with the left mouse button pressed.
226 public void mouseEntered(MouseEvent e) {
228 if (mtv.isLeftMouseButtonPressed()) {
234 * Registers mouse exited.
236 public void mouseExited(MouseEvent e) {
238 Moosique.getReceiver().send(note.getNoteOffEvent().getMessage(), -1);
242 * Checks if the mouse is pressed.
243 * Increases the pitch or velocity if the right mouse button is pressed while holding CTRL.
244 * Decreases the pitch or velocity if the left mouse button is pressed while holding CTRL.
245 * @param e the event recieved.
247 public void mousePressed(MouseEvent e) {
248 if (e.isControlDown()) {
249 if (pitchRect.contains(e.getPoint())) {
250 if (SwingUtilities.isRightMouseButton(e)) {
252 } else if (SwingUtilities.isLeftMouseButton(e)) {
255 Moosique.setEdited();
258 } else if (veloRect.contains(e.getPoint())) {
259 if (SwingUtilities.isRightMouseButton(e)) {
260 note.setVelocity(note.getVelocity() + 1);
261 } else if (SwingUtilities.isLeftMouseButton(e)) {
262 note.setVelocity(note.getVelocity() - 1);
264 Moosique.setEdited();
274 public void mouseReleased(MouseEvent e) {
275 if (!maybeShowPopup(e) && !mouseIn) {
277 if (y < 0) mtv.maybeMoveSelectedNotes((int)Math.floor((double)y / MooTrackView.NOTE_HEIGHT) * MooTrackView.NOTE_HEIGHT);
278 if (y > getHeight()) mtv.maybeMoveSelectedNotes((int)Math.ceil(((double)y - getHeight()) / MooTrackView.NOTE_HEIGHT) * MooTrackView.NOTE_HEIGHT);
284 * Shows the menu if an OS-specific popup-trigger was activated.
286 private boolean maybeShowPopup(MouseEvent e) {
287 if (!e.isPopupTrigger()) return false;
288 if (!e.isControlDown()) {
289 if (!selected || mtv.isTheOnlySelected((MooNoteElement)e.getComponent())) popup.show(e.getComponent(), e.getX(), e.getY());
290 else mtv.showSelectionPopup(e.getComponent(), e.getX(), e.getY());
297 * Takes the appropriate action when a user selects an item on the popup menu.
299 class PopupListener implements ActionListener {
300 public void actionPerformed(ActionEvent e) {
301 Object source = e.getSource();
302 if (source == popupProp) {
303 System.out.println("Duration: " + note.getDuration());
305 System.out.println("Duration: " + note.getDuration());
308 } else if (source == popupRemove) {
310 } else if (source == popupTranspUpItems[0]) {
312 } else if (source == popupTranspDownItems[0]) {
315 for (int i = 1; i < 12; i++) {
316 if (source == popupTranspUpItems[i]) transpose(i);
317 else if (source == popupTranspDownItems[i]) transpose(-i);