package org.herac.tuxguitar.gui.editors.tab;
import java.util.Iterator;
import org.herac.tuxguitar.gui.TuxGuitar;
import org.herac.tuxguitar.gui.editors.TGPainter;
import org.herac.tuxguitar.gui.editors.tab.layout.ViewLayout;
import org.herac.tuxguitar.gui.editors.tab.painters.TGNotePainter;
import org.herac.tuxguitar.gui.editors.tab.painters.TGSilencePainter;
import org.herac.tuxguitar.song.factory.TGFactory;
import org.herac.tuxguitar.song.models.TGDivisionType;
import org.herac.tuxguitar.song.models.TGDuration;
import org.herac.tuxguitar.song.models.TGVoice;
public class TGVoiceImpl extends TGVoice{
/**
* desviacion a la izquierda
*/
public static final int JOINED_TYPE_NONE_LEFT = 1;
/**
* desviacion a la derecha
*/
public static final int JOINED_TYPE_NONE_RIGHT = 2;
/**
* Union a la izquierda
*/
public static final int JOINED_TYPE_LEFT = 3;
/**
* Union a la derecha
*/
public static final int JOINED_TYPE_RIGHT = 4;
private int width;
private TGNoteImpl maxNote;
private TGNoteImpl minNote;
private boolean[] usedStrings;
private int joinedType;
private boolean joinedGreaterThanQuarter;
private TGVoiceImpl join1;
private TGVoiceImpl join2;
private TGVoiceImpl previous;
private TGVoiceImpl next;
private TGBeatGroup group;
private boolean hiddenSilence;
private int maxY;
private int minY;
private float silenceY;
private float silenceHeight;
private int maxString;
private int minString;
public TGVoiceImpl(TGFactory factory,int index){
super(factory, index);
}
public int getPosX() {
return this.getBeatImpl().getPosX();
}
public int getWidth() {
return this.width;
}
public void setWidth(int width) {
this.width = width;
}
public TGNoteImpl getMinNote(){
return this.minNote;
}
public TGNoteImpl getMaxNote(){
return this.maxNote;
}
public TGBeatImpl getBeatImpl() {
return (TGBeatImpl)getBeat();
}
public TGMeasureImpl getMeasureImpl() {
return (TGMeasureImpl)getBeat().getMeasure();
}
public boolean[] getUsedStrings() {
if(this.usedStrings == null){
this.usedStrings = new boolean[getBeat().getMeasure().getTrack().stringCount()];
}
return this.usedStrings;
}
public TGVoiceImpl getJoin1() {
return this.join1;
}
public void setJoin1(TGVoiceImpl join1) {
this.join1 = join1;
}
public TGVoiceImpl getJoin2() {
return this.join2;
}
public void setJoin2(TGVoiceImpl join2) {
this.join2 = join2;
}
public boolean isJoinedGreaterThanQuarter() {
return this.joinedGreaterThanQuarter;
}
public void setJoinedGreaterThanQuarter(boolean joinedGreaterThanQuarter) {
this.joinedGreaterThanQuarter = joinedGreaterThanQuarter;
}
public int getJoinedType() {
return this.joinedType;
}
public void setJoinedType(int joinedType) {
this.joinedType = joinedType;
}
public void setPreviousBeat(TGVoiceImpl previous){
this.previous = previous;
}
public void setNextBeat(TGVoiceImpl next){
this.next = next;
}
public TGBeatGroup getBeatGroup() {
return this.group;
}
public void setBeatGroup(TGBeatGroup group) {
this.group = group;
}
public boolean isPlaying(ViewLayout layout){
return (getMeasureImpl().isPlaying(layout) && TuxGuitar.instance().getEditorCache().isPlaying(getBeat().getMeasure(),getBeat()));
}
public void reset(){
this.maxNote = null;
this.minNote = null;
this.hiddenSilence = false;
this.usedStrings = new boolean[getBeat().getMeasure().getTrack().stringCount()];
this.maxString = 1;
this.minString = getBeat().getMeasure().getTrack().stringCount();
this.group = null;
this.previous = null;
this.next = null;
}
public void check(TGNoteImpl note){
int value = note.getRealValue();
if(this.maxNote == null || value > this.maxNote.getRealValue()){
this.maxNote = note;
}
if(this.minNote == null || value < this.minNote.getRealValue()){
this.minNote = note;
}
this.getUsedStrings();
this.usedStrings[note.getString() - 1] = true;
if( note.getString() > this.maxString ){
this.maxString = note.getString();
}
if( note.getString() < this.minString ){
this.minString = note.getString();
}
}
public void update(ViewLayout layout) {
this.minY = 0;
this.maxY = 0;
if(isRestVoice()){
this.updateSilenceSpacing(layout);
}
else{
this.updateNoteVoice(layout);
}
}
public void updateNoteVoice(ViewLayout layout) {
this.joinedType = JOINED_TYPE_NONE_RIGHT;
this.joinedGreaterThanQuarter = false;
this.setJoin1(this);
this.setJoin2(this);
boolean noteJoined = false;
boolean withPrev = false;
//trato de unir con el componente anterior
if (this.previous != null && !this.previous.isRestVoice()) {
if (getMeasureImpl().canJoin(layout.getSongManager(),this, this.previous)) {
withPrev = true;
if (this.previous.getDuration().getValue() >= getDuration().getValue()) {
this.setJoin1(this.previous);
this.setJoin2(this);
this.joinedType = JOINED_TYPE_LEFT;
noteJoined = true;
}
if (this.previous.getDuration().getValue() > TGDuration.QUARTER){
this.joinedGreaterThanQuarter = true;
}
}
}
//trato de unir con el componente que le sigue
if (this.next != null && !this.next.isRestVoice() ) {
if (getMeasureImpl().canJoin(layout.getSongManager(),this, this.next)) {
if (this.next.getDuration().getValue() >= getDuration().getValue()) {
this.setJoin2(this.next);
if (this.previous == null || this.previous.isRestVoice() || this.previous.getDuration().getValue() < getDuration().getValue()) {
this.setJoin1(this);
}
noteJoined = true;
this.joinedType = JOINED_TYPE_RIGHT;
}
if (this.next.getDuration().getValue() > TGDuration.QUARTER){
this.joinedGreaterThanQuarter = true;
}
}
}
//si no hubo union decido para que lado girar la figura
if (!noteJoined && withPrev) {
this.joinedType = JOINED_TYPE_NONE_LEFT;
}
if( (layout.getStyle() & ViewLayout.DISPLAY_TABLATURE) != 0 && (layout.getStyle() & ViewLayout.DISPLAY_SCORE) == 0){
this.minY = 0;
this.maxY = getBeatImpl().getMeasureImpl().getTrackImpl().getTabHeight();
if( getBeatGroup().getDirection() == TGBeatGroup.DIRECTION_DOWN ){
this.maxY += (((layout.getStringSpacing() / 2) * 5) + 1);
}else{
this.minY -= (((layout.getStringSpacing() / 2) * 5) + 1);
}
}
}
public void updateSilenceSpacing(ViewLayout layout) {
this.silenceY = 0;
this.silenceHeight = 0;
if(!isHiddenSilence()){
int style = layout.getStyle();
int lineSpacing = 0;
int lineCount = 0;
float scale = 0;
if((style & ViewLayout.DISPLAY_SCORE) != 0 ){
lineSpacing = layout.getScoreLineSpacing();
lineCount = 5;
scale = (lineSpacing / 9.0f);
}else{
lineSpacing = layout.getStringSpacing();
lineCount = getBeat().getMeasure().getTrack().stringCount();
scale = (lineSpacing / 10.0f);
}
int duration = getDuration().getValue();
if(duration == TGDuration.WHOLE){
this.silenceHeight = (scale * 3.6513581f);
this.silenceY = ( lineCount <= 5 ? lineSpacing : lineSpacing * 2 );
}
else if(duration == TGDuration.HALF){
this.silenceHeight = (scale * 3.6513581f);
this.silenceY = ( lineCount <= 5 ? lineSpacing * 2 : lineSpacing * 3 ) - this.silenceHeight;
}
else if(duration == TGDuration.QUARTER){
this.silenceHeight = (scale * 16);
this.silenceY = ((lineSpacing * (lineCount - 1)) / 2) - (this.silenceHeight / 2);
}
else if(duration == TGDuration.EIGHTH){
this.silenceHeight = (scale * 12);
this.silenceY = ((lineSpacing * (lineCount - 1)) / 2) - (this.silenceHeight / 2);
}
else if(duration == TGDuration.SIXTEENTH){
this.silenceHeight = (scale * 16);
this.silenceY = ((lineSpacing * (lineCount - 1)) / 2) - (this.silenceHeight / 2);
}
else if(duration == TGDuration.THIRTY_SECOND){
this.silenceHeight = (scale * 24);
this.silenceY = ((lineSpacing * (lineCount - 1)) / 2) - (this.silenceHeight / 2);
}
else if(duration == TGDuration.SIXTY_FOURTH){
this.silenceHeight = (scale * 28);
this.silenceY = ((lineSpacing * (lineCount - 1)) / 2) - (this.silenceHeight / 2);
}
for( int v = 0; v < getBeat().countVoices(); v ++){
if( v != getIndex() ){
TGVoiceImpl voice = getBeatImpl().getVoiceImpl( v );
if( !voice.isEmpty() ){
if( voice.isRestVoice()){
if( !voice.isHiddenSilence() ){
float maxSilenceHeight = (lineSpacing * 3);
float firstPosition = (this.silenceY - (maxSilenceHeight / getBeat().countVoices()));
this.silenceY = (firstPosition + ( maxSilenceHeight * getIndex() ));
}
}
else if((layout.getStyle() & ViewLayout.DISPLAY_SCORE) != 0 ){
int direction = voice.getBeatGroup().getDirection();
int y1 = voice.getBeatGroup().getY1(layout,voice.getMinNote(),getMeasureImpl().getKeySignature(),getMeasureImpl().getClef());
int y2 = voice.getBeatGroup().getY1(layout,voice.getMaxNote(),getMeasureImpl().getKeySignature(),getMeasureImpl().getClef());
if(direction == TGBeatGroup.DIRECTION_UP){
float position = (y1 + (lineSpacing * 2));
if( position > this.silenceY ){
this.silenceY = position;
}
}else if(direction == TGBeatGroup.DIRECTION_DOWN){
float position = (y2 - (this.silenceHeight + lineSpacing));
if( position < this.silenceY ){
this.silenceY = position;
}
}
}else if((layout.getStyle() & ViewLayout.DISPLAY_TABLATURE) != 0 ){
int direction = voice.getBeatGroup().getDirection();
if(direction == TGBeatGroup.DIRECTION_UP){
float position = (lineSpacing * voice.getMaxString() );
if( position > this.silenceY ){
this.silenceY = position;
}
}
else if(direction == TGBeatGroup.DIRECTION_DOWN){
float position = ((lineSpacing * (voice.getMinString() - 1) ) - (this.silenceHeight + lineSpacing));
if( position < this.silenceY ){
this.silenceY = position;
}
}
}
}
}
}
this.minY = (int)this.silenceY;
this.maxY = (int)(this.silenceY + this.silenceHeight);
}
}
public void paint(ViewLayout layout,TGPainter painter, int fromX, int fromY) {
if(!isEmpty()){
if(isRestVoice() && !isHiddenSilence()){
paintSilence(layout, painter, fromX, fromY);
}
else{
Iterator notes = getNotes().iterator();
while (notes.hasNext()) {
TGNoteImpl note = (TGNoteImpl)notes.next();
note.paint(layout,painter,fromX ,fromY);
}
if(!layout.isPlayModeEnabled()){
paintBeat(layout, painter, fromX, fromY) ;
}
}
}
}
//----silence
public void paintSilence(ViewLayout layout,TGPainter painter, int fromX, int fromY) {
int style = layout.getStyle();
int x = 0;
int lineSpacing = 0;
float y = 0;
float scale = 0;
if((style & ViewLayout.DISPLAY_SCORE) != 0 ){
x = fromX + getPosX() + getBeatImpl().getSpacing();
y = fromY + getPaintPosition(TGTrackSpacing.POSITION_SCORE_MIDDLE_LINES) + this.silenceY;
lineSpacing = layout.getScoreLineSpacing();
scale = (lineSpacing / 9.0f);
}else{
x = fromX + getPosX() + getBeatImpl().getSpacing() - 1;
y = fromY + getPaintPosition(TGTrackSpacing.POSITION_TABLATURE) + this.silenceY;
lineSpacing = layout.getStringSpacing();
scale = (lineSpacing / 10.0f);
}
setStyle(layout, painter,(layout.isPlayModeEnabled() && isPlaying(layout)));
painter.initPath(TGPainter.PATH_FILL);
int duration = getDuration().getValue();
if(duration == TGDuration.WHOLE){
TGSilencePainter.paintWhole(painter, x, y , scale);
}
else if(duration == TGDuration.HALF){
TGSilencePainter.paintHalf(painter, x, y , scale);
}
else if(duration == TGDuration.QUARTER){
TGSilencePainter.paintQuarter(painter, x, y, scale);
}
else if(duration == TGDuration.EIGHTH){
TGSilencePainter.paintEighth(painter, x, y, scale);
}
else if(duration == TGDuration.SIXTEENTH){
TGSilencePainter.paintSixteenth(painter, x, y, scale);
}
else if(duration == TGDuration.THIRTY_SECOND){
TGSilencePainter.paintThirtySecond(painter, x, y, scale);
}
else if(duration == TGDuration.SIXTY_FOURTH){
TGSilencePainter.paintSixtyFourth(painter, x, y, scale);
}
painter.closePath();
if(getDuration().isDotted() || getDuration().isDoubleDotted()){
layout.setDotStyle(painter);
painter.initPath();
painter.moveTo(x + 10,y +1);
painter.addOval(x + 10,y +1,1,1);
if(getDuration().isDoubleDotted()){
painter.moveTo(x + 13,y +1);
painter.addOval(x + 13,y +1,1,1);
}
painter.closePath();
}
if(!getDuration().getDivision().isEqual(TGDivisionType.NORMAL)){
layout.setDivisionTypeStyle(painter);
if((style & ViewLayout.DISPLAY_SCORE) != 0 ){
painter.drawString(Integer.toString(getDuration().getDivision().getEnters()), x,(fromY + getPaintPosition(TGTrackSpacing.POSITION_DIVISION_TYPE)));
}else{
painter.drawString(Integer.toString(getDuration().getDivision().getEnters()),x,(fromY + getPaintPosition(TGTrackSpacing.POSITION_DIVISION_TYPE)));
}
}
}
public void setStyle(ViewLayout layout, TGPainter painter, boolean playMode){
if((layout.getStyle() & ViewLayout.DISPLAY_SCORE) != 0 ){
layout.setScoreSilenceStyle(painter, playMode);
}else{
layout.setTabSilenceStyle(painter, playMode);
}
}
public void paintBeat(ViewLayout layout,TGPainter painter, int fromX, int fromY){
if(!isRestVoice() ){
int style = layout.getStyle();
int spacing = getBeatImpl().getSpacing();
if((style & ViewLayout.DISPLAY_SCORE) != 0){
paintScoreBeat(layout, painter, fromX, fromY+getPaintPosition(TGTrackSpacing.POSITION_SCORE_MIDDLE_LINES), spacing);
}
if((style & ViewLayout.DISPLAY_TABLATURE) != 0 && (style & ViewLayout.DISPLAY_SCORE) == 0){
paintTablatureBeat(layout, painter, fromX, fromY + getPaintPosition(TGTrackSpacing.POSITION_TABLATURE), spacing);
}
}
}
public void paintTablatureBeat(ViewLayout layout,TGPainter painter, int fromX, int fromY, int spacing){
if(!isRestVoice() ){
float scale = layout.getScale();
float xMove = (2 * scale);
float x = ( fromX + getPosX() + spacing + xMove );
float y1 = 0;
float y2 = 0;
float verticalLineWidth = scale;
float horizontalLineWidth = (2 * scale);
int stringSpacing = layout.getStringSpacing();
if( getBeatGroup().getDirection() == TGBeatGroup.DIRECTION_DOWN ){
y1 = (fromY + getMeasureImpl().getTrackImpl().getTabHeight() + (stringSpacing / 2));
y2 = (fromY + getMeasureImpl().getTrackImpl().getTabHeight() + ((stringSpacing / 2) * 5));
}else{
y1 = (fromY - (stringSpacing / 2) - horizontalLineWidth);
y2 = (fromY - ((stringSpacing / 2) * 5));
}
if (getDuration().getValue() >= TGDuration.QUARTER) {
layout.setTabNoteFooterStyle(painter);
painter.initPath();
painter.setAntialias(false);
painter.setLineWidth( (int)verticalLineWidth );
painter.moveTo(x, y1);
painter.lineTo(x, y2);
painter.closePath();
if (getDuration().getValue() >= TGDuration.EIGHTH) {
float x1 = 0;
float x2 = 0;
int joinedType = getJoinedType();
if(joinedType == TGVoiceImpl.JOINED_TYPE_NONE_RIGHT){
x1 = getPosX() + xMove + spacing;
x2 = getPosX() + xMove + spacing + (6 * scale);
}else if(joinedType == TGVoiceImpl.JOINED_TYPE_NONE_LEFT){
x1 = getPosX() + xMove + spacing - (5 * scale);
x2 = getPosX() + xMove + spacing;
}else{
x1 = getJoin1().getPosX() + xMove + getJoin1().getBeatImpl().getSpacing();
x2 = getJoin2().getPosX() + xMove + getJoin2().getBeatImpl().getSpacing();
}
int index = ( getDuration().getIndex() - 2);
if(index > 0){
int height = (layout.getStringSpacing() / 2);
int direction = (getBeatGroup().getDirection() == TGBeatGroup.DIRECTION_DOWN ? 1 : -1);
painter.setLineWidth( (int)horizontalLineWidth );
painter.initPath();
for(int i = index; i > 0 ;i --){
painter.moveTo(fromX + x1, y2 + ((height - (i * height)) * direction));
painter.lineTo(fromX + x2, y2 + ((height - (i * height)) * direction));
}
painter.closePath();
painter.setLineWidth(1);
}
}
} else if (getDuration().getValue() == TGDuration.HALF) {
layout.setTabNoteFooterStyle(painter);
painter.initPath();
painter.setAntialias(false);
painter.setLineWidth( (int)verticalLineWidth );
painter.moveTo(x, (y1 + ((y2 - y1) / 2)));
painter.lineTo(x, y2);
painter.closePath();
}
//-------------puntillo--------------------------------------
if (getDuration().isDotted() || getDuration().isDoubleDotted()) {
int joinedType = getJoinedType();
float posX = ((getDuration().getValue() > TGDuration.WHOLE)?((joinedType == TGVoiceImpl.JOINED_TYPE_NONE_RIGHT || joinedType == TGVoiceImpl.JOINED_TYPE_RIGHT)?(x+ (4.0f * scale)):(x- (5.0f * scale))):x);
float posY = (y2 - ((getDuration().getValue() >= TGDuration.EIGHTH)? ((stringSpacing / 2) * (getDuration().getIndex() - 2)):(1.0f * scale)));
paintDot(layout, painter, posX, posY,scale);
}
//-------------tresillo--------------------------------------
if (!getDuration().getDivision().isEqual(TGDivisionType.NORMAL)) {
layout.setDivisionTypeStyle(painter);
painter.drawString(Integer.toString(getDuration().getDivision().getEnters()), (int)(x - 3),((fromY - getPaintPosition(TGTrackSpacing.POSITION_TABLATURE)) + getPaintPosition(TGTrackSpacing.POSITION_DIVISION_TYPE)));
}
}
}
public void paintScoreBeat(ViewLayout layout,TGPainter painter, int fromX, int fromY, int spacing){
int vX = ( fromX + getPosX() + spacing );
//division type
if (!getDuration().getDivision().isEqual(TGDivisionType.NORMAL)) {
layout.setDivisionTypeStyle(painter);
painter.drawString(Integer.toString(getDuration().getDivision().getEnters()),vX ,((fromY - getPaintPosition(TGTrackSpacing.POSITION_SCORE_MIDDLE_LINES)) + getPaintPosition(TGTrackSpacing.POSITION_DIVISION_TYPE)));
}
//dibujo el pie
if(getDuration().getValue() >= TGDuration.HALF){
layout.setScoreNoteFooterStyle(painter);
float scale = layout.getScale();
float lineSpacing = layout.getScoreLineSpacing();
int direction = this.group.getDirection();
int key = getBeat().getMeasure().getKeySignature();
int clef = getBeat().getMeasure().getClef();
int xMove = (direction == TGBeatGroup.DIRECTION_UP ? layout.getResources().getScoreNoteWidth() : 0);
int yMove = (direction == TGBeatGroup.DIRECTION_UP ? ((layout.getScoreLineSpacing() / 3) + 1) : ((layout.getScoreLineSpacing() / 3) * 2));
int vY1 = fromY + ( direction == TGBeatGroup.DIRECTION_DOWN ? this.maxNote.getScorePosY() : this.minNote.getScorePosY() );
int vY2 = fromY + this.group.getY2(layout,getPosX() + spacing,key,clef);
painter.initPath();
painter.setAntialias(false);
painter.moveTo(vX + xMove, vY1 + yMove);
painter.lineTo(vX + xMove, vY2);
painter.closePath();
if (getDuration().getValue() >= TGDuration.EIGHTH) {
int index = ( getDuration().getIndex() - 3);
if(index >= 0){
int dir = (direction == TGBeatGroup.DIRECTION_DOWN)?1:-1;
int joinedType = getJoinedType();
boolean joinedGreaterThanQuarter = isJoinedGreaterThanQuarter();
if((joinedType == TGVoiceImpl.JOINED_TYPE_NONE_LEFT || joinedType == TGVoiceImpl.JOINED_TYPE_NONE_RIGHT) && !joinedGreaterThanQuarter){
float hX = (fromX + xMove + getPosX() + spacing);
float hY = ( (fromY + this.group.getY2(layout,getPosX() + spacing,key,clef)) - ( (lineSpacing * 2)* dir )) ;
for(int i = 0; i <= index; i ++){
painter.initPath(TGPainter.PATH_FILL);
TGNotePainter.paintFooter(painter,hX,(hY - ( (i * (lineSpacing / 2.0f)) * dir)),dir,lineSpacing);
painter.closePath();
}
}else{
int hX1 = 0;
int hX2 = 0;
if(joinedType == TGVoiceImpl.JOINED_TYPE_NONE_RIGHT){
hX1 = getPosX() + spacing;
hX2 = getPosX() + spacing + 6;
}else if(joinedType == TGVoiceImpl.JOINED_TYPE_NONE_LEFT){
hX1 = getPosX() + spacing - 5;
hX2 = getPosX() + spacing;
}else{
hX1 = getJoin1().getPosX() + getJoin1().getBeatImpl().getSpacing();
hX2 = getJoin2().getPosX() + getJoin2().getBeatImpl().getSpacing();
}
int hY1 = fromY + this.group.getY2(layout,hX1,key,clef);
int hY2 = fromY + this.group.getY2(layout,hX2,key,clef);
painter.setLineWidth(Math.max(1,Math.round(3f * scale)));
painter.initPath();
for(int i = 0; i <= index; i ++){
painter.moveTo(fromX + xMove + hX1, hY1 - ( (i * (5f * scale)) * dir));
painter.lineTo(fromX + xMove + hX2, hY2 - ( (i * (5f * scale)) * dir));
}
painter.closePath();
painter.setLineWidth(1);
}
}
}
}
}
public void paintDot(ViewLayout layout,TGPainter painter,float fromX, float fromY,float scale){
float dotSize = (3.0f * scale);
float posX = fromX;
float posY = fromY;
layout.setDotStyle(painter);
painter.initPath(TGPainter.PATH_FILL);
painter.moveTo(posX - (dotSize / 2), posY - (dotSize / 2));
painter.addOval(posX - (dotSize / 2), posY - (dotSize / 2), dotSize,dotSize);
if(getDuration().isDoubleDotted()){
painter.moveTo(posX + (dotSize + 2) - (dotSize / 2), posY - (dotSize / 2));
painter.addOval(posX + (dotSize + 2) - (dotSize / 2), posY - (dotSize / 2), dotSize,dotSize);
}
painter.closePath();
}
public int getPaintPosition(int index){
return getMeasureImpl().getTs().getPosition(index);
}
public int getMaxString() {
return this.maxString;
}
public int getMinString() {
return this.minString;
}
public int getMaxY() {
return this.maxY;
}
public int getMinY() {
return this.minY;
}
public boolean isHiddenSilence() {
return this.hiddenSilence;
}
public void setHiddenSilence(boolean hiddenSilence) {
this.hiddenSilence = hiddenSilence;
}
}