/* * Created on 28-dic-2005 * * TODO To change the template for this generated file go to Window - * Preferences - Java - Code Style - Code Templates */ package org.herac.tuxguitar.gui.editors.fretboard; 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.Color; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Combo; 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.system.config.TGConfigKeys; import org.herac.tuxguitar.gui.undo.undoables.measure.UndoableMeasureGeneric; import org.herac.tuxguitar.gui.util.TGMusicKeyUtils; 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; /** * @author julian * * TODO To change the template for this generated type comment go to * Window - Preferences - Java - Code Style - Code Templates */ public class FretBoard extends Composite { class FretBoardListener implements PaintListener, MouseListener { public void mouseDoubleClick(MouseEvent e) { // Not implemented } public void mouseDown(MouseEvent e) { // Not implemented } public void mouseUp(MouseEvent e) { getFretBoardComposite().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) { TGPainter painter = new TGPainter(e.gc); paintEditor(painter); } } public static final int BOTTOM_SPACING = 10; public static final int MAX_FRETS = 24; private static final String[] NOTE_NAMES = TGMusicKeyUtils .getSharpKeyNames(TGMusicKeyUtils.PREFIX_FRETBOARD); private static final int STRING_SPACING = TuxGuitar.instance().getConfig() .getIntConfigValue(TGConfigKeys.FRETBOARD_STRING_SPACING); public static final int TOP_SPACING = 10; private TGBeat beat; private boolean changes; private FretBoardConfig config; private int duration; private Label durationLabel; private TGBeat externalBeat; private Image fretBoard; protected Composite fretBoardComposite; private int[] frets; private int fretSpacing; protected Combo handSelector; private Point lastSize; private FretBoardListener listener; private Button scale; private Label scaleName; private Button settings; private int[] strings; private Composite toolComposite; public FretBoard(Composite parent) { super(parent, SWT.NONE); this.setLayout(new FormLayout()); this.listener = new FretBoardListener(); this.config = new FretBoardConfig(); this.config.load(); this.initToolBar(); this.initEditor(); this.loadIcons(); this.loadProperties(); TuxGuitar.instance().getkeyBindingManager().appendListenersTo( this.toolComposite); TuxGuitar.instance().getkeyBindingManager().appendListenersTo( this.fretBoardComposite); } private void addNote(int fret, int string) { TGSongManager manager = TuxGuitar.instance().getSongManager(); // comienza el undoable UndoableMeasureGeneric undoable = UndoableMeasureGeneric.startUndo(); Caret caret = TuxGuitar.instance().getTablatureEditor().getTablature() .getCaret(); TGNote note = new TGNoteImpl(); note.setValue(fret); note.setVelocity(caret.getVelocity()); note.setString(string); 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(); } protected void afterAction() { int measure = TuxGuitar.instance().getTablatureEditor().getTablature() .getCaret().getMeasure().getNumber(); TuxGuitar.instance().getTablatureEditor().getTablature().getViewLayout() .fireUpdate(measure); TuxGuitar.instance().updateCache(true); } private void calculateFretSpacing(int width) { this.fretSpacing = (width / MAX_FRETS); int aux = 0; for (int i = 0; i < MAX_FRETS; i++) { aux += (i * 2); } this.fretSpacing += (aux / MAX_FRETS) + 2; } protected void configure() { this.config.configure(getShell()); this.handSelector.select(this.getDirection(this.config.getDirection())); this.setChanges(true); this.redraw(); } @Override public void dispose() { super.dispose(); this.disposeFretBoardImage(); this.config.dispose(); } private void disposeFretBoardImage() { if (this.fretBoard != null && !this.fretBoard.isDisposed()) { this.fretBoard.dispose(); } } private int getDirection(int value) { int direction = value; if (direction != FretBoardConfig.DIRECTION_RIGHT && direction != FretBoardConfig.DIRECTION_LEFT) { direction = FretBoardConfig.DIRECTION_RIGHT; } return direction; } public TGBeat getExternalBeat() { return this.externalBeat; } public Composite getFretBoardComposite() { return this.fretBoardComposite; } private int getFretIndex(int x) { int length = this.frets.length; if ((x - 10) <= this.frets[0] && this.frets[0] < this.frets[length - 1]) { return 0; } if ((x + 10) >= this.frets[0] && this.frets[0] > this.frets[length - 1]) { return 0; } for (int i = 0; i < length; i++) { if ((i + 1) < length) { if (x > this.frets[i] && x <= this.frets[i + 1] || x > this.frets[i + 1] && x <= this.frets[i]) { return i + 1; } } } return length - 1; } public int getHeight() { int borderWidth = (2 * this.fretBoardComposite.getBorderWidth()); int toolBarHeight = (this.toolComposite.getBounds().height); int fretBoardHeight = (((STRING_SPACING) * (this.strings.length - 1)) + TOP_SPACING + BOTTOM_SPACING); return (borderWidth + toolBarHeight + fretBoardHeight); } private int getOvalSize() { return ((STRING_SPACING / 2) + (STRING_SPACING / 10)); } private int getStringCount() { TGTrack track = getTrack(); if (track != null) { return track.stringCount(); } return 0; } private int getStringIndex(int y) { int index = -1; for (int i = 0; i < this.strings.length; i++) { if (index < 0) { index = i; } else { int distanceY = Math.abs(y - this.strings[index]); int currDistanceY = Math.abs(y - this.strings[i]); if (currDistanceY < distanceY) { index = i; } } } return index; } private TGTrack getTrack() { if (this.beat != null) { TGMeasure measure = this.beat.getMeasure(); if (measure != null) { TGTrack track = measure.getTrack(); if (track != null) { return track; } } } return TuxGuitar.instance().getTablatureEditor().getTablature().getCaret() .getTrack(); } public int getWidth() { return this.frets[this.frets.length - 1]; } public boolean hasChanges() { return this.changes; } protected void hit(int x, int y) { int fretIndex = getFretIndex(x); int stringIndex = getStringIndex(y); TuxGuitar.instance().getTablatureEditor().getTablature().getCaret() .setStringNumber(stringIndex + 1); if (!removeNote(fretIndex, stringIndex + 1)) { addNote(fretIndex, stringIndex + 1); } } private void initEditor() { this.lastSize = new Point(0, 0); FormData data = new FormData(); data.left = new FormAttachment(0, 0); data.right = new FormAttachment(100, 0); data.top = new FormAttachment(this.toolComposite, 0); data.bottom = new FormAttachment(100, 0); this.fretBoardComposite = new Composite(this, SWT.BORDER | SWT.DOUBLE_BUFFERED); this.fretBoardComposite.setLayoutData(data); this.fretBoardComposite.setBackground(this.config.getColorBackground()); this.fretBoardComposite.addMouseListener(this.listener); this.fretBoardComposite.addPaintListener(this.listener); } protected void initFrets(int fromX) { this.frets = new int[MAX_FRETS]; int nextX = fromX; int direction = this.getDirection(this.config.getDirection()); if (direction == FretBoardConfig.DIRECTION_RIGHT) { for (int i = 0; i < this.frets.length; i++) { this.frets[i] = nextX; nextX += (this.fretSpacing - ((i + 1) * 2)); } } else if (direction == FretBoardConfig.DIRECTION_LEFT) { for (int i = this.frets.length - 1; i >= 0; i--) { this.frets[i] = nextX; nextX += (this.fretSpacing - (i * 2)); } } } private void initStrings(int count) { int fromY = TOP_SPACING; this.strings = new int[count]; for (int i = 0; i < this.strings.length; i++) { this.strings[i] = fromY + (STRING_SPACING * i); } } private void initToolBar() { FormData data = new FormData(); data.left = new FormAttachment(0, 0); data.right = new FormAttachment(100, 0); data.top = new FormAttachment(0, 0); GridLayout layout = new GridLayout(); layout.makeColumnsEqualWidth = false; layout.numColumns = 0; layout.marginWidth = 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); // hand selector layout.numColumns++; this.handSelector = new Combo(this.toolComposite, SWT.DROP_DOWN | SWT.READ_ONLY); this.handSelector.add(TuxGuitar.getProperty("fretboard.right-mode")); this.handSelector.add(TuxGuitar.getProperty("fretboard.left-mode")); this.handSelector.select(this.getDirection(this.config.getDirection())); this.handSelector.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { updateDirection(FretBoard.this.handSelector.getSelectionIndex()); } }); // 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.setLayoutData(data); this.toolComposite.setLayout(layout); } @Override public void layout() { super.layout(); } public void layout(int width) { this.disposeFretBoardImage(); this.calculateFretSpacing(width); this.initFrets(10); this.initStrings(getStringCount()); this.setChanges(false); } 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.settings.setImage(TuxGuitar.instance().getIconManager().getSettings()); this.loadDurationImage(true); this.layout(true, true); this.layout(getClientArea().width); } public void loadProperties() { int selection = this.handSelector.getSelectionIndex(); this.handSelector.removeAll(); this.handSelector.add(TuxGuitar.getProperty("fretboard.right-mode")); this.handSelector.add(TuxGuitar.getProperty("fretboard.left-mode")); this.handSelector.select(selection); this.settings.setToolTipText(TuxGuitar.getProperty("settings")); this.scale.setText(TuxGuitar.getProperty("scale")); this.loadScaleName(); this.setChanges(true); 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 makeToolSeparator(Composite parent) { Label separator = new Label(parent, SWT.SEPARATOR); separator.setLayoutData(new GridData(20, 20)); } protected void paintEditor(TGPainter painter) { if (!TuxGuitar.instance().isLocked()) { TuxGuitar.instance().lock(); this.updateEditor(); if (this.frets.length > 0 && this.strings.length > 0) { paintFretBoard(painter); paintNotes(painter); } TuxGuitar.instance().unlock(); } } private void paintFretBoard(TGPainter painter) { if (this.fretBoard == null || this.fretBoard.isDisposed()) { this.fretBoard = new Image(getDisplay(), getClientArea().width, ((STRING_SPACING) * (this.strings.length - 1)) + TOP_SPACING + BOTTOM_SPACING); TGPainter painterBuffer = new TGPainter(new GC(this.fretBoard)); // fondo painterBuffer.setBackground(this.config.getColorBackground()); painterBuffer.initPath(TGPainter.PATH_FILL); painterBuffer.addRectangle(getClientArea()); painterBuffer.closePath(); // pinto las cegillas Image fretImage = TuxGuitar.instance().getIconManager() .getFretboardFret(); Image firstFretImage = TuxGuitar.instance().getIconManager() .getFretboardFirstFret(); painterBuffer.drawImage(firstFretImage, 0, 0, firstFretImage.getBounds().width, firstFretImage.getBounds().height, this.frets[0] - 5, this.strings[0] - 5, firstFretImage.getBounds().width, this.strings[this.strings.length - 1]); paintFretPoints(painterBuffer, 0); for (int i = 1; i < this.frets.length; i++) { painterBuffer.drawImage(fretImage, 0, 0, fretImage.getBounds().width, fretImage.getBounds().height, this.frets[i], this.strings[0] - 5, fretImage.getBounds().width, this.strings[this.strings.length - 1]); paintFretPoints(painterBuffer, i); } // pinto las cuerdas for (int i = 0; i < this.strings.length; i++) { painterBuffer.setForeground(this.config.getColorString()); if (i > 2) { painterBuffer.setLineWidth(2); } painterBuffer.initPath(); painterBuffer.setAntialias(false); painterBuffer.moveTo(this.frets[0], this.strings[i]); painterBuffer .lineTo(this.frets[this.frets.length - 1], this.strings[i]); painterBuffer.closePath(); } // pinto la escala paintScale(painterBuffer); painterBuffer.dispose(); } painter.drawImage(this.fretBoard, 0, 0); } private void paintFretPoints(TGPainter painter, int fretIndex) { painter.setBackground(this.config.getColorFretPoint()); if ((fretIndex + 1) < this.frets.length) { int fret = ((fretIndex + 1) % 12); painter.setLineWidth(10); if (fret == 0) { int size = getOvalSize(); int x = this.frets[fretIndex] + ((this.frets[fretIndex + 1] - this.frets[fretIndex]) / 2); int y1 = this.strings[0] + ((this.strings[this.strings.length - 1] - this.strings[0]) / 2) - STRING_SPACING; int y2 = this.strings[0] + ((this.strings[this.strings.length - 1] - this.strings[0]) / 2) + STRING_SPACING; painter.initPath(TGPainter.PATH_FILL); painter.addOval(x - (size / 2), y1 - (size / 2), size, size); painter.addOval(x - (size / 2), y2 - (size / 2), size, size); painter.closePath(); } else if (fret == 3 || fret == 5 || fret == 7 || fret == 9) { int size = getOvalSize(); int x = this.frets[fretIndex] + ((this.frets[fretIndex + 1] - this.frets[fretIndex]) / 2); int y = this.strings[0] + ((this.strings[this.strings.length - 1] - this.strings[0]) / 2); painter.initPath(TGPainter.PATH_FILL); painter.addOval(x - (size / 2), y - (size / 2), size, size); painter.closePath(); } painter.setLineWidth(1); } } private void paintKeyOval(TGPainter painter, Color background, int x, int y) { int size = getOvalSize(); painter.setBackground(background); painter.initPath(TGPainter.PATH_FILL); painter.moveTo(x - (size / 2), y - (size / 2)); painter.addOval(x - (size / 2), y - (size / 2), size, size); painter.closePath(); } private void paintKeyText(TGPainter painter, Color foreground, int x, int y, String text) { painter.setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE)); painter.setForeground(foreground); painter.setFont(this.config.getFont()); Point size = painter.getStringExtent(text); painter.initPath(TGPainter.PATH_FILL); painter.addRectangle(x - (size.x / 2), y - (size.y / 2), size.x, size.y); painter.closePath(); painter.drawString(text, x - (size.x / 2), y - (size.y / 2), true); } private void paintNotes(TGPainter painter) { if (this.beat != null) { TGTrack track = getTrack(); for (int v = 0; v < this.beat.countVoices(); v++) { for (final TGNote note : this.beat.getVoice(v).getNotes()) { int fretIndex = note.getValue(); int stringIndex = note.getString() - 1; if (fretIndex >= 0 && fretIndex < this.frets.length && stringIndex >= 0 && stringIndex < this.strings.length) { int x = this.frets[fretIndex]; if (fretIndex > 0) { x -= ((this.frets[fretIndex] - this.frets[fretIndex - 1]) / 2); } int y = this.strings[stringIndex]; if ((this.config.getStyle() & FretBoardConfig.DISPLAY_TEXT_NOTE) != 0) { int realValue = track.getString(note.getString()).getValue() + note.getValue(); paintKeyText(painter, this.config.getColorNote(), x, y, NOTE_NAMES[(realValue % 12)]); } else { paintKeyOval(painter, this.config.getColorNote(), x, y); } } } } painter.setLineWidth(1); } } private void paintScale(TGPainter painter) { TGTrack track = getTrack(); for (int i = 0; i < this.strings.length; i++) { TGString string = track.getString(i + 1); for (int j = 0; j < this.frets.length; j++) { int noteIndex = ((string.getValue() + j) % 12); if (TuxGuitar.instance().getScaleManager().getScale() .getNote(noteIndex)) { int x = this.frets[j]; if (j > 0) { x -= ((x - this.frets[j - 1]) / 2); } int y = this.strings[i]; if ((this.config.getStyle() & FretBoardConfig.DISPLAY_TEXT_SCALE) != 0) { paintKeyText(painter, this.config.getColorScale(), x, y, NOTE_NAMES[noteIndex]); } else { paintKeyOval(painter, this.config.getColorScale(), x, y); } } } } painter.setForeground(this.config.getColorBackground()); } @Override public void redraw() { if (!super.isDisposed() && !TuxGuitar.instance().isLocked()) { super.redraw(); this.fretBoardComposite.redraw(); this.loadDurationImage(false); } } public void redrawPlayingMode() { if (!super.isDisposed() && !TuxGuitar.instance().isLocked()) { this.fretBoardComposite.redraw(); } } private boolean removeNote(int fret, int string) { 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.getValue() == fret && note.getString() == string) { // 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 updateDirection(int direction) { this.config.saveDirection(this.getDirection(direction)); this.initFrets(10); this.setChanges(true); this.fretBoardComposite.redraw(); } private void updateEditor() { if (isVisible()) { 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(); } if (this.strings.length != getStringCount()) { disposeFretBoardImage(); initStrings(getStringCount()); // Fuerzo a cambiar el ancho this.lastSize.y = 0; } int clientWidth = getClientArea().width; int clientHeight = getClientArea().height; if (this.lastSize.x != clientWidth || hasChanges()) { this.layout(getClientArea().width); } if (this.lastSize.y != clientHeight) { TuxGuitar.instance().getFretBoardEditor().showFretBoard(); } this.lastSize.x = clientWidth; this.lastSize.y = clientHeight; } } }