package org.herac.tuxguitar.gui.editors.piano; import java.util.List; import org.eclipse.swt.SWT; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.herac.tuxguitar.gui.TuxGuitar; import org.herac.tuxguitar.gui.actions.ActionLock; import org.herac.tuxguitar.gui.actions.caret.GoLeftAction; import org.herac.tuxguitar.gui.actions.caret.GoRightAction; import org.herac.tuxguitar.gui.actions.duration.DecrementDurationAction; import org.herac.tuxguitar.gui.actions.duration.IncrementDurationAction; import org.herac.tuxguitar.gui.actions.tools.ScaleAction; import org.herac.tuxguitar.gui.editors.TGPainter; import org.herac.tuxguitar.gui.editors.tab.Caret; import org.herac.tuxguitar.gui.editors.tab.TGNoteImpl; import org.herac.tuxguitar.gui.undo.undoables.measure.UndoableMeasureGeneric; import org.herac.tuxguitar.song.managers.TGSongManager; import org.herac.tuxguitar.song.models.TGBeat; import org.herac.tuxguitar.song.models.TGDuration; import org.herac.tuxguitar.song.models.TGMeasure; import org.herac.tuxguitar.song.models.TGNote; import org.herac.tuxguitar.song.models.TGString; import org.herac.tuxguitar.song.models.TGTrack; import org.herac.tuxguitar.song.models.TGVoice; public class Piano extends Composite { private class PianoListener implements PaintListener, MouseListener { public PianoListener() { super(); } public void mouseDoubleClick(MouseEvent e) { // Not implemented } public void mouseDown(MouseEvent e) { // Not implemented } public void mouseUp(MouseEvent e) { getPianoComposite().setFocus(); if (e.button == 1) { if (!TuxGuitar.instance().getPlayer().isRunning() && !TuxGuitar.instance().isLocked() && !ActionLock.isLocked()) { ActionLock.lock(); if (getExternalBeat() == null) { hit(e.x, e.y); } else { setExternalBeat(null); } afterAction(); ActionLock.unlock(); } } else { TuxGuitar.instance().getAction(GoRightAction.NAME).process(e); } } public void paintControl(PaintEvent e) { if (!TuxGuitar.instance().isLocked()) { TuxGuitar.instance().lock(); updateEditor(); TGPainter painter = new TGPainter(e.gc); painter.drawImage(Piano.this.image, 0, 0); // pinto notas if (Piano.this.beat != null) { for (int v = 0; v < Piano.this.beat.countVoices(); v++) { TGVoice voice = Piano.this.beat.getVoice(v); for (final TGNote note : voice.getNotes()) { paintNote(painter, getRealNoteValue(note)); } } } TuxGuitar.instance().unlock(); } } } private static final int MAX_OCTAVES = 8; private static final int NATURAL_HEIGHT = 60; private static final int NATURAL_NOTES = 7; private static final int NATURAL_WIDTH = 15; private static final int SHARP_HEIGHT = 40; private static final int SHARP_WIDTH = 8; private static final boolean TYPE_NOTES[] = new boolean[] { true, false, true, false, true, true, false, true, false, true, false, true }; protected TGBeat beat; private boolean changes; private PianoConfig config; private int duration; private Label durationLabel; protected TGBeat externalBeat; protected Image image; private PianoListener listener; private Composite pianoComposite; private Button scale; private Label scaleName; private Button settings; private Composite toolComposite; public Piano(Composite parent, int style) { super(parent, style); this.setLayout(new GridLayout()); this.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); this.listener = new PianoListener(); this.config = new PianoConfig(); this.config.load(); this.initToolBar(); this.makePiano(); this.loadIcons(); this.loadProperties(); TuxGuitar.instance().getkeyBindingManager().appendListenersTo( this.toolComposite); TuxGuitar.instance().getkeyBindingManager().appendListenersTo( this.pianoComposite); } private boolean addNote(int value) { Caret caret = TuxGuitar.instance().getTablatureEditor().getTablature() .getCaret(); List<TGString> strings = caret.getTrack().getStrings(); for (int i = 0; i < strings.size(); i++) { TGString string = (TGString) strings.get(i); if (value >= string.getValue()) { boolean emptyString = true; if (this.beat != null) { for (int v = 0; v < this.beat.countVoices(); v++) { TGVoice voice = this.beat.getVoice(v); for (final TGNote note : voice.getNotes()){ if (note.getString() == string.getNumber()) { emptyString = false; break; } } } } if (emptyString) { TGSongManager manager = TuxGuitar.instance().getSongManager(); // comienza el undoable UndoableMeasureGeneric undoable = UndoableMeasureGeneric.startUndo(); TGNote note = new TGNoteImpl(); note.setValue((value - string.getValue())); note.setVelocity(caret.getVelocity()); note.setString(string.getNumber()); TGDuration duration = caret.getDuration().clone(); manager.getMeasureManager().addNote(caret.getMeasure(), caret.getPosition(), note, duration, caret.getVoice()); // termia el undoable TuxGuitar.instance().getUndoableManager().addEdit(undoable.endUndo()); TuxGuitar.instance().getFileHistory().setUnsavedFile(); // reprodusco las notas en el pulso caret.getSelectedBeat().play(); return true; } } } return false; } protected void afterAction() { int measure = TuxGuitar.instance().getTablatureEditor().getTablature() .getCaret().getMeasure().getNumber(); TuxGuitar.instance().getTablatureEditor().getTablature().getViewLayout() .fireUpdate(measure); TuxGuitar.instance().updateCache(true); } protected void configure() { this.config.configure(getShell()); this.setChanges(true); this.redraw(); } @Override public void dispose() { super.dispose(); this.image.dispose(); this.config.dispose(); } public TGBeat getExternalBeat() { return this.externalBeat; } public Composite getPianoComposite() { return this.pianoComposite; } protected int getRealNoteValue(TGNote note) { TGVoice voice = note.getVoice(); if (voice != null) { TGBeat beat = voice.getBeat(); if (beat != null) { TGMeasure measure = beat.getMeasure(); if (measure != null) { TGTrack track = measure.getTrack(); if (track != null) { return (note.getValue() + track.getString(note.getString()) .getValue()); } } } } // If note have no parents, uses current track strings. Caret caret = TuxGuitar.instance().getTablatureEditor().getTablature() .getCaret(); TGTrack track = caret.getTrack(); if (track != null) { return (note.getValue() + track.getString(note.getString()).getValue()); } return 0; } /** * Retorna el indice de la nota seleccionada * * @param point * @return */ private int getSelection(Point point) { int posX = 0; for (int i = 0; i < (MAX_OCTAVES * TYPE_NOTES.length); i++) { int width = 0; if (TYPE_NOTES[i % TYPE_NOTES.length]) { width = NATURAL_WIDTH; if (i > 0 && !TYPE_NOTES[(i - 1) % TYPE_NOTES.length]) { width -= ((SHARP_WIDTH / 2)); } if (!TYPE_NOTES[(i + 1) % TYPE_NOTES.length]) { width -= ((SHARP_WIDTH / 2)); } } else { width = SHARP_WIDTH; } if (point.x >= posX && point.x < (posX + width)) { return i; } posX += width; } return -1; } public boolean hasChanges() { return this.changes; } protected void hit(int x, int y) { int value = getSelection(new Point(x, y)); if (!removeNote(value)) { addNote(value); } } private void initToolBar() { GridLayout layout = new GridLayout(); layout.makeColumnsEqualWidth = false; layout.numColumns = 0; layout.marginWidth = 0; layout.marginHeight = 0; this.toolComposite = new Composite(this, SWT.NONE); // position layout.numColumns++; Button goLeft = new Button(this.toolComposite, SWT.ARROW | SWT.LEFT); goLeft.addSelectionListener(TuxGuitar.instance().getAction( GoLeftAction.NAME)); layout.numColumns++; Button goRight = new Button(this.toolComposite, SWT.ARROW | SWT.RIGHT); goRight.addSelectionListener(TuxGuitar.instance().getAction( GoRightAction.NAME)); // separator layout.numColumns++; makeToolSeparator(this.toolComposite); // duration layout.numColumns++; Button decrement = new Button(this.toolComposite, SWT.ARROW | SWT.MIN); decrement.addSelectionListener(TuxGuitar.instance().getAction( DecrementDurationAction.NAME)); layout.numColumns++; this.durationLabel = new Label(this.toolComposite, SWT.BORDER); layout.numColumns++; Button increment = new Button(this.toolComposite, SWT.ARROW | SWT.MAX); increment.addSelectionListener(TuxGuitar.instance().getAction( IncrementDurationAction.NAME)); // separator layout.numColumns++; makeToolSeparator(this.toolComposite); // scale layout.numColumns++; this.scale = new Button(this.toolComposite, SWT.PUSH); this.scale.setText(TuxGuitar.getProperty("scale")); this.scale.addSelectionListener(TuxGuitar.instance().getAction( ScaleAction.NAME)); // scale name layout.numColumns++; this.scaleName = new Label(this.toolComposite, SWT.LEFT); // settings layout.numColumns++; this.settings = new Button(this.toolComposite, SWT.PUSH); this.settings.setImage(TuxGuitar.instance().getIconManager().getSettings()); this.settings.setToolTipText(TuxGuitar.getProperty("settings")); this.settings.setLayoutData(new GridData(SWT.RIGHT, SWT.FILL, true, true)); this.settings.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { configure(); } }); this.toolComposite.setLayout(layout); this.toolComposite .setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, true)); } private void loadDurationImage(boolean force) { int duration = TuxGuitar.instance().getTablatureEditor().getTablature() .getCaret().getDuration().getValue(); if (force || this.duration != duration) { this.duration = duration; this.durationLabel.setImage(TuxGuitar.instance().getIconManager() .getDuration(this.duration)); } } public void loadIcons() { this.getShell() .setImage(TuxGuitar.instance().getIconManager().getAppIcon()); this.settings.setImage(TuxGuitar.instance().getIconManager().getSettings()); this.loadDurationImage(true); this.layout(true, true); } public void loadProperties() { this.scale.setText(TuxGuitar.getProperty("scale")); this.settings.setToolTipText(TuxGuitar.getProperty("settings")); this.loadScaleName(); this.layout(true, true); } public void loadScale() { this.loadScaleName(); this.setChanges(true); } private void loadScaleName() { int scaleKey = TuxGuitar.instance().getScaleManager().getSelectionKey(); int scaleIndex = TuxGuitar.instance().getScaleManager().getSelectionIndex(); String key = TuxGuitar.instance().getScaleManager().getKeyName(scaleKey); String name = TuxGuitar.instance().getScaleManager().getScaleName( scaleIndex); this.scaleName.setText((key != null && name != null) ? (key + " - " + name) : ""); this.scaleName.pack(); } private void makePiano() { this.image = makePianoImage(); this.pianoComposite = new Composite(this, SWT.BORDER | SWT.DOUBLE_BUFFERED); this.pianoComposite.setLayout(new GridLayout()); this.pianoComposite.setLayoutData(new GridData( (NATURAL_WIDTH * (MAX_OCTAVES * NATURAL_NOTES)), NATURAL_HEIGHT)); this.pianoComposite.addPaintListener(this.listener); this.pianoComposite.addMouseListener(this.listener); this.pianoComposite.setFocus(); } /** * Crea la imagen del piano * * @return */ private Image makePianoImage() { Image image = new Image(getDisplay(), (NATURAL_WIDTH * (MAX_OCTAVES * NATURAL_NOTES)), NATURAL_HEIGHT); TGPainter painter = new TGPainter(new GC(image)); int x = 0; int y = 0; painter.setBackground(this.config.getColorNatural()); painter.initPath(TGPainter.PATH_FILL); painter.addRectangle(x, y, (NATURAL_WIDTH * (MAX_OCTAVES * NATURAL_NOTES)), NATURAL_HEIGHT); painter.closePath(); for (int i = 0; i < (MAX_OCTAVES * TYPE_NOTES.length); i++) { if (TYPE_NOTES[i % TYPE_NOTES.length]) { painter.setForeground(this.config.getColorNotNatural()); painter.initPath(); painter.setAntialias(false); painter.addRectangle(x, y, NATURAL_WIDTH, NATURAL_HEIGHT); painter.closePath(); x += NATURAL_WIDTH; } else { painter.setBackground(this.config.getColorNotNatural()); painter.initPath(TGPainter.PATH_FILL); painter.setAntialias(false); painter.addRectangle(x - (SHARP_WIDTH / 2), y, SHARP_WIDTH, SHARP_HEIGHT); painter.closePath(); } } paintScale(painter); painter.dispose(); return image; } private void makeToolSeparator(Composite parent) { Label separator = new Label(parent, SWT.SEPARATOR); separator.setLayoutData(new GridData(20, 20)); } /** * Pinta la nota a partir del indice * * @param gc * @param value */ protected void paintNote(TGPainter painter, int value) { painter.setBackground(this.config.getColorNote()); int posX = 0; int y = 0; for (int i = 0; i < (MAX_OCTAVES * TYPE_NOTES.length); i++) { int width = 0; if (TYPE_NOTES[i % TYPE_NOTES.length]) { width = NATURAL_WIDTH; if (i > 0 && !TYPE_NOTES[(i - 1) % TYPE_NOTES.length]) { width -= ((SHARP_WIDTH / 2)); } if (!TYPE_NOTES[(i + 1) % TYPE_NOTES.length]) { width -= ((SHARP_WIDTH / 2)); } } else { width = SHARP_WIDTH; } if (i == value) { if (TYPE_NOTES[i % TYPE_NOTES.length]) { painter.initPath(TGPainter.PATH_FILL); painter.setAntialias(false); painter.addRectangle(posX + 1, y + 1, width - 1, SHARP_HEIGHT); int x = posX; if (i > 0 && !TYPE_NOTES[(i - 1) % TYPE_NOTES.length]) { x -= ((SHARP_WIDTH / 2)); } painter.addRectangle(x + 1, (y + SHARP_HEIGHT) + 1, NATURAL_WIDTH - 1, (NATURAL_HEIGHT - SHARP_HEIGHT) - 1); painter.closePath(); } else { painter.initPath(TGPainter.PATH_FILL); painter.setAntialias(false); painter.addRectangle(posX + 1, y + 1, width - 1, SHARP_HEIGHT - 1); painter.closePath(); } } posX += width; } } /** * Pinta la nota a partir del indice * * @param gc * @param value */ private void paintScale(TGPainter painter) { painter.setBackground(this.config.getColorScale()); painter.setForeground(this.config.getColorScale()); int posX = 0; for (int i = 0; i < (MAX_OCTAVES * TYPE_NOTES.length); i++) { int width = 0; if (TYPE_NOTES[i % TYPE_NOTES.length]) { width = NATURAL_WIDTH; if (i > 0 && !TYPE_NOTES[(i - 1) % TYPE_NOTES.length]) { width -= ((SHARP_WIDTH / 2)); } if (!TYPE_NOTES[(i + 1) % TYPE_NOTES.length]) { width -= ((SHARP_WIDTH / 2)); } } else { width = SHARP_WIDTH; } if (TuxGuitar.instance().getScaleManager().getScale().getNote(i)) { if (TYPE_NOTES[i % TYPE_NOTES.length]) { int x = posX; if (i > 0 && !TYPE_NOTES[(i - 1) % TYPE_NOTES.length]) { x -= ((SHARP_WIDTH / 2)); } int size = SHARP_WIDTH; painter.initPath(TGPainter.PATH_FILL); painter.setAntialias(false); painter.addRectangle((x + 1 + (((NATURAL_WIDTH - size) / 2))), (NATURAL_HEIGHT - size - (((NATURAL_WIDTH - size) / 2))), size, size); painter.closePath(); } else { painter.initPath(TGPainter.PATH_FILL); painter.setAntialias(false); painter.addRectangle(posX + 1, SHARP_HEIGHT - SHARP_WIDTH + 1, SHARP_WIDTH - 2, SHARP_WIDTH - 2); painter.closePath(); } } posX += width; } } @Override public void redraw() { if (!super.isDisposed() && !TuxGuitar.instance().isLocked()) { super.redraw(); this.pianoComposite.redraw(); this.loadDurationImage(false); } } public void redrawPlayingMode() { if (!super.isDisposed() && !TuxGuitar.instance().isLocked()) { this.pianoComposite.redraw(); } } private boolean removeNote(int value) { if (this.beat != null) { for (int v = 0; v < this.beat.countVoices(); v++) { TGVoice voice = this.beat.getVoice(v); for (final TGNote note : voice.getNotes()) { if (getRealNoteValue(note) == value) { // comienza el undoable UndoableMeasureGeneric undoable = UndoableMeasureGeneric .startUndo(); TGSongManager manager = TuxGuitar.instance().getSongManager(); manager.getMeasureManager().removeNote(note); // termia el undoable TuxGuitar.instance().getUndoableManager().addEdit( undoable.endUndo()); TuxGuitar.instance().getFileHistory().setUnsavedFile(); return true; } } } } return false; } public void setChanges(boolean changes) { this.changes = changes; } public void setExternalBeat(TGBeat externalBeat) { this.externalBeat = externalBeat; } protected void updateEditor() { if (isVisible()) { if (hasChanges()) { this.image.dispose(); this.image = makePianoImage(); } if (TuxGuitar.instance().getPlayer().isRunning()) { this.beat = TuxGuitar.instance().getEditorCache().getPlayBeat(); } else if (this.externalBeat != null) { this.beat = this.externalBeat; } else { this.beat = TuxGuitar.instance().getEditorCache().getEditBeat(); } } } }