/*
* Created on 14-Feb-2006
*
* Copyright (c) 2006 P.J.Leonard
*
* http://www.frinika.com
*
* This file is part of Frinika.
*
* Frinika 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 2 of the License, or
* (at your option) any later version.
* Frinika 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 Frinika; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package com.frinika.sequencer.gui.pianoroll;
import java.awt.AWTEvent;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import com.frinika.project.ProjectContainer;
import com.frinika.project.gui.ProjectFrame;
import com.frinika.sequencer.FrinikaSequence;
import com.frinika.sequencer.SwingSongPositionListenerWrapper;
import com.frinika.sequencer.gui.ColorScheme;
import com.frinika.sequencer.gui.DragViewTool;
import com.frinika.sequencer.gui.EraseTool;
import com.frinika.sequencer.gui.Item;
import com.frinika.sequencer.gui.ItemScrollPane;
import com.frinika.sequencer.gui.Layout;
import com.frinika.sequencer.gui.MyCursors;
import com.frinika.sequencer.gui.RectZoomTool;
import com.frinika.sequencer.gui.SelectTool;
import com.frinika.sequencer.gui.WriteTool;
import com.frinika.sequencer.model.EditHistoryAction;
import com.frinika.sequencer.model.EditHistoryContainer;
import com.frinika.sequencer.model.MidiLane;
import com.frinika.sequencer.model.MidiPart;
import com.frinika.sequencer.model.MultiEvent;
import com.frinika.sequencer.model.NoteEvent;
import com.frinika.sequencer.model.Part;
import com.frinika.sequencer.model.timesignature.TimeSignatureList.QStepIterator;
import com.frinika.sequencer.model.util.EventsInPartsIterator;
import static com.frinika.localization.CurrentLocale.getMessage;
/**
* Implementation of a pianoRoll view and editor.
*
*
* @author pjl
*
*/
public class PianoRoll extends PianoRollPanelAdapter {
private int noteItemHeight;
// int defaultLength; // create notes 1 beat long
int pitchTop = 128; // top of screen in pitch
int yScreenBot;
int velocity = 100;
int channel = 1;
private static final long serialVersionUID = 1L;
private static final Color selCol = new Color(127, 127, 127, 200);
private static final Color noteCol = Color.RED;
private static final Color dragCol = Color.BLACK;
Iterable<MultiEvent> notesOnScreen;
Iterable<MultiEvent> notesInFocus;
boolean pasteing = false;
EditHistoryContainer editHistory;
private ItemPanelMultiEventListener multiEventListener;
private ItemPanelPartListener partListener;
private NoteEvent newNote;
AudioFeedBack audioFeedBack;
Point writeAtPoint;
private boolean drumWriteMode = false; // if true write zero length notes
/**
* Constructor.
*
* @param project
* project to view
* @param scroller
* controls the view onto the virtualScreen.
*/
public PianoRoll(final ProjectFrame frame, ItemScrollPane scroller) {
super(frame.getProjectContainer(), scroller, true, true);
final ProjectContainer project = frame.getProjectContainer();
notesOnScreen = new Iterable<MultiEvent>() {
public Iterator<MultiEvent> iterator() {
return new EventsInPartsIterator(project.getPartSelection()
.getSelected(), PianoRoll.this);
}
};
notesInFocus = new Iterable<MultiEvent>() {
public Iterator<MultiEvent> iterator() {
Part focus = project.getPartSelection().getFocus();
if (focus == null)
return null;
return new EventsInPartsIterator(project.getPartSelection()
.getFocus(), PianoRoll.this);
}
};
audioFeedBack = new AudioFeedBack(project);
this.sequencer = project.getSequencer();
multiEventListener = new ItemPanelMultiEventListener(this);
partListener = new ItemPanelPartListener(this);
project.getMultiEventSelection().addSelectionListener(
multiEventListener);
project.getPartSelection().addSelectionListener(partListener);
// focusLane = null;
sequencer.addSongPositionListener(new SwingSongPositionListenerWrapper(
this));
FrinikaSequence seq = (FrinikaSequence) sequencer.getSequence();
editHistory = project.getEditHistoryContainer();
editHistory.addEditHistoryListener(this);
project.getDragList().addDragEventListener(new DragEventListener() {
public void update() {
repaintItems();
}
});
ticksPerBeat = seq.getResolution();
// defaultLength = ticksPerBeat;
if (project.getPianoRollSnapQuantization() == 0) {
project.setPianoRollSnapQuantization(ticksPerBeat);
}
// snaptoQuantization = ticksPerBeat;
setLayout(null);
setBackground(Color.WHITE);
repaintItems();
addComponentListener(this);
makeTools();
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
setFocusable(true);
}
protected void processMouseEvent(MouseEvent e) {
if (e.getID() == MouseEvent.MOUSE_PRESSED) {
grabFocus();
}
super.processMouseEvent(e);
}
public void dispose() {
project.getMultiEventSelection().removeSelectionListener(
multiEventListener);
project.getPartSelection().removeSelectionListener(partListener);
editHistory.removeEditHistoryListener(this);
}
/**
* drags the dragList to Point p.
*
*/
public void dragTo(Point p) {
int dxDragged = p.x - xAnchor;
int dyDragged = p.y - yAnchor;
long dtick;
NoteEvent dddNote = null;
dtick = screenToTickRel(xAnchor, dxDragged, project
.isPianoRollSnapQuantized());
/*
* if (project.isPianoRollSnapQuantized()) { dtick =
* snaptoQuantize(dxDragged); } else { dtick = (long) (dxDragged /
* ticksToScreen); }
*/
int dpitch = 0;
if (dragMode == OVER_ITEM_MIDDLE)
dpitch = -dyDragged / noteItemHeight;
if (dtick == 0 && dpitch == 0 && !altIsDown)
return;
if (dragArmed)
startDrag();
dragArmed = false;
List<Item> dragList = project.getDragList();
if (dragList.isEmpty())
return;
if (altIsDown && project.isPianoRollSnapQuantized()) {
dddNote = (NoteEvent) (dragList.get(0));
if (dragMode != OVER_ITEM_RIGHT) {
long refTick = ((NoteEvent) dddNote).getStartTick();
long screenPos = (int) userToScreen(refTick);
long newTick = screenToTickAbs((int) (screenPos + dxDragged),
true);
dtick = newTick - refTick;
} else {
long refTick = ((NoteEvent) dddNote).getEndTick();
long screenPos = (int) userToScreen(refTick);
long newTick = screenToTickAbs((int) (screenPos + dxDragged),
true);
dtick = newTick - refTick;
}
// System. out.println(dddNote + " " + dtick);
if (dtick == 0)
return;
}
if (dpitch != 0) {
int pitlim;
if (dpitch > 0)
pitlim = 0;
else
pitlim = 127;
for (Item it : dragList) {
NoteEvent ev = (NoteEvent) it;
int pitch = ((NoteEvent) ev).getNote() + dpitch;
if (dpitch > 0)
pitlim = Math.max(pitch, pitlim);
else
pitlim = Math.min(pitch, pitlim);
}
if (dpitch > 0 && pitlim > 127)
dpitch = dpitch - (pitlim - 127);
else if (dpitch < 0 && pitlim < 0)
dpitch = dpitch - pitlim;
}
long dt = 0;
for (Item it : dragList) {
NoteEvent ev = (NoteEvent) it;
switch (dragMode) {
case OVER_ITEM_MIDDLE:
long tick = ev.getStartTick() + dtick;
int pitch = ((NoteEvent) ev).getNote() + dpitch;
dt = Math.min(dt, tick);
ev.setStartTick(tick);
ev.setNote(pitch);
break;
case OVER_ITEM_RIGHT:
long dur = ev.getDuration() + dtick;
dur = Math.max(1, dur);
ev.setDuration(dur);
break;
case OVER_ITEM_LEFT:
dur = ev.getDuration() - dtick;
long st = ev.getStartTick() + dtick;
dur = Math.max(1, dur);
ev.setDuration(dur);
ev.setStartTick(st);
break;
default:
System.err.println(" unknown dragmode " + dragMode);
}
if (dpitch != 0)
feedBack(ev);
}
if (dt != 0) {
for (Item it : dragList) {
NoteEvent ev = (NoteEvent) it;
long tick = ev.getStartTick() - dt;
ev.setStartTick(tick);
}
}
project.getDragList().notifyDragEventListeners();
project.getDragList().notifyFeedbackItemListeners();
xAnchor = xAnchor + (int) (dtick * userToScreen);
yAnchor = yAnchor - dpitch * noteItemHeight;
// repaintItems();
}
public void clientClearSelection() {
project.getMultiEventSelection().clearSelection();
}
/**
* Call this to start dragging with the reference point. See dragTo
*
* @param e
*/
public void startDrag() {
project.getDragList().startDrag(dragItem);
}
/**
* Select/deselect all the items in a rectange.
*
* @param yes
* true to select. false to deselect
* @param rect
* rectangle in score screen space.
*/
public synchronized void selectInRect(Rectangle rect, boolean shift) {
Collection<MultiEvent> addTmp = new Vector<MultiEvent>();
Collection<MultiEvent> delTmp = new Vector<MultiEvent>();
Iterable<? extends MultiEvent> list;
Part focusPart = project.getPartSelection().getFocus();
if (!(focusPart instanceof MidiPart))
return;
if (focusPart != null)
list = ((MidiPart) focusPart).getMultiEvents();
else
list = notesOnScreen;
for (MultiEvent note : list) {
if (note instanceof NoteEvent) {
if (rect.intersects(getItemBounds((NoteEvent) note))) {
if (shift) {
if (note.isSelected())
delTmp.add(note);
else
addTmp.add(note);
} else {
addTmp.add(note);
}
}
}
}
project.getMultiEventSelection().removeSelected(delTmp);
project.getMultiEventSelection().addSelected(addTmp);
project.getMultiEventSelection().notifyListeners();
}
@Override
protected void writeReleasedAt(Point p) {
if (newNote == null)
return;
newNote.getPart().add(newNote);
project.getMultiEventSelection().setSelected(newNote);
project.getEditHistoryContainer().notifyEditHistoryListeners();
project.getMultiEventSelection().notifyListeners();
newNote = null;
writeAtPoint=null;
}
public synchronized void writeDraggedAt(Point p) {
if (newNote == null)
return;
long tick = screenToTickAbs(p.x, true);
long tick1 = newNote.getStartTick();
long tick2 = tick1 + newNote.getDuration();
int pitch = screenToPitch(p.y);
boolean doit = false;
if (drumWriteMode) {
if (tick != tick1 ) {
if (writeAtPoint != null) p.y=writeAtPoint.y; // keep pitch of first beat
writeReleasedAt(p);
writePressedAt(p);
doit=true;
}
} else {
if (tick > tick2) {
newNote.setDuration(tick - tick1);
doit = true;
} else if (tick < tick2 && tick > tick1) {
newNote.setDuration(tick - tick1);
doit = true;
}
if (pitch != newNote.getNote() && pitch >= 0 && pitch < 128) {
doit = true;
newNote.setNote(pitch);
feedBack(newNote);
}
project.getDragList().notifyFeedbackItemListeners(newNote);
}
if (doit)
repaintItems();
}
/**
* Used by the write tool to insert a note.
*/
protected synchronized void writePressedAt(Point p) {
Part focusPart = project.getPartSelection().getFocus();
if (focusPart == null || !(focusPart instanceof MidiPart)) {
System.out.println(" Please slectect a part ");
return;
}
if (writeAtPoint == null) writeAtPoint=p;
long tick = screenToTickAbs(p.x, true,drumWriteMode);
int pitch = screenToPitch(p.y);
assert (pitch > 0);
assert (pitch < 128);
project.getEditHistoryContainer().mark(
getMessage("sequencer.pianoroll.add_note"));
if (drumWriteMode) {
newNote = new NoteEvent((MidiPart) focusPart, tick, pitch,
velocity, channel, 0);
} else {
long quant = (long) project.getPianoRollSnapQuantization();
if (quant <= 0)
quant = project.getTicksPerBeat();
newNote = new NoteEvent((MidiPart) focusPart, tick, pitch,
velocity, channel, quant);
}
feedBack(newNote);
project.getDragList().notifyFeedbackItemListeners(newNote);
repaintItems();
}
/**
* convert screen y to a pitch
*
* @param y
* @return pitch for the given screen y
*/
private int screenToPitch(int y) {
return pitchTop - (y / noteItemHeight);
}
/**
* Find component the contains point x,y and set. first component found is
* set (is this what we want ?) TODO multitrack thinking.
*
* @param x
* @param y
* @return the NoteEvent at this point.
*/
public Item itemAt(Point p) {
Item at = null;
for (MultiEvent note : notesOnScreen) {
if (getItemBounds(note).contains(p)) {
if (note.isSelected())
return note;
else if (at == null)
at = note;
}
}
return at;
}
/**
* Translate pitch to screen (vertical)
*
* @param pitch
* @return screen y for given pitch
*/
int pitchToScreen(int pitch) {
return (pitchTop - pitch) * noteItemHeight;
}
public void fireSequenceDataChanged(EditHistoryAction[] edithistoryActions) {
repaintItems();
}
private Color alphaColor(Color c, float alpha) {
float[] rgb = c.getRGBComponents(new float[4]);
return new Color(rgb[0], rgb[1], rgb[2], alpha);
}
private Color alphaColor(Color c, int velocity) {
return alphaColor(c, velocity * (1.0f / 127.0f));
}
private Color alphaColor(Color c, MultiEvent note) {
return alphaColor(c, ((NoteEvent) note).getVelocity());
}
public synchronized void paintImageImpl(final Rectangle visibleRect,
Graphics2D g) {
if (g == null)
return;
noteItemHeight = Layout.getNoteItemHeight();
yScreenBot = pitchTop * noteItemHeight;
Part focusPart = project.getPartSelection().getFocus();
// System.out.println("paintImageImpl");
// if (dragList != null && dragList.isEmpty())
// dragList = null;
int w = visibleRect.width;
int x = visibleRect.x;
int y = visibleRect.y;
int h = visibleRect.height;
int yBot = yScreenBot; // - itemViewRect.y + Layout.timePanelHeight;
// Horizontal lines
g.setColor(Color.lightGray);
int p1 = screenToPitch(y);
int y1 = pitchToScreen(p1);
if (y1 <= y - noteItemHeight) {
p1 -= 1;
y1 = pitchToScreen(p1);
}
assert (y1 > y - noteItemHeight);
Rectangle frect = new Rectangle(visibleRect);
if (focusPart != null) {
g.fill(frect);
g.setColor(ColorScheme.pianaoRollInvalid);
int fl = (int) (focusPart.getStartTick() * userToScreen);
int fr = (int) (focusPart.getEndTick() * userToScreen);
frect.x = fl;
frect.width = fr - fl;
frect = frect.intersection(visibleRect);
// if (!frect.isEmpty()) {
// // g.setColor(new Color(0xF0FEFE));
// g.setColor(ColorScheme.validBackground);
// g.fill(frect);
// }
}
Color blackNoteStripColor = new Color(200, 200, 240);
while (y1 < y + h) {
int i = noteItemHeight;
boolean drawLine = y1 >= y;
if (!drawLine) {
i -= y - y1;
y1 = y;
}
switch (p1 % 12) {
case 0:
case 2:
case 4:
case 5:
case 7:
case 9:
case 11:
g.setColor(Color.WHITE);
break;
default:
g.setColor(blackNoteStripColor);
break;
}
g.fill(new Rectangle(frect.x, y1, frect.width, noteItemHeight));
if (drawLine) {
Color cc;
if (p1 % 12 == 11) {
cc = Color.red;
g.setXORMode(cc);
g.drawLine(x, y1, x + w, y1);
} else if (p1 % 12 == 4) {
cc = Color.gray;
g.setXORMode(cc);
g.drawLine(x, y1, x + w, y1);
// cc = Color.lightGray;
}
}
g.setPaintMode();
p1 -= 1;
y1 = pitchToScreen(p1);
}
// Draw vertical lines
// Vertical lines
int ticksPerBeat = project.getSequence().getResolution();
double beat1 = screenToTickAbs(x, true) / ticksPerBeat;
double beat2 = screenToTickAbs(x + w, true) / ticksPerBeat;
double step = project.getPianoRollSnapQuantization() / ticksPerBeat;
QStepIterator iter = project.getTimeSignatureList()
.createQStepIterator(beat1, beat2, step);
boolean drawSub = (int) userToScreen((long) (step * ticksPerBeat)) > 5;
boolean drawBeat = (int) userToScreen((long) (ticksPerBeat)) > 5;
while (iter.hasNext()) {
iter.next();
double beat = iter.getBeat();
boolean isBar = iter.isBar();
if (isBar) {
g.setColor(ColorScheme.partViewLinesBar);
} else {
if (!drawBeat)
continue;
if (Math.abs((beat + 1e-7) % 1) < 2e-7) {
g.setColor(ColorScheme.partViewLinesBeat);
} else {
if (!drawSub)
continue;
g.setColor(ColorScheme.partViewLinesSubBeat);
}
}
long tick = (long) (beat * ticksPerBeat);
int x1 = (int) userToScreen(tick);
g.drawLine(x1, y, x1, y + h);
}
/***********************************************************************
* int x1 = (int)tickToScreen((long) tick1); if (x1 < x) { tick1 +=
* snaptoQuantization; x1 = (int)tickToScreen((long) tick1); }
*
* assert (x1 >= x); // int beatsPerBar = project.beatsPerBar;
*
*
* while (x1 < x + w) { // if (Math.abs((tick1 + 1.0) % (ticksPerBeat *
* beatsPerBar)) < 2.0) g.setColor(Color.BLUE); // else if
* (Math.abs((tick1 + 1.0) % ticksPerBeat) < 2.0)
* g.setColor(Color.DARK_GRAY); // else g.setColor(Color.lightGray);
* g.drawLine(x1, y, x1, y + h); tick1 += snaptoQuantization; x1 =
* (int)tickToScreen((long) tick1); } }
**********************************************************************/
if (!(focusPart instanceof MidiPart))
return; // focusPart=null;
// return;
// Now draw the notes....................
Collection<Item> dragList = project.getDragList();
for (MultiEvent note : notesOnScreen) {
if (focusPart != null && note.getPart() == focusPart)
continue;
// if (!validEvent(note))
// continue;
Rectangle2D noteRect = getItemBounds(note);
if (visibleRect != null && !visibleRect.intersects(noteRect))
continue;
Shape shape = getItemShape(note);
if (note.isZombie()) {
// g.setColor(Color.LIGHT_GRAY);
// g.fill(noteRect);
} else if (note.isSelected()) {
if (dragList.isEmpty()) {
g.setColor(ColorScheme.selectedColor);
g.fill(shape);
}
} else {
MidiLane myLane = (MidiLane) note.getPart().getLane();
if (myLane == null) {
g.setColor(Color.BLACK);
} else {
g.setColor(note.getPart().getColor());
}
g.fill(shape);
}
}
if (focusPart != null) {
for (MultiEvent note : notesInFocus) {
assert (note instanceof NoteEvent);
Rectangle noteRect = getItemBounds(note);
if (visibleRect != null && !visibleRect.intersects(noteRect))
continue;
Shape shape = getItemShape(note);
if (note.isSelected()) {
if (dragList.isEmpty()) {
g.setColor(selCol);
g.fill(shape);
}
} else if (note.isZombie()) {
// g.setColor(Color.LIGHT_GRAY);
// g.fill(noteRect);
} else {
MidiLane myLane = (MidiLane) note.getPart().getLane();
if (myLane == null) {
g.setColor(Color.BLACK);
g.fill(shape);
} else {
Color col = note.getPart().getColor();
g.setColor(alphaColor(col, note));
g.fill(shape);
g.setColor(col);
if (!((NoteEvent) note).isDrumHit()) { // what's all
// this about
// anyway. I
// should know I
// wrote it PJL
Rectangle noteRect2 = new Rectangle();
noteRect2.width = noteRect.width - 2;
noteRect2.height = noteRect.height - 2;
noteRect2.x = noteRect.x + 1;
noteRect2.y = noteRect.y + 1;
g.draw(noteRect2);
}
}
}
g.setColor(Color.BLACK);
g.draw(shape);
}
}
if (!dragList.isEmpty()) {
for (Item it : dragList) {
NoteEvent note = (NoteEvent) it;
Rectangle noteRect = getItemBounds(note);
if (visibleRect != null && !visibleRect.intersects(noteRect))
continue;
Shape shape = getItemShape(note);
g.setColor(selCol);
g.fill(noteRect);
g.setColor(Color.RED);
g.draw(shape);
}
}
if (newNote != null) {
Rectangle noteRect = getItemBounds(newNote);
/*
* if (visibleRect != null && !visibleRect.intersects(noteRect))
* continue;
*/
Shape shape = getItemShape(newNote);
g.setColor(selCol);
g.fill(noteRect);
g.setColor(Color.BLACK);
g.draw(shape);
}
}
/**
* Find the screen rectangle for the event
*
* use it quickly because we modify a single object and return a reference
* it could be changed by the next call.
*
* @param e
* NoteEvent
* @return rectangle on screen
*/
final Rectangle rectTmp = new Rectangle();
/**
* returns the Rectangle contian the GUI representation of the item
*
* @param it
* @return
*/
private Rectangle getItemBounds(Item it) {
NoteEvent e = (NoteEvent) it;
long tick = e.getStartTick();
// Careful that origins must always conincide
int x1 = (int) userToScreen(tick);
int pitch = e.getNote();
int y1 = pitchToScreen(pitch);
if (!e.isDrumHit()) {
long dur = e.getDuration();
int w = (int) userToScreen(dur);
if (w <= 6)
w = 6;
rectTmp.setBounds((int) x1, (int) y1 + 1, w, noteItemHeight - 2);
} else {
int dd = noteItemHeight / 2 - 1;
rectTmp.setBounds((int) x1 - dd, (int) y1 + 1, 2 * dd,
noteItemHeight - 2);
}
return rectTmp;
// return new Rectangle((int) x1, (int) y1 + 1, w, noteItemHeight - 2);
}
/* a little sneakiness to avoid new */
final int xp[] = new int[4];
final int yp[] = new int[4];
final Polygon drumShape = new Polygon(xp, yp, 4);
/**
* returns the Rectangle contian the GUI representation of the item
*
* @param it
* @return
*/
private Shape getItemShape(Item it) {
NoteEvent e = (NoteEvent) it;
long tick = e.getStartTick();
// Careful that origins must always conincide
int x1 = (int) userToScreen(tick);
int pitch = e.getNote();
int y1 = pitchToScreen(pitch);
if (!e.isDrumHit()) {
long dur = e.getDuration();
// Careful that origins must always conincide
int w = (int) userToScreen(dur);
if (w == 0)
w = 1;
rectTmp.setBounds((int) x1, (int) y1 + 1, w, noteItemHeight - 2);
return rectTmp;
} else {
int dd = noteItemHeight / 2;
int yc = y1 + dd;
dd -= 1;
xp[0] = xp[2] = x1;
xp[1] = x1 - dd;
xp[3] = x1 + dd;
yp[0] = yc - dd;
yp[2] = yc + dd;
yp[1] = yp[3] = yc;
return new Polygon(xp, yp, 4); // drumShape;
}
// return new Rectangle((int) x1, (int) y1 + 1, w, noteItemHeight - 2);
}
@Override
public void endDrag() {
if (dragArmed) {
dragArmed = false;
return;
}
project.getDragList().endDrag(controlIsDown);
}
public void erase(Item it) {
NoteEvent note = (NoteEvent) it;
editHistory.mark(getMessage("sequencer.pianoroll.erase_note"));
note.getPart().remove(note);
editHistory.notifyEditHistoryListeners();
}
@Override
public void rightButtonPressedOnItem(int x, int y) {
System.out.println(" Right button pressed (so what?) ");
}
/**
* play the note
*/
public void feedBack(Item item) {
audioFeedBack.select((NoteEvent) item);
}
@Override
public void clientAddToSelection(Item item) {
project.getPartSelection().setFocus(((MultiEvent) item).getPart());
project.getMultiEventSelection().addSelected((NoteEvent) item);
project.getMultiEventSelection().notifyListeners();
}
@Override
public void clientRemoveFromSelection(Item item) {
project.getMultiEventSelection().removeSelected((NoteEvent) item);
project.getMultiEventSelection().notifyListeners();
}
@Override
public int getHoverStateAt(Point p) {
Part focusPart = project.getPartSelection().getFocus();
if (!(focusPart instanceof MidiPart))
return OVER_NOTHING;
final int endTol = 20;
// final int extraX = 20 ;
// if (true) return OVER_ITEM_MIDDLE;
int tol = endTol;
Iterable<? extends MultiEvent> list;
if (focusPart == null)
list = notesOnScreen;
else
list = ((MidiPart) focusPart).getMultiEvents();
for (MultiEvent e : list) {
if (e instanceof NoteEvent) {
Rectangle rect = getItemBounds(e);
if (rect.contains(p)) {
if (((NoteEvent) e).isDrumHit())
return OVER_ITEM_MIDDLE;
if (rect.width < endTol * 5)
tol = rect.width / 3;
if ((p.x - rect.x) <= tol)
return OVER_ITEM_LEFT;
if ((rect.x + rect.width - p.x) <= tol)
return OVER_ITEM_RIGHT;
return OVER_ITEM_MIDDLE;
}
}
}
return OVER_NOTHING;
}
void makeTools() {
Cursor c = new Cursor(Cursor.DEFAULT_CURSOR);
selectTool = new SelectTool(c);
rectZoomTool = new RectZoomTool(c);
// drumWriteTool = new WriteTool(MyCursors.getCursor("pencil"));
writeTool = new WriteTool(MyCursors.getCursor("pencil"));
eraseTool = new EraseTool(MyCursors.getCursor("eraser"));
dragViewTool = new DragViewTool(MyCursors.getCursor("move"));
}
@Override
protected void paintImageImplLabel(Graphics2D graphics) {
// TODO Auto-generated method stub
}
public final boolean isValidEvent(MultiEvent event) {
return event instanceof NoteEvent;
}
public void ignorePartWarp(boolean b) {
PartSelectedAction.ignoreWarp = b;
}
public synchronized void componentResized(ComponentEvent arg0) {
super.componentResized(arg0);
int extent = (int) getVisibleRect().getHeight();
getYRangeModel().setExtent(extent);
}
public void selectAll() {
Part focus = project.getPartSelection().getFocus();
if (focus == null)
return;
Vector<MultiEvent> notes = new Vector<MultiEvent>();
for (MultiEvent e : notesInFocus) {
notes.add(e);
}
project.getMultiEventSelection().setSelected(notes);
project.getMultiEventSelection().notifyListeners();
}
interface NoteShape extends Shape {
};
@SuppressWarnings("serial")
class MNoteShape extends Rectangle implements NoteShape {
}
@SuppressWarnings("serial")
class DNoteShape extends Polygon implements NoteShape {
}
void setDrumWriteMode(boolean b) {
drumWriteMode = b;
}
}