2
* Created on 28-dic-2005
4
* TODO To change the template for this generated file go to
5
* Window - Preferences - Java - Code Style - Code Templates
7
package org.herac.tuxguitar.gui.editors.fretboard;
9
import java.util.Iterator;
11
import org.eclipse.swt.SWT;
12
import org.eclipse.swt.events.MouseEvent;
13
import org.eclipse.swt.events.MouseListener;
14
import org.eclipse.swt.events.PaintEvent;
15
import org.eclipse.swt.events.PaintListener;
16
import org.eclipse.swt.events.SelectionAdapter;
17
import org.eclipse.swt.events.SelectionEvent;
18
import org.eclipse.swt.graphics.Color;
19
import org.eclipse.swt.graphics.GC;
20
import org.eclipse.swt.graphics.Image;
21
import org.eclipse.swt.graphics.Point;
22
import org.eclipse.swt.layout.FormAttachment;
23
import org.eclipse.swt.layout.FormData;
24
import org.eclipse.swt.layout.FormLayout;
25
import org.eclipse.swt.layout.GridData;
26
import org.eclipse.swt.layout.GridLayout;
27
import org.eclipse.swt.widgets.Button;
28
import org.eclipse.swt.widgets.Combo;
29
import org.eclipse.swt.widgets.Composite;
30
import org.eclipse.swt.widgets.Label;
31
import org.herac.tuxguitar.gui.TuxGuitar;
32
import org.herac.tuxguitar.gui.actions.ActionLock;
33
import org.herac.tuxguitar.gui.actions.caret.GoLeftAction;
34
import org.herac.tuxguitar.gui.actions.caret.GoRightAction;
35
import org.herac.tuxguitar.gui.actions.duration.DecrementDurationAction;
36
import org.herac.tuxguitar.gui.actions.duration.IncrementDurationAction;
37
import org.herac.tuxguitar.gui.actions.tools.ScaleAction;
38
import org.herac.tuxguitar.gui.editors.TGPainter;
39
import org.herac.tuxguitar.gui.editors.tab.Caret;
40
import org.herac.tuxguitar.gui.system.config.TGConfigKeys;
41
import org.herac.tuxguitar.gui.undo.undoables.measure.UndoableMeasureGeneric;
42
import org.herac.tuxguitar.gui.util.TGMusicKeyUtils;
43
import org.herac.tuxguitar.song.managers.TGSongManager;
44
import org.herac.tuxguitar.song.models.TGBeat;
45
import org.herac.tuxguitar.song.models.TGDuration;
46
import org.herac.tuxguitar.song.models.TGNote;
47
import org.herac.tuxguitar.song.models.TGString;
48
import org.herac.tuxguitar.song.models.TGTrack;
53
* TODO To change the template for this generated type comment go to Window - Preferences - Java - Code Style - Code Templates
55
public class FretBoard extends Composite {
57
public static final int MAX_FRETS = 24;
58
public static final int TOP_SPACING = 10;
59
public static final int BOTTOM_SPACING = 10;
61
private static final int STRING_SPACING = TuxGuitar.instance().getConfig().getIntConfigValue(TGConfigKeys.FRETBOARD_STRING_SPACING);
62
private static final String[] NOTE_NAMES = TGMusicKeyUtils.getSharpKeyNames(TGMusicKeyUtils.PREFIX_FRETBOARD);
64
private FretBoardListener listener;
65
private FretBoardConfig config;
66
private Composite toolComposite;
67
private Label durationLabel;
69
private Button settings;
70
private Image fretBoard;
71
//private List components;
76
private int[] strings;
77
private int fretSpacing;
78
private boolean changes;
79
private Point lastSize;
81
protected Combo handSelector;
82
protected Composite fretBoardComposite;
84
public FretBoard(Composite parent) {
85
super(parent, SWT.NONE);
86
this.setLayout(new FormLayout());
87
//this.components = new ArrayList();
88
this.listener = new FretBoardListener();
89
this.config = new FretBoardConfig();
95
TuxGuitar.instance().getkeyBindingManager().appendListenersTo(this.toolComposite);
96
TuxGuitar.instance().getkeyBindingManager().appendListenersTo(this.fretBoardComposite);
99
private void initToolBar() {
100
FormData data = new FormData();
101
data.left = new FormAttachment(0, 0);
102
data.right = new FormAttachment(100, 0);
103
data.top = new FormAttachment(0,0);
105
GridLayout layout = new GridLayout();
106
layout.makeColumnsEqualWidth = false;
107
layout.numColumns = 0;
108
layout.marginWidth = 0;
110
this.toolComposite = new Composite(this, SWT.NONE);
113
layout.numColumns ++;
114
Button goLeft = new Button(this.toolComposite, SWT.ARROW | SWT.LEFT);
115
goLeft.addSelectionListener(TuxGuitar.instance().getAction(GoLeftAction.NAME));
117
layout.numColumns ++;
118
Button goRight = new Button(this.toolComposite, SWT.ARROW | SWT.RIGHT);
119
goRight.addSelectionListener(TuxGuitar.instance().getAction(GoRightAction.NAME));
122
layout.numColumns ++;
123
makeToolSeparator(this.toolComposite);
126
layout.numColumns ++;
127
Button decrement = new Button(this.toolComposite, SWT.ARROW | SWT.MIN);
128
decrement.addSelectionListener(TuxGuitar.instance().getAction(DecrementDurationAction.NAME));
130
layout.numColumns ++;
131
this.durationLabel = new Label(this.toolComposite, SWT.BORDER);
133
layout.numColumns ++;
134
Button increment = new Button(this.toolComposite, SWT.ARROW | SWT.MAX);
135
increment.addSelectionListener(TuxGuitar.instance().getAction(IncrementDurationAction.NAME));
138
layout.numColumns ++;
139
makeToolSeparator(this.toolComposite);
142
layout.numColumns ++;
143
this.handSelector = new Combo(this.toolComposite, SWT.DROP_DOWN | SWT.READ_ONLY);
144
this.handSelector.add(TuxGuitar.getProperty("fretboard.right-mode"));
145
this.handSelector.add(TuxGuitar.getProperty("fretboard.left-mode"));
146
this.handSelector.select(0);
147
this.handSelector.addSelectionListener(new SelectionAdapter() {
148
public void widgetSelected(SelectionEvent e) {
149
int index = FretBoard.this.handSelector.getSelectionIndex();
156
FretBoard.this.fretBoardComposite.redraw();
161
layout.numColumns ++;
162
makeToolSeparator(this.toolComposite);
165
layout.numColumns ++;
166
this.scale = new Button(this.toolComposite, SWT.PUSH);
167
this.scale.setText(TuxGuitar.getProperty("scale"));
168
this.scale.addSelectionListener(TuxGuitar.instance().getAction(ScaleAction.NAME));
171
layout.numColumns ++;
172
this.settings = new Button(this.toolComposite, SWT.PUSH);
173
this.settings.setImage(TuxGuitar.instance().getIconManager().getSettings());
174
this.settings.setToolTipText(TuxGuitar.getProperty("settings"));
175
this.settings.setLayoutData(new GridData(SWT.RIGHT,SWT.FILL,true,true));
176
this.settings.addSelectionListener(new SelectionAdapter() {
177
public void widgetSelected(SelectionEvent e) {
182
this.toolComposite.setLayoutData(data);
183
this.toolComposite.setLayout(layout);
186
private void makeToolSeparator(Composite parent){
187
Label separator = new Label(parent,SWT.SEPARATOR);
188
separator.setLayoutData(new GridData(20,20));
191
private void initEditor() {
192
this.lastSize = new Point(0,0);
194
FormData data = new FormData();
195
data.left = new FormAttachment(0, 0);
196
data.right = new FormAttachment(100, 0);
197
data.top = new FormAttachment(this.toolComposite,0);
198
data.bottom = new FormAttachment(100, 0);
200
this.fretBoardComposite = new Composite(this, SWT.BORDER | SWT.DOUBLE_BUFFERED);
201
this.fretBoardComposite.setLayoutData(data);
202
this.fretBoardComposite.setBackground(this.config.getColorBackground());
203
this.fretBoardComposite.addMouseListener(this.listener);
204
this.fretBoardComposite.addPaintListener(this.listener);
207
private void loadDurationImage(boolean force) {
208
int duration = TuxGuitar.instance().getTablatureEditor().getTablature().getCaret().getDuration().getValue();
209
if(force || this.duration != duration){
210
this.duration = duration;
211
this.durationLabel.setImage(TuxGuitar.instance().getIconManager().getDuration(this.duration));
215
private void calculateFretSpacing(int width) {
216
this.fretSpacing = (width / MAX_FRETS);
218
for (int i = 0; i < MAX_FRETS; i++) {
221
this.fretSpacing += (aux / MAX_FRETS) + 2;
224
private void disposeFretBoardImage(){
225
if(this.fretBoard != null && !this.fretBoard.isDisposed()){
226
this.fretBoard.dispose();
230
protected void initFrets(int fromX, int hand) {
231
this.frets = new int[MAX_FRETS];
234
for (int i = 0; i < this.frets.length; i++) {
235
this.frets[i] = nextX;
236
nextX += (this.fretSpacing - ((i + 1) * 2));
238
} else if (hand == 2) {
239
for (int i = this.frets.length - 1; i >= 0; i--) {
240
this.frets[i] = nextX;
241
nextX += (this.fretSpacing - (i * 2));
246
private void initStrings(int count) {
247
int fromY = TOP_SPACING;
248
this.strings = new int[count];
250
for (int i = 0; i < this.strings.length; i++) {
251
this.strings[i] = fromY + (STRING_SPACING * i);
255
private void updateEditor(){
257
if(TuxGuitar.instance().getPlayer().isRunning()){
258
this.beat = TuxGuitar.instance().getEditorCache().getPlayBeat();
260
this.beat = TuxGuitar.instance().getEditorCache().getEditBeat();
263
if (this.strings.length != getStringCount()) {
264
disposeFretBoardImage();
265
initStrings(getStringCount());
266
//Fuerzo a cambiar el ancho
270
int clientWidth = getClientArea().width;
271
int clientHeight = getClientArea().height;
273
if(this.lastSize.x != clientWidth || hasChanges()){
274
this.layout(getClientArea().width,this.handSelector.getSelectionIndex() + 1);
277
if(this.lastSize.y != clientHeight){
278
TuxGuitar.instance().getFretBoardEditor().showFretBoard();
280
this.lastSize.x = clientWidth;
281
this.lastSize.y = clientHeight;
285
private void paintFretBoard(TGPainter painter){
286
if(this.fretBoard == null || this.fretBoard.isDisposed()){
287
this.fretBoard = new Image(getDisplay(),getClientArea().width,((STRING_SPACING) * (this.strings.length - 1)) + TOP_SPACING + BOTTOM_SPACING);
289
TGPainter painterBuffer = new TGPainter(new GC(this.fretBoard));
292
painterBuffer.setBackground(this.config.getColorBackground());
293
painterBuffer.initPath(TGPainter.PATH_FILL);
294
painterBuffer.addRectangle(getClientArea());
295
painterBuffer.closePath();
298
// pinto las cegillas
299
Image fretImage = TuxGuitar.instance().getIconManager().getFretboardFret();
300
Image firstFretImage = TuxGuitar.instance().getIconManager().getFretboardFirstFret();
302
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] );
304
paintFretPoints(painterBuffer,0);
305
for (int i = 1; i < this.frets.length; i++) {
306
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] );
307
paintFretPoints(painterBuffer, i);
311
for (int i = 0; i < this.strings.length; i++) {
312
painterBuffer.setForeground(this.config.getColorString());
314
painterBuffer.setLineWidth(2);
316
//painterBuffer.drawLine(this.frets[0], this.strings[i], this.frets[this.frets.length - 1], this.strings[i]);
317
painterBuffer.initPath();
318
painterBuffer.moveTo(this.frets[0], this.strings[i]);
319
painterBuffer.lineTo(this.frets[this.frets.length - 1], this.strings[i]);
320
painterBuffer.closePath();
324
paintScale(painterBuffer);
326
painterBuffer.dispose();
328
painter.drawImage(this.fretBoard,0,0);
331
private void paintFretPoints(TGPainter painter, int fretIndex) {
332
painter.setBackground(this.config.getColorFretPoint());
333
if ((fretIndex + 1) < this.frets.length) {
334
int fret = ((fretIndex + 1) % 12);
335
painter.setLineWidth(10);
337
int size = getOvalSize();
338
int x = this.frets[fretIndex] + ((this.frets[fretIndex + 1] - this.frets[fretIndex]) / 2);
339
int y1 = this.strings[0] + ((this.strings[this.strings.length - 1] - this.strings[0]) / 2) - STRING_SPACING;
340
int y2 = this.strings[0] + ((this.strings[this.strings.length - 1] - this.strings[0]) / 2) + STRING_SPACING;
341
painter.initPath(TGPainter.PATH_FILL);
342
painter.addOval(x - (size / 2), y1 - (size / 2), size, size);
343
painter.addOval(x - (size / 2), y2 - (size / 2), size, size);
345
} else if (fret == 3 || fret == 5 || fret == 7 || fret == 9) {
346
int size = getOvalSize();
347
int x = this.frets[fretIndex] + ((this.frets[fretIndex + 1] - this.frets[fretIndex]) / 2);
348
int y = this.strings[0] + ((this.strings[this.strings.length - 1] - this.strings[0]) / 2);
349
painter.initPath(TGPainter.PATH_FILL);
350
painter.addOval(x - (size / 2),y - (size / 2),size, size);
353
painter.setLineWidth(1);
357
private void paintScale(TGPainter painter) {
358
TGTrack track = TuxGuitar.instance().getTablatureEditor().getTablature().getCaret().getTrack();
360
for (int i = 0; i < this.strings.length; i++) {
361
TGString string = track.getString(i + 1);
362
for (int j = 0; j < this.frets.length; j++) {
364
int noteIndex = ((string.getValue() + j) % 12 );
365
if(TuxGuitar.instance().getScaleManager().getScale().getNote(noteIndex)){
366
int x = this.frets[j];
368
x -= ((x - this.frets[j - 1]) / 2);
370
int y = this.strings[i];
372
if( (this.config.getStyle() & FretBoardConfig.DISPLAY_TEXT_SCALE) != 0 ){
373
paintKeyText(painter,this.config.getColorScale(),x,y,NOTE_NAMES[noteIndex]);
376
paintKeyOval(painter,this.config.getColorScale(),x,y);
382
painter.setForeground(this.config.getColorBackground());
385
private void paintNotes(TGPainter painter) {
386
if(this.beat != null){
387
TGTrack track = TuxGuitar.instance().getTablatureEditor().getTablature().getCaret().getTrack();
389
Iterator it = this.beat.getNotes().iterator();
390
while (it.hasNext()) {
391
TGNote note = (TGNote) it.next();
392
int fretIndex = note.getValue();
393
int stringIndex = note.getString() - 1;
394
if (fretIndex >= 0 && fretIndex < this.frets.length && stringIndex >= 0 && stringIndex < this.strings.length) {
395
int x = this.frets[fretIndex];
397
x -= ((this.frets[fretIndex] - this.frets[fretIndex - 1]) / 2);
399
int y = this.strings[stringIndex];
401
if( (this.config.getStyle() & FretBoardConfig.DISPLAY_TEXT_NOTE) != 0 ){
402
int realValue = track.getString(note.getString()).getValue() + note.getValue();
403
paintKeyText(painter,this.config.getColorNote(), x, y, NOTE_NAMES[ (realValue % 12) ]);
406
paintKeyOval(painter,this.config.getColorNote(), x, y);
410
painter.setLineWidth(1);
414
private void paintKeyOval(TGPainter painter,Color background,int x, int y) {
415
int size = getOvalSize();
416
painter.setBackground(background);
417
painter.initPath(TGPainter.PATH_FILL);
418
painter.moveTo(x - (size / 2),y - (size / 2));
419
painter.addOval(x - (size / 2),y - (size / 2),size, size);
423
private void paintKeyText(TGPainter painter,Color foreground,int x, int y,String text) {
424
painter.setBackground(getDisplay().getSystemColor(SWT.COLOR_WHITE));
425
painter.setForeground(foreground);
426
painter.setFont(this.config.getFont());
427
Point size = painter.getStringExtent(text);
428
painter.initPath(TGPainter.PATH_FILL);
429
painter.addRectangle(x - (size.x / 2),y - (size.y / 2),size.x, size.y);
431
painter.drawString(text,x - (size.x / 2),y - (size.y / 2),true);
434
protected void paintEditor(TGPainter painter) {
435
if(!TuxGuitar.instance().isLocked()){
436
TuxGuitar.instance().lock();
438
if (this.frets.length > 0 && this.strings.length > 0) {
439
paintFretBoard(painter);
442
TuxGuitar.instance().unlock();
446
protected void hit(int x, int y) {
447
int fretIndex = getFretIndex(x);
448
int stringIndex = getStringIndex(y);
450
TuxGuitar.instance().getTablatureEditor().getTablature().getCaret().setStringNumber(stringIndex + 1);
451
if (!removeNote(fretIndex, stringIndex + 1)) {
452
addNote(fretIndex, stringIndex + 1);
456
private int getStringIndex(int y) {
458
for (int i = 0; i < this.strings.length; i++) {
462
int distanceY = Math.abs(y - this.strings[index]);
463
int currDistanceY = Math.abs(y - this.strings[i]);
464
if (currDistanceY < distanceY) {
472
private int getFretIndex(int x) {
473
int length = this.frets.length;
474
if ((x - 10) <= this.frets[0] && this.frets[0] < this.frets[length - 1]) {
477
if ((x + 10) >= this.frets[0] && this.frets[0] > this.frets[length - 1]) {
481
for (int i = 0; i < length; i++) {
482
if ((i + 1) < length) {
483
if (x > this.frets[i] && x <= this.frets[i + 1] || x > this.frets[i + 1] && x <= this.frets[i]) {
491
private boolean removeNote(int fret, int string) {
492
if(this.beat != null){
493
Iterator it = this.beat.getNotes().iterator();
494
while (it.hasNext()) {
495
TGNote note = (TGNote) it.next();
496
if (note.getValue() == fret && note.getString() == string) {
497
//comienza el undoable
498
UndoableMeasureGeneric undoable = UndoableMeasureGeneric.startUndo();
500
TGSongManager manager = TuxGuitar.instance().getSongManager();
501
manager.getMeasureManager().removeNote(note);
504
TuxGuitar.instance().getUndoableManager().addEdit(undoable.endUndo());
505
TuxGuitar.instance().getFileHistory().setUnsavedFile();
514
private int getStringCount() {
515
return TuxGuitar.instance().getTablatureEditor().getTablature().getCaret().getTrack().getStrings().size();
518
private int getOvalSize(){
519
return ((STRING_SPACING / 2) + (STRING_SPACING / 10));
522
private void addNote(int fret, int string) {
523
TGSongManager manager = TuxGuitar.instance().getSongManager();
525
//comienza el undoable
526
UndoableMeasureGeneric undoable = UndoableMeasureGeneric.startUndo();
528
Caret caret = TuxGuitar.instance().getTablatureEditor().getTablature().getCaret();
530
TGNote note = manager.getFactory().newNote();
532
note.setVelocity(caret.getVelocity());
533
note.setString(string);
535
TGDuration duration = manager.getFactory().newDuration();
536
caret.getDuration().copy(duration);
538
manager.getMeasureManager().addNote(caret.getMeasure(),caret.getPosition(),note,duration);
541
TuxGuitar.instance().getUndoableManager().addEdit(undoable.endUndo());
542
TuxGuitar.instance().getFileHistory().setUnsavedFile();
544
//reprodusco las notas en el pulso
545
caret.getSelectedBeat().play();
548
protected void afterAction() {
549
int measure = TuxGuitar.instance().getTablatureEditor().getTablature().getCaret().getMeasure().getNumber();
550
TuxGuitar.instance().getTablatureEditor().getTablature().getViewLayout().fireUpdate(measure);
551
TuxGuitar.instance().updateCache(true);
554
public boolean hasChanges(){
558
public void setChanges(boolean changes){
559
this.changes = changes;
562
public void redraw() {
563
if(!super.isDisposed() && !TuxGuitar.instance().isLocked()){
565
this.fretBoardComposite.redraw();
566
this.loadDurationImage(false);
570
public void redrawPlayingMode(){
571
if(!super.isDisposed() && !TuxGuitar.instance().isLocked()){
572
this.fretBoardComposite.redraw();
576
public void dispose(){
578
this.disposeFretBoardImage();
579
this.config.dispose();
582
public void loadProperties(){
583
int selection = this.handSelector.getSelectionIndex();
584
this.handSelector.removeAll();
585
this.handSelector.add(TuxGuitar.getProperty("fretboard.right-mode"));
586
this.handSelector.add(TuxGuitar.getProperty("fretboard.left-mode"));
587
this.handSelector.select(selection);
588
this.scale.setText(TuxGuitar.getProperty("scale"));
589
this.settings.setToolTipText(TuxGuitar.getProperty("settings"));
590
this.setChanges(true);
591
this.layout(true,true);
594
public void loadIcons(){
595
this.settings.setImage(TuxGuitar.instance().getIconManager().getSettings());
596
this.loadDurationImage(true);
597
this.layout(true,true);
598
this.layout(getClientArea().width,this.handSelector.getSelectionIndex() + 1);
601
public int getHeight(){
602
int borderWidth = (2 * this.fretBoardComposite.getBorderWidth());
603
int toolBarHeight = (this.toolComposite.getBounds().height);
604
int fretBoardHeight = (((STRING_SPACING) * (this.strings.length - 1)) + TOP_SPACING + BOTTOM_SPACING);
605
return (borderWidth + toolBarHeight + fretBoardHeight);
608
public int getWidth(){
609
return this.frets[this.frets.length - 1];
612
public void layout(){
616
public void layout(int width,int hand){
617
this.disposeFretBoardImage();
618
this.calculateFretSpacing(width);
619
this.initFrets(10,hand);
620
this.initStrings(getStringCount());
621
this.setChanges(false);
624
protected void configure(){
625
this.config.configure(getShell());
626
this.setChanges(true);
630
public Composite getFretBoardComposite(){
631
return this.fretBoardComposite;
634
private class FretBoardListener implements PaintListener,MouseListener {
636
public FretBoardListener(){
640
public void paintControl(PaintEvent e) {
641
TGPainter painter = new TGPainter(e.gc);
642
paintEditor(painter);
645
public void mouseUp(MouseEvent e) {
646
getFretBoardComposite().setFocus();
648
if(!TuxGuitar.instance().getPlayer().isRunning() && !TuxGuitar.instance().isLocked() && !ActionLock.isLocked()){
655
TuxGuitar.instance().getAction(GoRightAction.NAME).process(e);
659
public void mouseDown(MouseEvent e) {
663
public void mouseDoubleClick(MouseEvent e) {