]> ruin.nu Git - moosique.git/blob - MooNoteElement.java
no message
[moosique.git] / MooNoteElement.java
1 import javax.swing.*;
2 import java.awt.*;
3 import java.awt.event.*;
4
5 /**
6  * Graphical representation of a MIDI note.
7  * 
8  * @author  Andersson, Andreen, Lanneskog, Pehrson
9  * @version 1
10  */
11  
12 public class MooNoteElement extends JPanel implements Comparable{
13
14         private MooTrackView mtv;
15         private MooNote note;
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);
26
27         /** 
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
31          */
32         public MooNoteElement (MooTrackView parent, MooNote mn) {
33                 mtv = parent;
34                 note = mn;
35                 calculateString();
36                 addMouseListener(new MAdapter());
37                 setBorder(BorderFactory.createLineBorder(Color.black));
38                 setBackground(bgColor);
39                 textColor = Color.black;
40
41                 // Defines coordinates.
42                 pitchRect = new Rectangle(0, 0, 15, 10);
43                 veloRect = new Rectangle(20, 0, 40, 10);
44
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");
53         }
54
55         /** 
56          * Returns the note of this element.
57          * @return the note
58          */
59         public MooNote getNote() {
60                 return note;
61         }
62
63         /** 
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
66          */
67         public int compareTo(Object o) {
68                 return note.compareTo(((MooNoteElement)o).getNote());
69         }
70
71         /** 
72          * Selects the current NoteElement.
73          */
74         public void select() {
75                 selected = true;
76                 mtv.selectNote(this);
77                 setBackground(invBgColor);
78                 textColor = Color.white;
79                 repaint();
80         }
81
82         /** 
83          * Deselects the current NoteElement.
84          */
85         public void deselect() {
86                 selected = false;
87                 // mtv.deselectNote(this);
88                 setBackground(bgColor);
89                 textColor = Color.black;
90                 repaint();
91         }
92
93         /** 
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
96          */
97         public void transpose(int halftones) {
98                 note.transpose(halftones);
99                 update();
100         }
101
102         /**
103          * Draws the string that shows the note's properties.
104          * @param g     The Graphics object used to draw the strings.
105          */
106         public void paintComponent(Graphics g)
107         {
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));
113         /*
114                 switch(columns) {
115                         case 0:
116                         case 1:
117                         ...
118                 }
119         */
120                 
121                 g2.drawString(notePitch, 1, 8);
122                 g2.drawString("" + noteVelocity, 21, 8);
123         }
124
125         /**
126          * Calculate what the string that shows the note properties should look like.
127          */
128         protected void calculateString(){
129
130                 noteVelocity = ""; 
131                 notePitch = "";
132                 if(note == null) return;
133
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;
148                 }
149                 notePitch += pitch / 12 - 1;
150                 noteVelocity = ""+note.getVelocity();
151         }
152
153
154         /**
155          * Asks the MooTrackView that the note element is painted on to remove this element and the note.
156          */
157         protected void remove(){
158                 mtv.removeNote(this);
159         }
160
161         /**
162          * Updates the graphical content of the element and repaints it.
163          */
164         public void update() {
165                 calculateString();
166                 repaint();
167         }
168
169         /**
170          * Layout this changed elemnt.
171          */
172         protected void newLayout(){
173                 mtv.layoutElement(this,true);
174         }
175
176         /**
177          * Adds a menu item with the given command to the given popup menu.
178          */
179         private JMenuItem addMenuItem(JPopupMenu menu, String command) {
180                 JMenuItem item = new JMenuItem(command);
181                 item.addActionListener(new PopupListener());
182                 menu.add(item);
183                 return item;
184         }
185
186         /**
187          * Adds a menu item with the given command to the given menu.
188          */
189         private JMenuItem addMenuItem(JMenu menu, String command) {
190                 JMenuItem item = new JMenuItem(command);
191                 item.addActionListener(new PopupListener());
192                 menu.add(item);
193                 return item;
194         }
195
196         /**
197          * Creates a transpose sub menu with the given title in the given popup menu,
198          * inserting the items into the given array.
199          */
200         private JMenu createTransposeMenu(JPopupMenu menu, JMenuItem[] items, String title) {
201                 JMenu trans = new JMenu("Transpose " + title);
202                 menu.add(trans);
203                 items[0] = addMenuItem(trans, "One octave");
204                 for (int i = 1; i < 12; i++) {
205                         items[i] = addMenuItem(trans, (i) + " halftones");
206                 }
207                 return trans;
208         }
209
210         /**
211          * Listener that checks the mouse actions on this element.
212          */
213         class MAdapter extends MouseAdapter {
214         
215                 /**
216                  * Plays the note on double-click.
217                  */
218                 public void mouseClicked(MouseEvent e) {
219                         if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2)
220                                 Moosique.getReceiver().send(note.getMessage(), -1);
221                 }
222
223                 /**
224                  * Selects the note if mouse entered with the left mouse button pressed.
225                  */
226                 public void mouseEntered(MouseEvent e) {
227                         mouseIn = true;
228                         if (mtv.isLeftMouseButtonPressed()) {
229                                 select();
230                         }
231                 }
232
233                 /**
234                  * Registers mouse exited.
235                  */
236                 public void mouseExited(MouseEvent e) {
237                         mouseIn = false;
238                         Moosique.getReceiver().send(note.getNoteOffEvent().getMessage(), -1);
239                 }
240
241                 /**
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.
246                  */
247                 public void mousePressed(MouseEvent e) {
248                         if (e.isControlDown()) {
249                                 if (pitchRect.contains(e.getPoint())) {
250                                         if (SwingUtilities.isRightMouseButton(e)) {
251                                                 note.transpose(1);
252                                         } else if (SwingUtilities.isLeftMouseButton(e)) {
253                                                 note.transpose(-1);
254                                         }
255                                         Moosique.setEdited();
256                                         calculateString();
257                                         repaint();
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);
263                                         }
264                                         Moosique.setEdited();
265                                         calculateString();
266                                         repaint();
267                                 }
268                         } else {
269                                 select();
270                                 maybeShowPopup(e);
271                         }
272                 }
273
274                 public void mouseReleased(MouseEvent e) {
275                         if (!maybeShowPopup(e) && !mouseIn) {
276                                 int y = e.getY();
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);
279                                 
280                         }
281                 }
282
283                 /**
284                  * Shows the menu if an OS-specific popup-trigger was activated.
285                  */
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());
291                         }
292                         return true;
293                 }
294         }
295
296         /**
297          * Takes the appropriate action when a user selects an item on the popup menu.
298          */
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());
304                                 new MooDialog(note);
305                                 System.out.println("Duration: " + note.getDuration());
306                                 newLayout();
307                                 update();
308                         } else if (source == popupRemove) {
309                                 remove();
310                         } else if (source == popupTranspUpItems[0]) {
311                                 transpose(12);
312                         } else if (source == popupTranspDownItems[0]) {
313                                 transpose(-12);
314                         } else {
315                                 for (int i = 1; i < 12; i++) {
316                                         if (source == popupTranspUpItems[i]) transpose(i);
317                                         else if (source == popupTranspDownItems[i]) transpose(-i);
318                                 }
319                         }
320                 }
321         }
322 }