]> ruin.nu Git - moosique.git/blobdiff - MooTrackView.java
Fixed drag select in track view.
[moosique.git] / MooTrackView.java
index bac8cbc59fa4d8c75cd09c0078ac5be21a22a1ac..a591d374853bd246647f16dd0c087ce38f58e335 100644 (file)
@@ -17,11 +17,15 @@ public class MooTrackView extends JPanel {
        private MooTrackTitle title;
        private Rectangle box;
 
-       private JPopupMenu popup;
-       private JMenuItem popupAdd;
-       private ArrayList rects;
+       private JPopupMenu popup, selPopup;
+       private JMenu selPopupTranspUp, selPopupTranspDown;
+       private JMenuItem popupAdd, popupPaste;
+       private JMenuItem selPopupCopy, selPopupCut, selPopupRemove, selPopupTranspUpOct, selPopupTranspDownOct;
+
+       private ArrayList coords, selection, copyBuffer; 
        private Insets insets;
        private int ticksPerSixteenth, popupY = 0;
+       private boolean leftMouseButtonPressed = false;
        protected static int viewLength = 0;
        protected static int extraHeight = 0;
        public static final int NOTE_HEIGHT = 10, NOTE_WIDTH = 40, VIEW_WIDTH = 200;
@@ -35,7 +39,17 @@ public class MooTrackView extends JPanel {
                super(true);
                this.track = track;
                this.title = title;
+
+               // Creates instance variables
                insets = getInsets();
+               coords = new ArrayList(track.size() / 2);
+               selection = new ArrayList();
+               copyBuffer = new ArrayList();
+
+               // Creates temporary variables
+               MidiEvent note;
+               MooNoteElement elem;
+               extraHeight = Toolkit.getDefaultToolkit().getScreenSize().height - 150;
 
                // Configures panel
                setBackground(Color.white);
@@ -43,12 +57,6 @@ public class MooTrackView extends JPanel {
                setLayout(null);
                setPreferredSize(new Dimension(VIEW_WIDTH, 140 * NOTE_HEIGHT));
 
-               // Creates temporary variables
-               MidiEvent note;
-               MooNoteElement elem;
-               rects = new ArrayList(track.size() / 2);
-               extraHeight = Toolkit.getDefaultToolkit().getScreenSize().height - 150;
-
                // Places note elements
                for (int i = 0; i < track.size(); i++) {
                        note = track.get(i);
@@ -63,12 +71,37 @@ public class MooTrackView extends JPanel {
 
                }
 
-               // Creates pop-up menu.
+               // Creates panel pop-up menu.
                popup = new JPopupMenu();
                PopupListener pList = new PopupListener();
                popupAdd = new JMenuItem("Add note...");
                popupAdd.addActionListener(pList);
                popup.add(popupAdd);
+               popupPaste = new JMenuItem("Paste");
+               popupPaste.addActionListener(pList);
+               popup.add(popupPaste);
+
+               // Creates selection pop-up menu.
+               selPopup = new JPopupMenu();
+               selPopupCopy = new JMenuItem("Copy selection");
+               selPopupCopy.addActionListener(pList);
+               selPopup.add(selPopupCopy);
+               selPopupCut = new JMenuItem("Cut selection");
+               selPopupCut.addActionListener(pList);
+               selPopup.add(selPopupCut);
+               selPopupRemove = new JMenuItem("Remove selection");
+               selPopupRemove.addActionListener(pList);
+               selPopup.add(selPopupRemove);
+               selPopupTranspUp = new JMenu("Transpose selection up");
+               selPopup.add(selPopupTranspUp);
+               selPopupTranspUpOct = new JMenuItem("One octave");
+               selPopupTranspUpOct.addActionListener(pList);
+               selPopupTranspUp.add(selPopupTranspUpOct);
+               selPopupTranspDown = new JMenu("Transpose selection down");
+               selPopup.add(selPopupTranspDown);
+               selPopupTranspDownOct = new JMenuItem("One octave");
+               selPopupTranspDownOct.addActionListener(pList);
+               selPopupTranspDown.add(selPopupTranspDownOct);
 
                // Adds listeners for popup menu and keyboard synthesizer.
                addMouseListener(new MAdapter());
@@ -85,10 +118,10 @@ public class MooTrackView extends JPanel {
                Rectangle r = new Rectangle();
                if (old){
                        r = elem.getBounds(r);
-                       for (Iterator i = rects.iterator(); i.hasNext();){
+                       for (Iterator i = coords.iterator(); i.hasNext();){
                                Object ob = i.next();
                                if (r.equals(ob)){
-                                       rects.remove(ob);
+                                       coords.remove(ob);
                                        break;
                                }
                        }
@@ -109,11 +142,15 @@ public class MooTrackView extends JPanel {
                // Places the element in the appropriate place.
                while(isOccupied(r)) r.translate(NOTE_WIDTH, 0);
                elem.setBounds(r);
-               rects.add(r);
+               coords.add(r);
                if (viewLength < (y + height)){
                        viewLength = y + height;
                        if(old)setPreferredSize(new Dimension(VIEW_WIDTH, viewLength + extraHeight));
                }
+               if (old) {
+                       validate();
+                       repaint();
+               }
        }
 
        /** 
@@ -137,7 +174,7 @@ public class MooTrackView extends JPanel {
         * @return true if the position is occupied.
         */
        private boolean isOccupied(Rectangle r) {
-               Iterator it = rects.iterator();
+               Iterator it = coords.iterator();
                while (it.hasNext()) {
                        if(r.intersects((Rectangle)it.next())) return true;
                }
@@ -154,9 +191,20 @@ public class MooTrackView extends JPanel {
                add(elem);
                layoutElement(elem, false);
                setPreferredSize(new Dimension(VIEW_WIDTH, viewLength + extraHeight));
+               Moosique.setEdited();
+               validate();
                repaint();
        }
 
+       /**
+        * Adds a standard note to this track.
+        */
+       private void addStandardNote() {
+               int row = (popupY - insets.top) / NOTE_HEIGHT;
+               long timestamp = (long)(ticksPerSixteenth * row);
+               addNote(new MooNote(title.getChannel(), 60, 100, timestamp, Moosique.getSequence().getResolution() / 4));
+       }
+
        /** 
         * Removes the given note element from the view and its note from the current track.
         * @param elem  the note element to remove
@@ -164,17 +212,120 @@ public class MooTrackView extends JPanel {
        public void removeNote(MooNoteElement elem) {
                elem.getNote().removeFrom(track);
                remove(elem);
-               elem.getNote().removeFrom(track);
+               Rectangle r = new Rectangle();
+               r = elem.getBounds(r);
+               coords.remove(r);
+               Moosique.setEdited();
+               validate();
                repaint();
        }
 
        /**
-        * Adds a standard note to this track.
+        * Selects the given note
+        * @param the note to select
         */
-       private void addStandardNote() {
-               int row =  (popupY - insets.top) / NOTE_HEIGHT;
+       public void selectNote(MooNoteElement elem) {
+               selection.add(elem);
+       }
+
+       /**
+        * Deselects the given note
+        * @param the note to deselect
+        */
+       public void deselectNote(MooNoteElement elem) {
+               selection.remove(selection.indexOf(elem));
+       }
+
+       /**
+        * Deselects all notes.
+        */
+       public void deselectAllNotes() {
+               Iterator it = selection.iterator();
+               while(it.hasNext()) {
+                       ((MooNoteElement)it.next()).deselect();
+               }
+               selection.clear();
+       }
+
+       /**
+        * Determines if the given MooNoteElement is the only one in the track view that is selected.
+        * @return if the given element is the only selected one
+        */
+       public boolean isTheOnlySelected(MooNoteElement elem) {
+               Iterator it = selection.iterator();
+               while(it.hasNext()) {
+                       if (!it.next().equals(elem)) return false;
+               }
+               return true;
+       }
+
+       /**
+        * Copies the current selection.
+        */
+       public void copySelectedNotes() {
+               copyBuffer = new ArrayList(selection.size());
+               Iterator it = selection.iterator();
+               while(it.hasNext()) {
+                       copyBuffer.add(((MooNoteElement)it.next()).getNote().clone());
+               }
+               Collections.sort(copyBuffer, new Moosique.NoteComparator());
+       }
+
+       /**
+        * Cuts the current selection.
+        */
+       public void cutSelectedNotes() {
+               copySelectedNotes();
+               removeSelectedNotes();
+       }
+
+       /**
+        * Pastes the current copy buffer at the given timestamp.
+        */
+       public void pasteCopiedNotes() {
+               int row = (popupY - insets.top) / NOTE_HEIGHT;
                long timestamp = (long)(ticksPerSixteenth * row);
-               addNote(new MooNote(title.getChannel(), 60, 100, timestamp, Moosique.getSequence().getResolution() / 4));
+               if (copyBuffer.size() > 0) {
+                       long startTime = ((MooNote)copyBuffer.get(0)).getTick();
+                       Iterator it = copyBuffer.iterator();
+                       while(it.hasNext()) {
+                               MooNote mn = (MooNote)((MooNote)it.next()).clone();
+                               mn.setTick(mn.getTick() - startTime + timestamp);
+                               addNote(mn);
+                       }
+               }
+       }
+
+       /**
+        * Removes the current selection.
+        */
+       public void removeSelectedNotes() {
+               Iterator it = selection.iterator();
+               while(it.hasNext()) {
+                       removeNote((MooNoteElement)it.next());
+               }
+               selection.clear();
+       }
+
+       /**
+        * Transposes all selected notes the given number of halftones.
+        */
+       private void transposeSelectedNotes(int halftones) {
+               Iterator it = selection.iterator();
+               while(it.hasNext()) {
+                       MooNoteElement elem = (MooNoteElement)it.next();
+                       elem.transpose(halftones);
+               }
+       }
+
+       /**
+        * Shows a popup-menu with options for the current selection of note elements.
+        * @param c     the component over which to display the menu
+        * @param x     the x-coordinate in which to display the menu
+        * @param y     the y-coordinate in which to display the menu
+        */
+       public void showSelectionPopup(Component c, int x, int y) {
+               selPopup.show(c, x, y);
        }
 
        /**
@@ -193,29 +344,49 @@ public class MooTrackView extends JPanel {
                }
        }
        
+       /**
+        * Returns whether the left mouse button is currently pressed or not.
+        * @return true if the left mosue button is currently pressed
+        */
+       public boolean isLeftMouseButtonPressed() {
+               return leftMouseButtonPressed;
+       }
+
        /**
         * The adapter used to listen on mouse actions
         */
        class MAdapter extends MouseAdapter {
 
                /**
-                * Adds a standard note if doubleclicked.
+                * Deselects all note on click, adds a standard note on double click.
                 */
                public void mouseClicked(MouseEvent e) {
-                       if (e.getClickCount() == 2) {
-                               popupY = e.getY();
-                               addStandardNote();
+                       if (SwingUtilities.isLeftMouseButton(e)) {
+                               deselectAllNotes();
+                               if (e.getClickCount() == 2) {
+                                       popupY = e.getY();
+                                       addStandardNote();
+                               }
                        }
                }
        
                public void mousePressed(MouseEvent e) {
+                       if (SwingUtilities.isLeftMouseButton(e)) leftMouseButtonPressed = true;
                        maybeShowPopup(e);
                }
 
                public void mouseReleased(MouseEvent e) {
+                       if (SwingUtilities.isLeftMouseButton(e)) leftMouseButtonPressed = false;
                        maybeShowPopup(e);
                }
 
+               /**
+                * Selects the notes within the area that was selected.
+                */
+               public void mouseDragged(MouseEvent e) {
+                       
+               }
+
                /**
                 * Shows the menu if an OS-specific popup-trigger was activated.
                 */
@@ -230,21 +401,34 @@ public class MooTrackView extends JPanel {
                 * Grabs the focus when the mouse has entered.
                 */
                public void mouseEntered(MouseEvent e) {
-                       // Moosique.setActiveChannel(track.getChannel());
+                       Moosique.setActiveChannel(title.getChannel());
                        grabFocus();
                }
        }
 
        /**
-        * Listens on actions on the popupmenu and executes the appropriate action.
+        * Listens on actions on the popup menu and executes the appropriate action.
         */
        class PopupListener implements ActionListener {
                public void actionPerformed(ActionEvent e) {
                        Object source = e.getSource();
-                       if  (source == popupAdd) {
+                       // Handling panel popup actions.
+                       if (source == popupAdd) {
                                addStandardNote();
+                       } else if (source == popupPaste) {
+                               pasteCopiedNotes();
+                       // Handling selection popup actions.
+                       } else if (source == selPopupCopy) {
+                               copySelectedNotes();
+                       } else if (source == selPopupCut) {
+                               cutSelectedNotes();
+                       } else if (source == selPopupRemove) {
+                               removeSelectedNotes();
+                       } else if (source == selPopupTranspUpOct) {
+                               transposeSelectedNotes(12);
+                       } else if (source == selPopupTranspDownOct) {
+                               transposeSelectedNotes(-12);
                        }
-                       // new MooNote(int channel, int pitch, int velocity, long timestamp, int duration)
                }
        }
 }