1 package org.herac.tuxguitar.gui.editors.matrix; 2 3 import java.util.Iterator; 4 import java.util.List; 5 6 import org.eclipse.swt.SWT; 7 import org.eclipse.swt.events.DisposeEvent; 8 import org.eclipse.swt.events.DisposeListener; 9 import org.eclipse.swt.events.MouseEvent; 10 import org.eclipse.swt.events.MouseListener; 11 import org.eclipse.swt.events.MouseMoveListener; 12 import org.eclipse.swt.events.MouseTrackListener; 13 import org.eclipse.swt.events.PaintEvent; 14 import org.eclipse.swt.events.PaintListener; 15 import org.eclipse.swt.events.SelectionAdapter; 16 import org.eclipse.swt.events.SelectionEvent; 17 import org.eclipse.swt.graphics.GC; 18 import org.eclipse.swt.graphics.Image; 19 import org.eclipse.swt.graphics.Point; 20 import org.eclipse.swt.graphics.Rectangle; 21 import org.eclipse.swt.graphics.Resource; 22 import org.eclipse.swt.layout.FillLayout; 23 import org.eclipse.swt.layout.GridData; 24 import org.eclipse.swt.layout.GridLayout; 25 import org.eclipse.swt.widgets.Button; 26 import org.eclipse.swt.widgets.Combo; 27 import org.eclipse.swt.widgets.Composite; 28 import org.eclipse.swt.widgets.Event; 29 import org.eclipse.swt.widgets.Label; 30 import org.eclipse.swt.widgets.Listener; 31 import org.eclipse.swt.widgets.ScrollBar; 32 import org.eclipse.swt.widgets.Shell; 33 import org.herac.tuxguitar.gui.TuxGuitar; 34 import org.herac.tuxguitar.gui.actions.ActionLock; 35 import org.herac.tuxguitar.gui.actions.caret.GoLeftAction; 36 import org.herac.tuxguitar.gui.actions.caret.GoRightAction; 37 import org.herac.tuxguitar.gui.actions.duration.DecrementDurationAction; 38 import org.herac.tuxguitar.gui.actions.duration.IncrementDurationAction; 39 import org.herac.tuxguitar.gui.editors.TGPainter; 40 import org.herac.tuxguitar.gui.editors.TGRedrawListener; 41 import org.herac.tuxguitar.gui.editors.tab.Caret; 42 import org.herac.tuxguitar.gui.editors.tab.TGNoteImpl; 43 import org.herac.tuxguitar.gui.system.config.TGConfigKeys; 44 import org.herac.tuxguitar.gui.system.icons.IconLoader; 45 import org.herac.tuxguitar.gui.system.language.LanguageLoader; 46 import org.herac.tuxguitar.gui.undo.undoables.measure.UndoableMeasureGeneric; 47 import org.herac.tuxguitar.gui.util.DialogUtils; 48 import org.herac.tuxguitar.gui.util.TGMusicKeyUtils; 49 import org.herac.tuxguitar.player.base.MidiPercussion; 50 import org.herac.tuxguitar.song.managers.TGSongManager; 51 import org.herac.tuxguitar.song.models.TGBeat; 52 import org.herac.tuxguitar.song.models.TGChannel; 53 import org.herac.tuxguitar.song.models.TGDuration; 54 import org.herac.tuxguitar.song.models.TGMeasure; 55 import org.herac.tuxguitar.song.models.TGNote; 56 import org.herac.tuxguitar.song.models.TGString; 57 import org.herac.tuxguitar.song.models.TGTrack; 58 import org.herac.tuxguitar.song.models.TGVelocities; 59 import org.herac.tuxguitar.song.models.TGVoice; 60 61 public class MatrixEditor implements TGRedrawListener,IconLoader,LanguageLoader{ 62 63 private static final int BORDER_HEIGHT = 20; 64 private static final int SCROLL_INCREMENT = 50; 65 private static final String[] NOTE_NAMES = TGMusicKeyUtils.getSharpKeyNames(TGMusicKeyUtils.PREFIX_MATRIX); 66 private static final MidiPercussion[] PERCUSSIONS = TuxGuitar.instance().getPlayer().getPercussions(); 67 protected static final int[] DIVISIONS = new int[] {1,2,3,4,6,8,16}; 68 69 private MatrixConfig config; 70 private MatrixListener listener; 71 private Shell dialog; 72 private Composite composite; 73 private Composite toolbar; 74 private Composite editor; 75 private Rectangle clientArea; 76 private Image buffer; 77 private BufferDisposer bufferDisposer; 78 private Label durationLabel; 79 private Label gridsLabel; 80 private Button settings; 81 private float width; 82 private float height; 83 private float bufferWidth; 84 private float bufferHeight; 85 private float timeWidth; 86 private float lineHeight; 87 private int leftSpacing; 88 private int minNote; 89 private int maxNote; 90 private int duration; 91 private int selection; 92 private int grids; 93 private int playedTrack; 94 private int playedMeasure; 95 private TGBeat playedBeat; 96 97 private Image selectionBackBuffer; 98 private int selectionX; 99 private int selectionY; 100 101 private boolean selectionPaintDisabled; 102 MatrixEditor()103 public MatrixEditor(){ 104 this.grids = this.loadGrids(); 105 this.listener = new MatrixListener(); 106 } 107 show()108 public void show(){ 109 this.config = new MatrixConfig(); 110 this.config.load(); 111 112 this.dialog = DialogUtils.newDialog(TuxGuitar.instance().getShell(),SWT.DIALOG_TRIM | SWT.RESIZE); 113 this.dialog.setText(TuxGuitar.getProperty("matrix.editor")); 114 this.dialog.setImage(TuxGuitar.instance().getIconManager().getAppIcon()); 115 this.dialog.setLayout(new GridLayout()); 116 this.dialog.addDisposeListener(new DisposeListenerImpl()); 117 this.bufferDisposer = new BufferDisposer(); 118 119 this.composite = new Composite(this.dialog,SWT.NONE); 120 this.composite.setLayout(new GridLayout()); 121 this.composite.setLayoutData(new GridData(SWT.FILL,SWT.FILL,true,true)); 122 123 this.initToolBar(); 124 this.initEditor(); 125 this.loadIcons(); 126 127 this.addListeners(); 128 this.dialog.addDisposeListener(new DisposeListener() { 129 public void widgetDisposed(DisposeEvent e) { 130 removeListeners(); 131 TuxGuitar.instance().updateCache(true); 132 } 133 }); 134 DialogUtils.openDialog(this.dialog,DialogUtils.OPEN_STYLE_CENTER); 135 } 136 addListeners()137 public void addListeners(){ 138 TuxGuitar.instance().getkeyBindingManager().appendListenersTo(this.toolbar); 139 TuxGuitar.instance().getkeyBindingManager().appendListenersTo(this.editor); 140 TuxGuitar.instance().getIconManager().addLoader(this); 141 TuxGuitar.instance().getLanguageManager().addLoader(this); 142 TuxGuitar.instance().getEditorManager().addRedrawListener( this ); 143 } 144 removeListeners()145 public void removeListeners(){ 146 TuxGuitar.instance().getIconManager().removeLoader(this); 147 TuxGuitar.instance().getLanguageManager().removeLoader(this); 148 TuxGuitar.instance().getEditorManager().removeRedrawListener( this ); 149 } 150 initToolBar()151 private void initToolBar() { 152 GridLayout layout = new GridLayout(); 153 layout.makeColumnsEqualWidth = false; 154 layout.numColumns = 0; 155 layout.marginWidth = 0; 156 layout.marginHeight = 0; 157 158 this.toolbar = new Composite(this.composite, SWT.NONE); 159 160 // position 161 layout.numColumns ++; 162 Button goLeft = new Button(this.toolbar, SWT.ARROW | SWT.LEFT); 163 goLeft.addSelectionListener(TuxGuitar.instance().getAction(GoLeftAction.NAME)); 164 165 layout.numColumns ++; 166 Button goRight = new Button(this.toolbar, SWT.ARROW | SWT.RIGHT); 167 goRight.addSelectionListener(TuxGuitar.instance().getAction(GoRightAction.NAME)); 168 169 // separator 170 layout.numColumns ++; 171 makeToolSeparator(this.toolbar); 172 173 // duration 174 layout.numColumns ++; 175 Button decrement = new Button(this.toolbar, SWT.ARROW | SWT.MIN); 176 decrement.addSelectionListener(TuxGuitar.instance().getAction(DecrementDurationAction.NAME)); 177 178 layout.numColumns ++; 179 this.durationLabel = new Label(this.toolbar, SWT.BORDER); 180 181 layout.numColumns ++; 182 Button increment = new Button(this.toolbar, SWT.ARROW | SWT.MAX); 183 increment.addSelectionListener(TuxGuitar.instance().getAction(IncrementDurationAction.NAME)); 184 185 // separator 186 layout.numColumns ++; 187 makeToolSeparator(this.toolbar); 188 189 // grids 190 layout.numColumns ++; 191 this.gridsLabel = new Label(this.toolbar,SWT.NONE); 192 this.gridsLabel.setText(TuxGuitar.getProperty("matrix.grids")); 193 194 layout.numColumns ++; 195 final Combo divisionsCombo = new Combo(this.toolbar, SWT.DROP_DOWN | SWT.READ_ONLY); 196 divisionsCombo.setLayoutData(new GridData(SWT.FILL,SWT.CENTER,false, true)); 197 for(int i = 0; i < DIVISIONS.length; i ++){ 198 divisionsCombo.add(Integer.toString(DIVISIONS[i])); 199 if(this.grids == DIVISIONS[i]){ 200 divisionsCombo.select(i); 201 } 202 } 203 if(this.grids == 0){ 204 divisionsCombo.select(0); 205 } 206 divisionsCombo.addSelectionListener(new SelectionAdapter() { 207 public void widgetSelected(SelectionEvent e) { 208 int index = divisionsCombo.getSelectionIndex(); 209 if(index >= 0 && index < DIVISIONS.length){ 210 setGrids(DIVISIONS[index]); 211 } 212 } 213 }); 214 215 // settings 216 layout.numColumns ++; 217 this.settings = new Button(this.toolbar, SWT.PUSH); 218 this.settings.setImage(TuxGuitar.instance().getIconManager().getSettings()); 219 this.settings.setToolTipText(TuxGuitar.getProperty("settings")); 220 this.settings.setLayoutData(new GridData(SWT.RIGHT,SWT.FILL,true,true)); 221 this.settings.addSelectionListener(new SelectionAdapter() { 222 public void widgetSelected(SelectionEvent e) { 223 configure(); 224 } 225 }); 226 227 this.toolbar.setLayout(layout); 228 this.toolbar.setLayoutData(new GridData(SWT.FILL,SWT.TOP,true,false)); 229 } 230 makeToolSeparator(Composite parent)231 private void makeToolSeparator(Composite parent){ 232 Label separator = new Label(parent,SWT.SEPARATOR); 233 separator.setLayoutData(new GridData(20,20)); 234 } 235 loadDurationImage(boolean force)236 private void loadDurationImage(boolean force) { 237 int duration = TuxGuitar.instance().getTablatureEditor().getTablature().getCaret().getDuration().getValue(); 238 if(force || this.duration != duration){ 239 this.duration = duration; 240 this.durationLabel.setImage(TuxGuitar.instance().getIconManager().getDuration(this.duration)); 241 } 242 } 243 initEditor()244 public void initEditor(){ 245 this.selection = -1; 246 this.editor = new Composite(this.composite,SWT.DOUBLE_BUFFERED | SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL); 247 this.editor.setLayoutData(new GridData(SWT.FILL,SWT.FILL,true,true)); 248 this.editor.setLayout(new FillLayout()); 249 this.editor.setFocus(); 250 this.editor.addPaintListener(this.listener); 251 this.editor.addMouseListener(this.listener); 252 this.editor.addMouseMoveListener(this.listener); 253 this.editor.addMouseTrackListener(this.listener); 254 this.editor.getHorizontalBar().setIncrement(SCROLL_INCREMENT); 255 this.editor.getHorizontalBar().addListener(SWT.Selection, new Listener() { 256 public void handleEvent(Event event) { 257 redrawLocked(); 258 } 259 }); 260 this.editor.getVerticalBar().setIncrement(SCROLL_INCREMENT); 261 this.editor.getVerticalBar().addListener(SWT.Selection, new Listener() { 262 public void handleEvent(Event event) { 263 redrawLocked(); 264 } 265 }); 266 } 267 updateScroll()268 protected void updateScroll(){ 269 if( this.clientArea != null ){ 270 int borderWidth = this.editor.getBorderWidth(); 271 ScrollBar vBar = this.editor.getVerticalBar(); 272 ScrollBar hBar = this.editor.getHorizontalBar(); 273 vBar.setMaximum(Math.round(this.height + (borderWidth * 2))); 274 vBar.setThumb(Math.round(Math.min(this.height + (borderWidth * 2), this.clientArea.height))); 275 hBar.setMaximum(Math.round(this.width + (borderWidth * 2))); 276 hBar.setThumb(Math.round(Math.min(this.width + (borderWidth * 2), this.clientArea.width))); 277 } 278 } 279 getValueAt(float y)280 protected int getValueAt(float y){ 281 if(this.clientArea == null || (y - BORDER_HEIGHT) < 0 || y + BORDER_HEIGHT > this.clientArea.height){ 282 return -1; 283 } 284 int scroll = this.editor.getVerticalBar().getSelection(); 285 int value = (this.maxNote - ((int)( (y + scroll - BORDER_HEIGHT) / this.lineHeight)) ); 286 return value; 287 } 288 getStartAt(float x)289 protected long getStartAt(float x){ 290 TGMeasure measure = getMeasure(); 291 float posX = (x + this.editor.getHorizontalBar().getSelection()); 292 long start =(long) (measure.getStart() + (((posX - this.leftSpacing) * measure.getLength()) / (this.timeWidth * measure.getTimeSignature().getNumerator()))); 293 return start; 294 } 295 paintEditor(TGPainter painter)296 protected void paintEditor(TGPainter painter){ 297 if(!TuxGuitar.instance().getPlayer().isRunning()){ 298 this.resetPlayed(); 299 } 300 301 this.disposeSelectionBuffer(); 302 this.clientArea = this.editor.getClientArea(); 303 304 if( this.clientArea != null ){ 305 Image buffer = getBuffer(); 306 307 this.width = this.bufferWidth; 308 this.height = (this.bufferHeight + (BORDER_HEIGHT *2)); 309 310 this.updateScroll(); 311 int scrollX = this.editor.getHorizontalBar().getSelection(); 312 int scrollY = this.editor.getVerticalBar().getSelection(); 313 314 painter.drawImage(buffer,-scrollX,(BORDER_HEIGHT - scrollY)); 315 this.paintMeasure(painter,(-scrollX), (BORDER_HEIGHT - scrollY) ); 316 this.paintBorders(painter,(-scrollX),0); 317 this.paintPosition(painter,(-scrollX),0); 318 319 this.paintSelection(painter, (-scrollX), (BORDER_HEIGHT - scrollY) ); 320 } 321 } 322 getBuffer()323 protected Image getBuffer(){ 324 if( this.clientArea != null ){ 325 this.bufferDisposer.update(this.clientArea.width, this.clientArea.height); 326 if(this.buffer == null || this.buffer.isDisposed()){ 327 String[] names = null; 328 TGMeasure measure = getMeasure(); 329 boolean percussion = measure.getTrack().isPercussionTrack(); 330 this.maxNote = 0; 331 this.minNote = 127; 332 if(percussion){ 333 names = new String[PERCUSSIONS.length]; 334 for(int i = 0; i < names.length;i ++){ 335 this.minNote = Math.min(this.minNote,PERCUSSIONS[i].getValue()); 336 this.maxNote = Math.max(this.maxNote,PERCUSSIONS[i].getValue()); 337 names[i] = PERCUSSIONS[names.length - i -1].getName(); 338 } 339 }else{ 340 for(int sNumber = 1; sNumber <= measure.getTrack().stringCount();sNumber ++){ 341 TGString string = measure.getTrack().getString(sNumber); 342 this.minNote = Math.min(this.minNote,string.getValue()); 343 this.maxNote = Math.max(this.maxNote,(string.getValue() + 20)); 344 } 345 names = new String[this.maxNote - this.minNote + 1]; 346 for(int i = 0; i < names.length;i ++){ 347 names[i] = (NOTE_NAMES[ (this.maxNote - i) % 12] + ((this.maxNote - i) / 12 ) ); 348 } 349 } 350 351 int minimumNameWidth = 110; 352 int minimumNameHeight = 0; 353 TGPainter painter = new TGPainter(new GC(this.dialog.getDisplay())); 354 painter.setFont(this.config.getFont()); 355 for(int i = 0; i < names.length;i ++){ 356 Point size = painter.getStringExtent(names[i]); 357 if( size.x > minimumNameWidth ){ 358 minimumNameWidth = size.x; 359 } 360 if( size.y > minimumNameHeight ){ 361 minimumNameHeight = size.y ; 362 } 363 } 364 painter.dispose(); 365 366 int cols = measure.getTimeSignature().getNumerator(); 367 int rows = (this.maxNote - this.minNote); 368 369 this.leftSpacing = minimumNameWidth + 10; 370 this.lineHeight = Math.max(minimumNameHeight,( (this.clientArea.height - (BORDER_HEIGHT * 2.0f))/ (rows + 1.0f))); 371 this.timeWidth = Math.max((10 * (TGDuration.SIXTY_FOURTH / measure.getTimeSignature().getDenominator().getValue())),( (this.clientArea.width-this.leftSpacing) / cols) ); 372 this.bufferWidth = this.leftSpacing + (this.timeWidth * cols); 373 this.bufferHeight = (this.lineHeight * (rows + 1)); 374 this.buffer = new Image(this.editor.getDisplay(),Math.round( this.bufferWidth),Math.round(this.bufferHeight)); 375 376 painter = new TGPainter(new GC(this.buffer)); 377 painter.setFont(this.config.getFont()); 378 painter.setForeground(this.config.getColorForeground()); 379 for(int i = 0; i <= rows; i++){ 380 painter.setBackground(this.config.getColorLine( i % 2 ) ); 381 painter.initPath(TGPainter.PATH_FILL); 382 painter.setAntialias(false); 383 painter.addRectangle(0 ,(i * this.lineHeight),this.bufferWidth ,this.lineHeight); 384 painter.closePath(); 385 painter.drawString(names[i],5,( Math.round( (i * this.lineHeight) ) + Math.round( (this.lineHeight - minimumNameHeight) / 2 ) ) ); 386 } 387 for(int i = 0; i < cols; i ++){ 388 float colX = this.leftSpacing + (i * this.timeWidth); 389 float divisionWidth = ( this.timeWidth / this.grids ); 390 for( int j = 0; j < this.grids; j ++ ){ 391 painter.setLineStyle( j == 0 ? SWT.LINE_SOLID : SWT.LINE_DOT); 392 painter.initPath(); 393 painter.setAntialias(false); 394 painter.moveTo(Math.round( colX + (j * divisionWidth) ),0); 395 painter.lineTo(Math.round( colX + (j * divisionWidth) ),this.bufferHeight); 396 painter.closePath(); 397 } 398 } 399 painter.dispose(); 400 } 401 } 402 return this.buffer; 403 } 404 paintMeasure(TGPainter painter,float fromX, float fromY)405 protected void paintMeasure(TGPainter painter,float fromX, float fromY){ 406 if( this.clientArea != null ){ 407 TGMeasure measure = getMeasure(); 408 if(measure != null){ 409 Iterator it = measure.getBeats().iterator(); 410 while(it.hasNext()){ 411 TGBeat beat = (TGBeat)it.next(); 412 paintBeat(painter, measure, beat, fromX, fromY); 413 } 414 } 415 } 416 } 417 paintBeat(TGPainter painter,TGMeasure measure,TGBeat beat,float fromX, float fromY)418 protected void paintBeat(TGPainter painter,TGMeasure measure,TGBeat beat,float fromX, float fromY){ 419 if( this.clientArea != null ){ 420 int minimumY = BORDER_HEIGHT; 421 int maximumY = (this.clientArea.height - BORDER_HEIGHT); 422 423 for( int v = 0; v < beat.countVoices(); v ++ ){ 424 TGVoice voice = beat.getVoice(v); 425 for( int i = 0 ; i < voice.countNotes() ; i ++){ 426 TGNoteImpl note = (TGNoteImpl)voice.getNote(i); 427 float x1 = (fromX + this.leftSpacing + (((beat.getStart() - measure.getStart()) * (this.timeWidth * measure.getTimeSignature().getNumerator())) / measure.getLength()) + 1); 428 float y1 = (fromY + (((this.maxNote - this.minNote) - (note.getRealValue() - this.minNote)) * this.lineHeight) + 1 ); 429 float x2 = (x1 + ((voice.getDuration().getTime() * this.timeWidth) / measure.getTimeSignature().getDenominator().getTime()) - 2 ); 430 float y2 = (y1 + this.lineHeight - 2 ); 431 432 if( y1 >= maximumY || y2 <= minimumY){ 433 continue; 434 } 435 436 y1 = ( y1 < minimumY ? minimumY : y1 ); 437 y2 = ( y2 > maximumY ? maximumY : y2 ); 438 439 if((x2 - x1) > 0 && (y2 - y1) > 0){ 440 painter.setBackground( (note.getBeatImpl().isPlaying(TuxGuitar.instance().getTablatureEditor().getTablature().getViewLayout()) ? this.config.getColorPlay():this.config.getColorNote() ) ); 441 painter.initPath(TGPainter.PATH_FILL); 442 painter.setAntialias(false); 443 painter.addRectangle(x1,y1, (x2 - x1), (y2 - y1)); 444 painter.closePath(); 445 } 446 } 447 } 448 } 449 } 450 paintBorders(TGPainter painter,float fromX, float fromY)451 protected void paintBorders(TGPainter painter,float fromX, float fromY){ 452 if( this.clientArea != null ){ 453 painter.setBackground(this.config.getColorBorder()); 454 painter.initPath(TGPainter.PATH_FILL); 455 painter.setAntialias(false); 456 painter.addRectangle(fromX,fromY,this.bufferWidth ,BORDER_HEIGHT); 457 painter.addRectangle(fromX,fromY + (this.clientArea.height - BORDER_HEIGHT),this.bufferWidth ,BORDER_HEIGHT); 458 painter.closePath(); 459 460 painter.initPath(); 461 painter.setAntialias(false); 462 painter.addRectangle(fromX,fromY,this.width,this.clientArea.height); 463 painter.closePath(); 464 } 465 } 466 paintPosition(TGPainter painter,float fromX, float fromY)467 protected void paintPosition(TGPainter painter,float fromX, float fromY){ 468 if( this.clientArea != null && !TuxGuitar.instance().getPlayer().isRunning()){ 469 Caret caret = getCaret(); 470 TGMeasure measure = getMeasure(); 471 TGBeat beat = caret.getSelectedBeat(); 472 if(beat != null){ 473 float x = (((beat.getStart() - measure.getStart()) * (this.timeWidth * measure.getTimeSignature().getNumerator())) / measure.getLength()); 474 float width = ((beat.getVoice(caret.getVoice()).getDuration().getTime() * this.timeWidth) / measure.getTimeSignature().getDenominator().getTime()); 475 painter.setBackground(this.config.getColorPosition()); 476 painter.initPath(TGPainter.PATH_FILL); 477 painter.setAntialias(false); 478 painter.addRectangle(fromX + (this.leftSpacing + x),fromY , width,BORDER_HEIGHT); 479 painter.closePath(); 480 481 painter.initPath(TGPainter.PATH_FILL); 482 painter.setAntialias(false); 483 painter.addRectangle(fromX + (this.leftSpacing + x),fromY + (this.clientArea.height - BORDER_HEIGHT), width,BORDER_HEIGHT); 484 painter.closePath(); 485 } 486 } 487 } 488 paintSelection(TGPainter painter, float fromX, float fromY)489 protected void paintSelection(TGPainter painter, float fromX, float fromY){ 490 if( !this.selectionPaintDisabled && this.clientArea != null && !TuxGuitar.instance().getPlayer().isRunning()){ 491 selectionFinish(); 492 if(this.selection >= 0){ 493 this.selectionPaintDisabled = true; 494 495 int x = Math.round( fromX ); 496 int y = Math.round( fromY + ((this.maxNote - this.selection) * this.lineHeight) ); 497 int width = Math.round( this.bufferWidth ); 498 int height = Math.round( this.lineHeight ); 499 500 Image selectionArea = new Image(this.editor.getDisplay(),width,height); 501 painter.copyArea(selectionArea,x,y); 502 painter.setAlpha(100); 503 painter.setBackground(this.config.getColorLine(2)); 504 painter.initPath(TGPainter.PATH_FILL); 505 painter.setAntialias(false); 506 painter.addRectangle(x,y,width,height); 507 painter.closePath(); 508 509 this.selectionX = x; 510 this.selectionY = y; 511 this.selectionBackBuffer = selectionArea; 512 this.selectionPaintDisabled = false; 513 } 514 } 515 } 516 updateSelection(float y)517 protected void updateSelection(float y){ 518 if(!TuxGuitar.instance().getPlayer().isRunning()){ 519 int selection = getValueAt(y); 520 521 if(this.selection != selection){ 522 this.selection = selection; 523 524 int scrollX = this.editor.getHorizontalBar().getSelection(); 525 int scrollY = this.editor.getVerticalBar().getSelection(); 526 527 TGPainter painter = new TGPainter(new GC(this.editor)); 528 this.paintSelection(painter, (-scrollX), (BORDER_HEIGHT - scrollY) ); 529 painter.dispose(); 530 } 531 } 532 } 533 selectionFinish()534 public void selectionFinish(){ 535 if(this.selectionBackBuffer != null && !this.selectionBackBuffer.isDisposed()){ 536 TGPainter painter = new TGPainter(new GC(this.editor)); 537 painter.drawImage(this.selectionBackBuffer,this.selectionX, this.selectionY); 538 painter.dispose(); 539 } 540 disposeSelectionBuffer(); 541 } 542 disposeSelectionBuffer()543 protected void disposeSelectionBuffer(){ 544 if(this.selectionBackBuffer != null && !this.selectionBackBuffer.isDisposed()){ 545 this.selectionBackBuffer.dispose(); 546 this.selectionBackBuffer = null; 547 } 548 } 549 hit(float x, float y)550 protected void hit(float x, float y){ 551 if(!TuxGuitar.instance().getPlayer().isRunning()){ 552 TGMeasure measure = getMeasure(); 553 Caret caret = getCaret(); 554 int value = getValueAt(y); 555 long start = getStartAt(x); 556 557 if(start >= measure.getStart() && start < (measure.getStart() + measure.getLength())){ 558 caret.update(caret.getTrack().getNumber(),start,caret.getStringNumber()); 559 TuxGuitar.instance().updateCache(true); 560 } 561 if(value >= this.minNote || value <= this.maxNote){ 562 if(start >= measure.getStart()){ 563 TGVoice voice = TuxGuitar.instance().getSongManager().getMeasureManager().getVoiceIn(measure, start, caret.getVoice()); 564 if( voice != null ){ 565 if(!removeNote(voice.getBeat(), value)){ 566 addNote(voice.getBeat(), start, value); 567 } 568 } 569 }else{ 570 play(value); 571 } 572 } 573 } 574 } 575 removeNote(TGBeat beat,int value)576 private boolean removeNote(TGBeat beat,int value) { 577 Caret caret = TuxGuitar.instance().getTablatureEditor().getTablature().getCaret(); 578 TGMeasure measure = getMeasure(); 579 580 for(int v = 0; v < beat.countVoices(); v ++){ 581 TGVoice voice = beat.getVoice( v ); 582 Iterator it = voice.getNotes().iterator(); 583 while (it.hasNext()) { 584 TGNoteImpl note = (TGNoteImpl) it.next(); 585 if (note.getRealValue() == value) { 586 caret.update(measure.getTrack().getNumber(),beat.getStart(),note.getString()); 587 588 //comienza el undoable 589 UndoableMeasureGeneric undoable = UndoableMeasureGeneric.startUndo(); 590 591 TGSongManager manager = TuxGuitar.instance().getSongManager(); 592 manager.getMeasureManager().removeNote(note); 593 594 //termia el undoable 595 TuxGuitar.instance().getUndoableManager().addEdit(undoable.endUndo()); 596 TuxGuitar.instance().getFileHistory().setUnsavedFile(); 597 598 this.afterAction(); 599 600 return true; 601 } 602 } 603 } 604 return false; 605 } 606 addNote(TGBeat beat,long start, int value)607 private boolean addNote(TGBeat beat,long start, int value) { 608 if(beat != null){ 609 TGMeasure measure = getMeasure(); 610 Caret caret = TuxGuitar.instance().getTablatureEditor().getTablature().getCaret(); 611 612 List strings = measure.getTrack().getStrings(); 613 for(int i = 0;i < strings.size();i ++){ 614 TGString string = (TGString)strings.get(i); 615 if(value >= string.getValue()){ 616 boolean emptyString = true; 617 618 for(int v = 0; v < beat.countVoices(); v ++){ 619 TGVoice voice = beat.getVoice( v ); 620 Iterator it = voice.getNotes().iterator(); 621 while (it.hasNext()) { 622 TGNoteImpl note = (TGNoteImpl) it.next(); 623 if (note.getString() == string.getNumber()) { 624 emptyString = false; 625 break; 626 } 627 } 628 } 629 if(emptyString){ 630 TGSongManager manager = TuxGuitar.instance().getSongManager(); 631 632 //comienza el undoable 633 UndoableMeasureGeneric undoable = UndoableMeasureGeneric.startUndo(); 634 635 TGNote note = manager.getFactory().newNote(); 636 note.setValue((value - string.getValue())); 637 note.setVelocity(caret.getVelocity()); 638 note.setString(string.getNumber()); 639 640 TGDuration duration = manager.getFactory().newDuration(); 641 caret.getDuration().copy(duration); 642 643 manager.getMeasureManager().addNote(beat,note,duration,start,caret.getVoice()); 644 645 caret.moveTo(caret.getTrack(),caret.getMeasure(),note.getVoice().getBeat(),note.getString()); 646 647 //termia el undoable 648 TuxGuitar.instance().getUndoableManager().addEdit(undoable.endUndo()); 649 TuxGuitar.instance().getFileHistory().setUnsavedFile(); 650 651 //reprodusco las notas en el pulso 652 caret.getSelectedBeat().play(); 653 654 this.afterAction(); 655 656 return true; 657 } 658 } 659 } 660 } 661 return false; 662 } 663 afterAction()664 protected void afterAction() { 665 TuxGuitar.instance().getTablatureEditor().getTablature().getViewLayout().fireUpdate(getMeasure().getNumber()); 666 TuxGuitar.instance().updateCache(true); 667 this.editor.redraw(); 668 } 669 play(final int value)670 protected void play(final int value){ 671 new Thread(new Runnable() { 672 public void run() { 673 TGTrack track = getMeasure().getTrack(); 674 int volume = TGChannel.DEFAULT_VOLUME; 675 int balance = TGChannel.DEFAULT_BALANCE; 676 int chorus = track.getChannel().getChorus(); 677 int reverb = track.getChannel().getReverb(); 678 int phaser = track.getChannel().getPhaser(); 679 int tremolo = track.getChannel().getTremolo(); 680 int channel = track.getChannel().getChannel(); 681 int program = track.getChannel().getInstrument(); 682 int[][] beat = new int[][]{ new int[]{ (track.getOffset() + value) , TGVelocities.DEFAULT } }; 683 TuxGuitar.instance().getPlayer().playBeat(channel,program, volume, balance,chorus,reverb,phaser,tremolo,beat); 684 } 685 }).start(); 686 } 687 loadGrids()688 protected int loadGrids(){ 689 int grids = TuxGuitar.instance().getConfig().getIntConfigValue(TGConfigKeys.MATRIX_GRIDS); 690 // check if is valid value 691 for(int i = 0 ; i < DIVISIONS.length ; i ++ ){ 692 if(grids == DIVISIONS[i]){ 693 return grids; 694 } 695 } 696 return DIVISIONS[1]; 697 } 698 setGrids(int grids)699 protected void setGrids(int grids){ 700 this.grids = grids; 701 this.disposeBuffer(); 702 this.redrawLocked(); 703 } 704 getGrids()705 public int getGrids(){ 706 return this.grids; 707 } 708 getMeasure()709 protected TGMeasure getMeasure(){ 710 if(TuxGuitar.instance().getPlayer().isRunning()){ 711 TGMeasure measure = TuxGuitar.instance().getEditorCache().getPlayMeasure(); 712 if(measure != null){ 713 return measure; 714 } 715 } 716 return TuxGuitar.instance().getTablatureEditor().getTablature().getCaret().getMeasure(); 717 } 718 getCaret()719 protected Caret getCaret(){ 720 return TuxGuitar.instance().getTablatureEditor().getTablature().getCaret(); 721 } 722 isDisposed()723 public boolean isDisposed(){ 724 return (this.dialog == null || this.dialog.isDisposed()); 725 } 726 resetPlayed()727 protected void resetPlayed(){ 728 this.playedBeat = null; 729 this.playedMeasure = -1; 730 this.playedTrack = -1; 731 } 732 redrawLocked()733 public void redrawLocked(){ 734 if(!TuxGuitar.instance().isLocked()){ 735 TuxGuitar.instance().lock(); 736 this.redraw(); 737 TuxGuitar.instance().unlock(); 738 } 739 } 740 redraw()741 public void redraw(){ 742 if(!isDisposed() && !TuxGuitar.instance().isLocked()){ 743 //TuxGuitar.instance().lock(); 744 745 this.editor.redraw(); 746 this.loadDurationImage(false); 747 748 //TuxGuitar.instance().unlock(); 749 } 750 } 751 redrawPlayingMode()752 public void redrawPlayingMode(){ 753 if(!isDisposed() && !TuxGuitar.instance().isLocked() && TuxGuitar.instance().getPlayer().isRunning()){ 754 //TuxGuitar.instance().lock(); 755 756 TGMeasure measure = TuxGuitar.instance().getEditorCache().getPlayMeasure(); 757 TGBeat beat = TuxGuitar.instance().getEditorCache().getPlayBeat(); 758 if(measure != null && beat != null){ 759 int currentMeasure = measure.getNumber(); 760 int currentTrack = measure.getTrack().getNumber(); 761 boolean changed = (currentMeasure != this.playedMeasure || currentTrack != this.playedTrack); 762 if(changed){ 763 this.resetPlayed(); 764 this.editor.redraw(); 765 } 766 else{ 767 TGPainter painter = new TGPainter(new GC(this.editor)); 768 int scrollX = this.editor.getHorizontalBar().getSelection(); 769 int scrollY = this.editor.getVerticalBar().getSelection(); 770 if(this.playedBeat != null){ 771 this.paintBeat(painter,measure,this.playedBeat,(-scrollX), (BORDER_HEIGHT - scrollY)); 772 } 773 this.paintBeat(painter,measure,beat,(-scrollX), (BORDER_HEIGHT - scrollY)); 774 painter.dispose(); 775 } 776 this.playedMeasure = currentMeasure; 777 this.playedTrack = currentTrack; 778 this.playedBeat = beat; 779 } 780 //TuxGuitar.instance().unlock(); 781 } 782 } 783 configure()784 protected void configure(){ 785 this.config.configure(this.dialog); 786 this.disposeBuffer(); 787 this.redrawLocked(); 788 } 789 layout()790 private void layout(){ 791 if( !isDisposed() ){ 792 this.toolbar.layout(); 793 this.editor.layout(); 794 this.composite.layout(true,true); 795 } 796 } 797 loadIcons()798 public void loadIcons(){ 799 if( !isDisposed() ){ 800 this.dialog.setImage(TuxGuitar.instance().getIconManager().getAppIcon()); 801 this.settings.setImage(TuxGuitar.instance().getIconManager().getSettings()); 802 this.loadDurationImage(true); 803 this.layout(); 804 this.redraw(); 805 } 806 } 807 loadProperties()808 public void loadProperties() { 809 if( !isDisposed() ){ 810 this.dialog.setText(TuxGuitar.getProperty("matrix.editor")); 811 this.gridsLabel.setText(TuxGuitar.getProperty("matrix.grids")); 812 this.settings.setToolTipText(TuxGuitar.getProperty("settings")); 813 this.disposeBuffer(); 814 this.layout(); 815 this.redraw(); 816 } 817 } 818 dispose()819 public void dispose(){ 820 if(!isDisposed()){ 821 this.dialog.dispose(); 822 } 823 } 824 disposeBuffer()825 protected void disposeBuffer(){ 826 if(this.buffer != null && !this.buffer.isDisposed()){ 827 this.buffer.dispose(); 828 this.buffer = null; 829 } 830 } 831 dispose(Resource[] resources)832 protected void dispose(Resource[] resources){ 833 if(resources != null){ 834 for(int i = 0; i < resources.length; i ++){ 835 dispose(resources[i]); 836 } 837 } 838 } 839 dispose(Resource resource)840 protected void dispose(Resource resource){ 841 if(resource != null){ 842 resource.dispose(); 843 } 844 } 845 disposeAll()846 protected void disposeAll(){ 847 this.disposeBuffer(); 848 this.disposeSelectionBuffer(); 849 this.config.dispose(); 850 } 851 getEditor()852 protected Composite getEditor(){ 853 return this.editor; 854 } 855 856 protected class BufferDisposer{ 857 private int numerator; 858 private int denominator; 859 private int track; 860 private boolean percussion; 861 862 private int width; 863 private int height; 864 update(int width, int height)865 public void update(int width, int height){ 866 TGMeasure measure = getMeasure(); 867 int track = measure.getTrack().getNumber(); 868 int numerator = measure.getTimeSignature().getNumerator(); 869 int denominator = measure.getTimeSignature().getDenominator().getValue(); 870 boolean percussion = measure.getTrack().isPercussionTrack(); 871 if(width != this.width || height != this.height || this.track != track || this.numerator != numerator || this.denominator != denominator || this.percussion != percussion){ 872 disposeBuffer(); 873 } 874 this.track = track; 875 this.numerator = numerator; 876 this.denominator = denominator; 877 this.percussion = percussion; 878 this.width = width; 879 this.height = height; 880 } 881 } 882 883 protected class DisposeListenerImpl implements DisposeListener{ widgetDisposed(DisposeEvent e)884 public void widgetDisposed(DisposeEvent e) { 885 disposeAll(); 886 } 887 } 888 889 protected class MatrixListener implements PaintListener,MouseListener,MouseMoveListener,MouseTrackListener { 890 MatrixListener()891 public MatrixListener(){ 892 super(); 893 } 894 paintControl(PaintEvent e)895 public void paintControl(PaintEvent e) { 896 if(!TuxGuitar.instance().isLocked()){ 897 TuxGuitar.instance().lock(); 898 TGPainter painter = new TGPainter(e.gc); 899 paintEditor(painter); 900 TuxGuitar.instance().unlock(); 901 } 902 } 903 mouseUp(MouseEvent e)904 public void mouseUp(MouseEvent e) { 905 getEditor().setFocus(); 906 if(e.button == 1){ 907 if(!TuxGuitar.instance().isLocked() && !ActionLock.isLocked()){ 908 ActionLock.lock(); 909 hit(e.x,e.y); 910 ActionLock.unlock(); 911 } 912 } 913 } 914 mouseMove(MouseEvent e)915 public void mouseMove(MouseEvent e) { 916 if(!TuxGuitar.instance().isLocked() && !ActionLock.isLocked()){ 917 updateSelection(e.y); 918 } 919 } 920 mouseExit(MouseEvent e)921 public void mouseExit(MouseEvent e) { 922 if(!TuxGuitar.instance().isLocked() && !ActionLock.isLocked()){ 923 updateSelection(-1); 924 } 925 } 926 mouseEnter(MouseEvent e)927 public void mouseEnter(MouseEvent e) { 928 if(!TuxGuitar.instance().isLocked() && !ActionLock.isLocked()){ 929 redrawLocked(); 930 } 931 } 932 mouseDoubleClick(MouseEvent e)933 public void mouseDoubleClick(MouseEvent e) { 934 // TODO Auto-generated method stub 935 } 936 mouseDown(MouseEvent e)937 public void mouseDown(MouseEvent e) { 938 // TODO Auto-generated method stub 939 } 940 mouseHover(MouseEvent e)941 public void mouseHover(MouseEvent e) { 942 // TODO Auto-generated method stub 943 } 944 } 945 doRedraw(int type)946 public void doRedraw(int type) { 947 if( type == TGRedrawListener.NORMAL ){ 948 this.redraw(); 949 }else if( type == TGRedrawListener.PLAYING_NEW_BEAT ){ 950 this.redrawPlayingMode(); 951 } 952 } 953 } 954