package aliview.gui.pane; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.font.TextAttribute; import java.awt.print.PageFormat; import java.awt.print.Printable; import java.awt.print.PrinterException; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.RenderingHints; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import javax.swing.JComponent; import javax.swing.JPanel; import org.apache.log4j.Logger; import aliview.AliView; import aliview.AminoAcid; import aliview.Base; import aliview.NucleotideUtilities; import aliview.alignment.AAHistogram; import aliview.alignment.NotUsed_AATranslator; import aliview.alignment.AliHistogram; import aliview.alignment.Alignment; import aliview.alignment.NucleotideHistogram; import aliview.color.ColorScheme; import aliview.sequences.Sequence; import aliview.settings.Settings; import aliview.utils.ArrayUtilities; // HAS to be JPanel - JComponent is not enough for only partial cliprect when in jscrollpane when painting // When JComponent only then I had to paint it all (maybe because of layoutmanager?) public class NotUsed_AlignmentPane_Orig extends JPanel{ /* private static final long serialVersionUID = 601195400946835871L; private static final Logger logger = Logger.getLogger(NotUsed_AlignmentPane_Orig.class); private static final double MIN_CHAR_SIZE = 0; private static final int MAX_CHAR_SIZE = 100; private static final double CHAR_HEIGHT_RATIO = 1.4; public static final int MAX_CHARSIZE_TO_DRAW = 8; public static final int INTERACTION_MODE_VIEW = 0; public static final int INTERACTION_MODE_EDIT = 1; private static final Color ALPHACOLOR = new Color(255, 255,255, 128 ); // public static final int INTERACTION_MODE_SELECT = 2; double charWidth = 10; double charHeight = 12; private Font baseFont = new Font(Font.MONOSPACED, Font.PLAIN, (int)charWidth); private Color ALIGNMENT_PANE_BG_COLOR = Color.WHITE; private Alignment alignment; private ColorScheme colorSchemeAminoAcid = Settings.getColorSchemeAminoAcid(); private ColorScheme colorSchemeNucleotide = Settings.getColorSchemeNucleotide(); private boolean highlightDiffTrace = false; private Rectangle tempSelectionRect; // private InfoLabel infoLabel; private int interactionMode; // TODO This should instead be tracing a sequence instead of a position? private int differenceTraceSequencePosition = 0; private boolean showTranslation = false; private boolean showTranslationOnePos = false; private AlignmentRuler alignmentRuler; private boolean drawAminoAcidCode; private boolean drawCodonPosRuler; private Rectangle lastClip = new Rectangle(); private boolean rulerIsDirty; private boolean highlightNonCons; private boolean highlightCons; DrawCharBuffer drawCharBuffer = new DrawCharBuffer(5000); private boolean ignoreGapInTranslation; private byte byteToDraw; public NotUsed_AlignmentPane_Orig() { //this.setDoubleBuffered(false); //this.setBackground(Color.white); //this.infoLabel = infoLabel; alignmentRuler = new AlignmentRuler(this); createAdjustedDerivedBaseFont(); } public boolean isOnlyDrawDiff() { return highlightDiffTrace; } public void setHighlightDiffTrace(boolean highlightDiff) { this.highlightDiffTrace = highlightDiff; } public void setHighlightNonCons(boolean b) { this.highlightNonCons = b; } public boolean isHighlightNonCons() { return highlightNonCons; } public void setHighlightCons(boolean b) { this.highlightCons = b; } public boolean isHighlightCons() { return highlightCons; } public void setDrawCodonPosRuler(boolean drawCodonPosRuler) { this.drawCodonPosRuler = drawCodonPosRuler; } public boolean getDrawCodonPosRuler() { return this.drawCodonPosRuler; } public void decCharSize(){ // stop when everything is in view (or char is 1 for smaller alignments) Dimension prefSize = getPreferredSize(); if((prefSize.width >= this.getSize().width || prefSize.height >= this.getSize().height) || charWidth > 1){ double preferredWidth = charWidth; double preferredHeight = charHeight; if(charWidth > 1){ preferredWidth = charWidth - 1; preferredHeight = (int)(preferredWidth*CHAR_HEIGHT_RATIO);// 1.2 * charWidth; } else{ preferredWidth = 0.80 * charWidth; preferredHeight = preferredWidth; } if(preferredWidth >= MIN_CHAR_SIZE){ charWidth = preferredWidth; charHeight = preferredHeight; } //baseFont = new Font(baseFont.getName(), baseFont.getStyle(), (int)charWidth); createAdjustedDerivedBaseFont(); logFontMetrics(); this.validateSize(); this.repaint(); } } public void incCharSize(){ if(charWidth >= 1){ charWidth = charWidth +1; // +1 charHeight = (int)(charWidth*CHAR_HEIGHT_RATIO); }else{ charWidth = charWidth * 1.25; // +1 if(charWidth > 1 && charWidth <2){ charWidth = 1; } charHeight = charWidth; // +1 } if(charWidth > MAX_CHAR_SIZE){ charWidth = MAX_CHAR_SIZE; charHeight = (int)(charWidth*CHAR_HEIGHT_RATIO); } //baseFont = new Font(baseFont.getName(), baseFont.getStyle(), (int)charWidth); createAdjustedDerivedBaseFont(); logFontMetrics(); this.validateSize(); } private void createAdjustedDerivedBaseFont() { Map<TextAttribute, Object> attributes = new HashMap<TextAttribute, Object>(); //; // 11 //attributes.put(TextAttribute.TRACKING, 0.443); // 10 //attributes.put(TextAttribute.TRACKING, 0.375); // 9 //attributes.put(TextAttribute.TRACKING, 0.4278); // 8 // create a font without Tracking to see the diff in font actual size and specified font size attributes.put(TextAttribute.TRACKING, 0); attributes.put(TextAttribute.SIZE, (int)charWidth); Font calcFont = baseFont.deriveFont(attributes); FontMetrics metrics = getFontMetrics(calcFont); int fontActualWidth = metrics.stringWidth("X"); double sizeDiff = charWidth - fontActualWidth; // Calculate tracking for font size double tracking = (double)sizeDiff/charWidth; logger.info("tracking" + tracking); // Create a font with correct tracking so characters are exactly spaced as pixels on pane attributes.put(TextAttribute.TRACKING, tracking); // 8 attributes.put(TextAttribute.SIZE, (int)charWidth); Font spacedFont = baseFont.deriveFont(attributes); baseFont = spacedFont; } private void logFontMetrics(){ FontMetrics metrics = this.getGraphics().getFontMetrics(baseFont); logger.info("baseFont.getSize()" + baseFont.getSize()); logger.info("baseFont.getSize2D()" + baseFont.getSize2D()); // get the height of a line of text in this // font and render context int hgt = metrics.getHeight(); logger.info("metrics.getHeight()" + metrics.getHeight()); logger.info("metrics.getMaxAdvance()" + metrics.getMaxAdvance()); // get the advance of my text in this font logger.info("metrics.getLeading()" + metrics.getLeading()); // logger.info("metrics.getLeading()" + metrics.getWidths() //logger.info("metrics.getMaxAdvance()" + metrics.get // and render context int adv = metrics.stringWidth("A"); logger.info("metrics.stringWidth(\"A\")" + metrics.stringWidth("AAAAAAAAAA")); logger.info("metrics.stringWidth(\"T\")" + metrics.stringWidth("T")); logger.info("metrics.stringWidth(\"c\")" + metrics.stringWidth("c")); logger.info("baseFont.getAttributes().get(WIDTH_REGULAR)" + baseFont.getAttributes().get(TextAttribute.WIDTH_REGULAR)); // logger.info("metrics.stringWidth(\"c\")" + metrics.get // calculate the size of a box to hold the // text with some padding. } // should throw no valid base error public Point getBasePosition(Base base){ if(base == null){ return null; } int x = (int) (base.getPosition() * charWidth); int y = (int) (alignment.getSequenceIndex(base.getSequence()) * charHeight); Point pos = new Point(x,y); return pos; } public Base selectBaseAt(Point pos) throws InvalidAlignmentPositionException{ Base base = null; base = getBaseAt(pos); if(base != null){ alignment.setSelectionAt(base.getPosition(), alignment.getSequenceIndex(base.getSequence()),true); } return base; } public int getUngapedPositionInSequenceAt(Point pos) throws InvalidAlignmentPositionException{ int ungapedPos = 0; Base base = getBaseAt(pos); if(base != null){ ungapedPos = base.getUngapedPosition(); } return ungapedPos; } public int getPositionInSequenceAt(Point pos) throws InvalidAlignmentPositionException{ int xPos = 0; Base base = getBaseAt(pos); if(base != null){ xPos = base.getPosition(); } return xPos; } public void selectColumnAt(Point pos) { int columnIndex = getColumnAt(pos); getAlignment().selectColumn(columnIndex); } public Base getBaseAt(Point pos) throws InvalidAlignmentPositionException{ Point matrixPoint = paneCoordToMatrixCoord(pos); Base base = null; if(alignment.isPositionValid(matrixPoint.x,matrixPoint.y)){ Sequence seq = (Sequence) alignment.getSequences().get(matrixPoint.y); base = new Base(seq, matrixPoint.x); } else{ base = null; } return base; } public Base getClosestBaseAt(Point pos){ Point matrixPoint = paneCoordToMatrixCoord(pos); Base base = null; if(alignment.isPositionValid(matrixPoint.x,matrixPoint.y)){ Sequence seq = (Sequence) alignment.getSequences().get(matrixPoint.y); base = new Base(seq, matrixPoint.x); } else{ // get last sequence Sequence seq = (Sequence) alignment.getSequences().get(alignment.getSequences().getSize()-1); base = new Base(seq, matrixPoint.x); } return base; } public int getColumnAt(Point pos){ Point matrixPoint = paneCoordToMatrixCoord(pos); return matrixPoint.x; } public void setAlignment(Alignment alignment){ this.alignment = alignment; // this.infoLabel.setAlignment(alignment); this.validateSize(); } // // Mainly for performance test-developing // private long endTime; private int drawCounter = 0; private int DRAWCOUNT_LOF_INTERVAL = 1; public void repaintForceRuler(){ rulerIsDirty = true; repaint(); } public void paintComponent(Graphics g){ super.paintComponent(g); paintAlignment(g); } public void paintAlignment(Graphics g){ drawCounter ++; long startTime = System.currentTimeMillis(); if(drawCounter % DRAWCOUNT_LOF_INTERVAL == 0){ logger.info("Time from last endTim " + (startTime - endTime) + " milliseconds"); } // logger.info("paintClipBounds" + g.getClipBounds()); Graphics2D g2d = (Graphics2D) g; // This need to be off because I use exact font width in createAdjustedDerivedBaseFont g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_OFF); g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED); // g2d.setRenderingHint(RenderingHints.KEY_RENDERING, // RenderingHints.VALUE_RENDER_QUALITY); // g2d.setRenderingHint(RenderingHints.KEY_DITHERING, // RenderingHints.VALUE_DITHER_DISABLE); // g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, // RenderingHints.VALUE_COLOR_RENDER_SPEED); // g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, // RenderingHints.VALUE_COLOR_RENDER_QUALITY); // Font g2d.setFont(baseFont); // to get some space left and bottom around characters int charCenterXOffset = (int) (0.15 * charWidth); int charCenterYOffset = (int) (0.2 * charHeight); // What part of alignment matrix is in view (what part of matrix is in graphical view) Rectangle clip = g2d.getClipBounds(); Rectangle matrixClip = paneCoordToMatrixCoord(clip); int xMin = matrixClip.x - 1; int yMin = matrixClip.y - 1; int xMax = (int) matrixClip.getMaxX() + 1; int yMax = (int) matrixClip.getMaxY() + 1; // adjust for part of matrix that exists xMin = Math.max(0, xMin); yMin = Math.max(0, yMin); xMax = Math.min(alignment.getMaxX(), xMax); yMax = Math.min(alignment.getMaxY(), yMax); // int drawWidth = xMax - xMin; // int drawHeight = yMax - yMin; // Draw bg (gap-background - makes us save some drawing operations) if(alignment.isAAAlignment()){ g2d.setColor(colorSchemeAminoAcid.getBaseBackgroundColor(NucleotideUtilities.GAP)); }else{ g2d.setColor(colorSchemeNucleotide.getBaseBackgroundColor(NucleotideUtilities.GAP)); } g2d.fillRect(clip.x,clip.y,clip.width,clip.height); // left and right of viewport so scrolling always looks good int EXTRA_POSITIONS = 1; // If it is to be translated AATranslator aaTransSeq = null; if(showTranslation || showTranslationOnePos){ aaTransSeq = new AATranslator(alignment.getAlignentMeta().getCodonPositions(), alignment.getGeneticCode()); EXTRA_POSITIONS = 1; // one full codon } // logger.info("matrixClip.getMaxX()" + matrixClip.getMaxX()); // logger.info("matrixClip.getMaxY()" + matrixClip.getMaxY()); // logger.info("clip.getMaxX()" + clip.getMaxX()); // logger.info("clip.getMaxY()" + clip.getMaxY()); // logger.info("xMax" + xMax); // logger.info("yMax" + yMax); // logger.info("charWidth" + charWidth); // small chars have their own loop here if(charWidth < 1){ if(showTranslationOnePos || showTranslation){ for(int y = clip.y; y < clip.getMaxY(); y++){ int ySeq =(int)((double)y * (1/(double)charWidth)); drawCharBuffer.clear(); if(ySeq < alignment.getMaxY()){ aaTransSeq.setSequence(alignment.getSequences().get(ySeq)); double maxX = clip.getMaxX(); if(showTranslationOnePos){ if(maxX > alignment.getAlignentMeta().getCodonPositions().getLengthOfTranslatedPos()){ maxX = alignment.getAlignentMeta().getCodonPositions().getLengthOfTranslatedPos(); } for(int x = clip.x; x < maxX ; x++){ int xPos =(int)((double)x * (1/(double)charWidth)); if(alignment.isPositionValid(xPos, ySeq)){ byte base = alignment.getBaseAt(xPos,ySeq); if(ignoreGapInTranslation){ AminoAcid acid = aaTransSeq.getAAinNoGapTranslatedPos(x); drawAminoAcids(g2d,acid.getCodeByteVal(),x,y, x, y, 1, 1, charCenterXOffset, charCenterYOffset); }else{ AminoAcid acid = aaTransSeq.getAAinTranslatedPos(x); drawAminoAcids(g2d,acid.getCodeByteVal(),x,y, x, y, 1, 1, charCenterXOffset, charCenterYOffset); } } } }else{ // X Loop Start for(int x = clip.x; x < maxX ; x++){ int xPos =(int)((double)x * (1/(double)charWidth)); if(alignment.isPositionValid(xPos, ySeq)){ byte base = alignment.getBaseAt(xPos,ySeq); if(ignoreGapInTranslation){ drawTranslatedNucleotidesSkipGap(g2d, base,xPos,ySeq,0,0, 0, 0, aaTransSeq, charCenterXOffset, charCenterYOffset); } else{ if(y==1){ // logger.info("xpos=" + xPos); } drawTranslatedNucleotides(g2d,base,xPos,ySeq,aaTransSeq, charCenterXOffset, charCenterYOffset); } } } } } // Now paint the buffered colors HashSet<Color> unique = new CharBufferCreator(drawCharBuffer).getUniqueBGColors(); for(Color bgColor: unique){ int endPos = 0; int MAX_LEN = 1000; while(endPos < drawCharBuffer.length()){ int startPos = endPos; //int drawCount = drawCharBuffer.getNextSameBGColorCount(startPos, MAX_LEN); int drawCount = 1; if(drawCharBuffer.getBgColor(startPos) == bgColor){ drawNucleotideBackground(g2d, startPos + (int)clip.getMinX(), y, drawCount, 1, drawCharBuffer.getBgColor(startPos)); } endPos = startPos + drawCount; } } // No painting chars because they are to small } }else{ // Always start at closest even 10 double startY = clip.y; startY = Math.floor(startY/100) * 100; for(int y = (int)startY; y < clip.getMaxY(); y++){ int ySeq =(int)((double)y * (1/(double)charWidth)); if(ySeq < alignment.getMaxY()){ // aaTransSeq.setSequence(alignment.getSequences().get(ySeq)); // X Loop Start drawCharBuffer.clear(); for(int x = clip.x; x < clip.getMaxX() ; x++){ int xPos =(int)((double)x * (1/(double)charWidth)); if(alignment.isPositionValid(xPos, ySeq)){ byte base = alignment.getBaseAt(xPos,ySeq); // Draw as Nucleotides if(alignment.isNucleotideAlignment()){ drawNucleotides(g2d,base,xPos,ySeq,x,y,1,1,0, 0); } // Draw as AA else{ drawAminoAcids(g2d,base,xPos,ySeq,x,y,1,1, 0, 0); } } } // Now paint the buffered colors HashSet<Color> unique = new CharBufferCreator(drawCharBuffer).getUniqueBGColors(); //Color bgColor = colorSchemeNucleotide.getBaseBackgroundColor(NucleotideUtilities.T); for(Color bgColor: unique){ int endPos = 0; int MAX_LEN = 1000; while(endPos < drawCharBuffer.length()){ int startPos = endPos; //int drawCount = drawCharBuffer.getNextSameBGColorCount(startPos, MAX_LEN); int drawCount = 1; if(drawCharBuffer.getBgColor(startPos) == bgColor){ drawNucleotideBackground(g2d, startPos + (int)clip.getMinX(), y, drawCount, 1, drawCharBuffer.getBgColor(startPos)); } endPos = startPos + drawCount; } } // No painting chars because they are to small } } } // Draw excludes - only if not if(!showTranslationOnePos){ // calculaate height for excludes (this is to avoid drawing below alignment if alignment is not filling panel) int drawExcludesHeight = (int) Math.min(this.getVisibleRect().getHeight(), alignment.getSize() * charHeight); //for(int x = xMin; x < xMax ; x++){ for(int x = clip.x; x < clip.getMaxX() ; x++){ int xPos =(int)((double)x * (1/(double)charWidth)); if(alignment.isExcluded(xPos) == true){ g2d.setColor(ColorScheme.GREY_TRANSPARENT); g2d.fillRect(x, this.getVisibleRect().y, 1, drawExcludesHeight); logger.info("drawExclude"); } } } } // Normal char width else{ if(showTranslationOnePos){ for(int y = yMin; y < yMax ; y = y + 1){ aaTransSeq.setSequence(alignment.getSequences().get(y)); // Draw one extra codon at start and end int minX = (int)(matrixClip.getMinX()-EXTRA_POSITIONS); if(minX < 0){ minX=0; } int maxX = (int)(matrixClip.getMaxX()+EXTRA_POSITIONS); if(maxX > alignment.getAlignentMeta().getCodonPositions().getLengthOfTranslatedPos()){ maxX = alignment.getAlignentMeta().getCodonPositions().getLengthOfTranslatedPos(); } // X Loop Start drawCharBuffer.clear(); int yPaneCoord = (int)(y * charHeight); int widthInPaneCoord = (int)charWidth * 1; int heightInPaneCoord = (int)charHeight; for(int x = minX; x < maxX ; x++){ int xPaneCoord = (int)(x * charWidth); if(ignoreGapInTranslation){ AminoAcid acid = aaTransSeq.getAAinNoGapTranslatedPos(x); drawAminoAcids(g2d,acid.getCodeByteVal(),x,y, xPaneCoord, yPaneCoord, widthInPaneCoord, heightInPaneCoord, charCenterXOffset, charCenterYOffset); }else{ AminoAcid acid = aaTransSeq.getAAinTranslatedPos(x); drawAminoAcids(g2d,acid.getCodeByteVal(),x,y, xPaneCoord, yPaneCoord, widthInPaneCoord, heightInPaneCoord, charCenterXOffset, charCenterYOffset); } } // Now paint the buffered background colors HashSet<Color> unique = new CharBufferCreator(drawCharBuffer).getUniqueBGColors(); int xPaneStartCoord = (int)(minX * charWidth); for(Color bgColor: unique){ int endPos = 0; int MAX_LEN = 1000; while(endPos < drawCharBuffer.length()){ int startPos = endPos; //int drawCount = drawCharBuffer.getNextSameBGColorCount(startPos, MAX_LEN); int drawCount = 1; if(drawCharBuffer.getBgColor(startPos) == bgColor){ drawNucleotideBackground(g2d,xPaneStartCoord + (startPos * widthInPaneCoord), yPaneCoord, widthInPaneCoord * drawCount, heightInPaneCoord, drawCharBuffer.getBgColor(startPos)); } endPos = startPos + drawCount; } } // Now draw the buffered chars if(charHeight > MAX_CHARSIZE_TO_DRAW){ charCenterXOffset = (int)(0.2*charWidth); CharBufferCreator cbCreator = new CharBufferCreator(drawCharBuffer); ArrayList<DrawCharBuffer> buffs = cbCreator.createFGBuffers(); //logger.info(buffs.size()); for(DrawCharBuffer charBuff: buffs){ int endPos = 0; int MAX_LEN = 100; while(endPos < charBuff.length()){ int startPos = endPos; int drawCount = charBuff.getNextSameFGColorCount(startPos, MAX_LEN); drawCharsBuffered(g2d, charBuff.byteBuffer, startPos, drawCount, xMin + startPos, y, charBuff.getFgColor(startPos), charCenterXOffset, charCenterYOffset); endPos = startPos + drawCount; } } } } }else{ for(int y = yMin; y < yMax ; y = y + 1){ if(showTranslation){ aaTransSeq.setSequence(alignment.getSequences().get(y)); } //aaTransSeq.setSequence(alignment.getSequences().get(y)); // Draw one extra codon at start and end int minX = (int)(matrixClip.getMinX()-EXTRA_POSITIONS); if(minX < 0){ minX=0; } int maxX = (int)(matrixClip.getMaxX()+EXTRA_POSITIONS); if(maxX > alignment.getLengthAt(y)){ maxX = alignment.getLengthAt(y); } drawCharBuffer.clear(); int widthInPaneCoord = (int)charWidth; int heightInPaneCoord = (int)charHeight; int yPaneCoord = (int)(y * charHeight); // X Loop Start for(int x = minX; x < maxX ; x++){ int xPaneCoord = (int)(x * charWidth); // Draw as nucleotides if(alignment.isNucleotideAlignment()){ byte base = alignment.getBaseAt(x,y); // Draw as translated if(showTranslation){ if(ignoreGapInTranslation){ drawTranslatedNucleotidesSkipGap(g2d, base,x,y,xPaneCoord,yPaneCoord, widthInPaneCoord, heightInPaneCoord, aaTransSeq, charCenterXOffset, charCenterYOffset); } else{ drawTranslatedNucleotides(g2d,base,x,y, aaTransSeq, charCenterXOffset, charCenterYOffset); } }else{ drawNucleotides(g2d, base,x,y,xPaneCoord,yPaneCoord, widthInPaneCoord, heightInPaneCoord, charCenterXOffset, charCenterYOffset); } } // Draw as AminoAcids else{ byte charAsByte = alignment.getBaseAt(x,y); drawAminoAcids(g2d,charAsByte,x,y, xPaneCoord, yPaneCoord, widthInPaneCoord, heightInPaneCoord, charCenterXOffset, charCenterYOffset); } } // Now paint the buffered background colors HashSet<Color> unique = new CharBufferCreator(drawCharBuffer).getUniqueBGColors(); int xPaneStartCoord = (int)(minX * charWidth); for(Color bgColor: unique){ int endPos = 0; int MAX_LEN = 1000; while(endPos < drawCharBuffer.length()){ int startPos = endPos; //int drawCount = drawCharBuffer.getNextSameBGColorCount(startPos, MAX_LEN); int drawCount = 1; if(drawCharBuffer.getBgColor(startPos) == bgColor){ drawNucleotideBackground(g2d,xPaneStartCoord + (startPos * widthInPaneCoord), yPaneCoord, widthInPaneCoord * drawCount, heightInPaneCoord, drawCharBuffer.getBgColor(startPos)); //drawNucleotideBackground(g2d,xPaneStartCoord + (startPos * widthInPaneCoord), yPaneCoord, widthInPaneCoord * drawCount, heightInPaneCoord, drawCharBuffer.getBgColor(startPos), drawCharBuffer.getByte(startPos)); } endPos = startPos + drawCount; } } // Now draw buffer of chars // Draw all same chars at once(this is a lot faster than drawing them one at a time once - at least on linux) if(charHeight > MAX_CHARSIZE_TO_DRAW){ charCenterXOffset = (int)(0.2*charWidth); CharBufferCreator cbCreator = new CharBufferCreator(drawCharBuffer); ArrayList<DrawCharBuffer> buffs = cbCreator.createFGBuffers(); //logger.info(buffs.size()); for(DrawCharBuffer charBuff: buffs){ int endPos = 0; int MAX_LEN = 100; while(endPos < charBuff.length()){ int startPos = endPos; int drawCount = charBuff.getNextSameFGColorCount(startPos, MAX_LEN); drawCharsBuffered(g2d, charBuff.byteBuffer, startPos, drawCount, xMin + startPos, y, charBuff.getFgColor(startPos), charCenterXOffset, charCenterYOffset); //drawCharsBuffered(g2d, charBuff.byteBuffer, startPos, drawCount, xPaneStartCoord + (startPos * widthInPaneCoord), y, charBuff.getFgColor(startPos), charCenterXOffset, charCenterYOffset); endPos = startPos + drawCount; } } } }// x loop end }// y loop end // Draw excludes if(! showTranslationOnePos){ // calculaate height for excludes (this is to avoid drawing below alignment if alignment is not filling panel) int drawExcludesHeight = (int) Math.min(this.getVisibleRect().getHeight(), alignment.getSize() * charHeight); for(int x = xMin; x < xMax ; x++){ if(alignment.isExcluded(x) == true){ g2d.setColor(ColorScheme.GREY_TRANSPARENT); g2d.fillRect((int)(x * charWidth), this.getVisibleRect().y, (int)charWidth, drawExcludesHeight); } } } } if(drawCounter % DRAWCOUNT_LOF_INTERVAL == 0){ endTime = System.currentTimeMillis(); logger.info("Alignment pane PaintComponent took " + (endTime - startTime) + " milliseconds"); } // repaint ruler also if needed if(clip.x != lastClip.x || clip.width != lastClip.width || rulerIsDirty){ alignmentRuler.repaint(); rulerIsDirty = false; } lastClip = clip; } private void drawAminoAcids(Graphics2D g2d, byte charAsByte, int x, int y, int xPaneCoord, int yPaneCoord, int widthInPaneCoord, int heightInPaneCoord, int charCenterXOffset, int charCenterYOffset){ // Set default AminoAcid acid = AminoAcid.getAminoAcidFromByte(charAsByte); Color baseForegroundColor = colorSchemeAminoAcid.getAminoAcidForgroundColor(acid, x, alignment); Color baseBackgroundColor = colorSchemeAminoAcid.getAminoAcidBackgroundColor(acid, x, alignment); // get char to draw byteToDraw = charAsByte; // adjustment if only diff to be shown if(highlightDiffTrace){ // TODO CHANGE THIS SO IT IS WORKING EVEN IF TRACING SEQUENCE IS SHORTER THAN OTHER if(y != differenceTraceSequencePosition && acid == AminoAcid.getAminoAcidFromByte(alignment.getBaseAt(x,differenceTraceSequencePosition))){ byteToDraw = '.'; baseBackgroundColor = colorSchemeAminoAcid.getAminoAcidBackgroundColor(AminoAcid.GAP, x, alignment); } } // adjustment if non-cons to be highlighted if(highlightNonCons){ if(acid == AminoAcid.GAP){ // no color on gap even if they are in maj.cons } else if(alignment.getHistogram().isMajorityRuleConsensus(x,acid.intVal)){ baseBackgroundColor = colorSchemeAminoAcid.getAminoAcidConsensusBackgroundColor(); //baseBackgroundColor = colorSchemeAminoAcid.getAminoAcidBackgroundColor(AminoAcid.GAP); } } // adjustment if cons to be highlighted if(highlightCons){ if(acid == AminoAcid.GAP){ // no color on gap even if they are in maj.cons } else if(! alignment.getHistogram().isMajorityRuleConsensus(x,acid.intVal)){ baseBackgroundColor = colorSchemeAminoAcid.getAminoAcidConsensusBackgroundColor(); //baseBackgroundColor = colorSchemeAminoAcid.getAminoAcidBackgroundColor(AminoAcid.GAP); } } // Temp Selection // We have to calculate within this way - because rect.contains(Point) is always returning false on a 0-width or 0 height Rectangle boolean isPointWithinSelectionRect = false; if(tempSelectionRect != null){ if(x <= tempSelectionRect.getMaxX() && x >= tempSelectionRect.getMinX() && y <= tempSelectionRect.getMaxY() && y >= tempSelectionRect.getMinY()){ isPointWithinSelectionRect = true; } } // draw selection and temp selection if(alignment.isBaseSelected(x,y) || (tempSelectionRect != null && isPointWithinSelectionRect)){ baseBackgroundColor = colorSchemeAminoAcid.getAminoAcidSelectionBackgroundColor(acid, x, alignment); baseForegroundColor = colorSchemeAminoAcid.getAminoAcidSelectionForegroundColor(acid, x, alignment); //drawNucleotideBackground(g2d, xPaneCoord, yPaneCoord, widthInPaneCoord, heightInPaneCoord, 1, baseBackgroundColor); } // Put char letter in buffer drawCharBuffer.append(byteToDraw, baseForegroundColor, baseBackgroundColor); } private void drawTranslatedNucleotides(Graphics2D g2d, byte base, int x, int y, AATranslator aaTransSeq, int charCenterXOffset, int charCenterYOffset){ int baseVal = NucleotideUtilities.baseValFromBase(base); // get char to draw // TODO remove this hack (file-sequences are including \n and they are removed when apppending to stringbuilder) if(base == '\n'){ base = ' '; } byteToDraw = base; AminoAcid acid = aaTransSeq.getAminoAcidAtNucleotidePos(x); // Set default Color baseForegroundColor = colorSchemeNucleotide.getBaseForegroundColor(baseVal); Color backgroundColor = colorSchemeNucleotide.getAminoAcidBackgroundColor(acid); // We have to calculate within this way - because rect.contains(Point) is always returning false on a 0-width or 0 height Rectangle boolean isPointWithinSelectionRect = false; if(tempSelectionRect != null){ if(x <= tempSelectionRect.getMaxX() && x >= tempSelectionRect.getMinX() && y <= tempSelectionRect.getMaxY() && y >= tempSelectionRect.getMinY()){ isPointWithinSelectionRect = true; } } // adjust colors if selected and temp selection if(alignment.isBaseSelected(x,y) || (tempSelectionRect != null && isPointWithinSelectionRect)){ //acid = aaTransSeq.getAminoAcidAtNucleotidePos(x); backgroundColor = colorSchemeNucleotide.getAminoAcidSelectionBackgroundColor(acid); } // Draw char letter if(! drawAminoAcidCode){ // Put char letter in buffer drawCharBuffer.append(byteToDraw, baseForegroundColor, backgroundColor); }else{ if(aaTransSeq.isCodonSecondPos(x)){ drawCharBuffer.append(acid.getCodeByteVal(), Color.white, backgroundColor); }else{ drawCharBuffer.append((byte)' ', baseForegroundColor, backgroundColor); } } } private void drawTranslatedNucleotidesSkipGap(Graphics2D g2d, byte base, int x, int y, int xPaneCoord, int yPaneCoord, int width, int height, AATranslator aaTransSeq, int charCenterXOffset, int charCenterYOffset){ int baseVal = NucleotideUtilities.baseValFromBase(base); // get char to draw // TODO remove this hack (file-sequences are including \n and they are removed when apppending to stringbuilder) if(base == '\n'){ base = ' '; } byteToDraw = base; AminoAcid acid = aaTransSeq.getNoGapAminoAcidAtNucleotidePos(x); int acidStartPos = aaTransSeq.getCachedClosestStartPos(); // Set default Color baseForegroundColor = colorSchemeNucleotide.getBaseForegroundColor(baseVal); Color backgroundColor = colorSchemeNucleotide.getAminoAcidBackgroundColor(acid); // We have to calculate within this way - because rect.contains(Point) is always returning false on a 0-width or 0 height Rectangle boolean isPointWithinSelectionRect = false; if(tempSelectionRect != null){ if(x <= tempSelectionRect.getMaxX() && x >= tempSelectionRect.getMinX() && y <= tempSelectionRect.getMaxY() && y >= tempSelectionRect.getMinY()){ isPointWithinSelectionRect = true; } } // adjust colors if selected and temp selection if(alignment.isBaseSelected(x,y) || (tempSelectionRect != null && isPointWithinSelectionRect)){ //acid = aaTransSeq.getAminoAcidAtNucleotidePos(x); backgroundColor = colorSchemeNucleotide.getAminoAcidSelectionBackgroundColor(acid); } // Draw char letter if(! drawAminoAcidCode){ // Put char letter in buffer drawCharBuffer.append(byteToDraw, baseForegroundColor, backgroundColor); }else{ if(x == acidStartPos + 1){ drawCharBuffer.append(acid.getCodeByteVal(), Color.white, backgroundColor); }else{ drawCharBuffer.append((byte)' ', baseForegroundColor, backgroundColor); } } } private void drawNucleotides(Graphics2D g2d, byte residue, int x, int y, int xPaneCoord, int yPaneCoord, int width, int height, int charCenterXOffset, int charCenterYOffset){ int baseVal = NucleotideUtilities.baseValFromBase(residue); byteToDraw = residue; // Set default Color baseForegroundColor = colorSchemeNucleotide.getBaseForegroundColor(baseVal); Color baseBackgroundColor = colorSchemeNucleotide.getBaseBackgroundColor(baseVal); // We have to calculate within this way - because rect.contains(Point) is always returning false on a 0-width or 0 height Rectangle boolean isPointWithinSelectionRect = false; if(tempSelectionRect != null){ if(x <= tempSelectionRect.getMaxX() && x >= tempSelectionRect.getMinX() && y <= tempSelectionRect.getMaxY() && y >= tempSelectionRect.getMinY()){ isPointWithinSelectionRect = true; } } // adjustment if only diff to be shown if(highlightDiffTrace){ // TODO CHANGE THIS SO IT IS WORKING EVEN IF TRACING SEQUENCE IS SHORTER THAN OTHER if(y != differenceTraceSequencePosition){ if(NucleotideUtilities.baseValFromBase(residue) == NucleotideUtilities.baseValFromBase(alignment.getBaseAt(x,differenceTraceSequencePosition))){ byteToDraw = '.'; //logger.info("bytetodraw"); baseBackgroundColor = colorSchemeNucleotide.getBaseBackgroundColor(NucleotideUtilities.GAP); } } } // adjustment if non-cons to be highlighted if(highlightNonCons){ NucleotideHistogram nucHistogram = (NucleotideHistogram) alignment.getHistogram(); if(baseVal == NucleotideUtilities.GAP){ // no color on gap even if they are in maj.cons } else if(nucHistogram.isMajorityRuleConsensus(x,baseVal)){ baseBackgroundColor = colorSchemeNucleotide.getBaseConsensusBackgroundColor(); //baseBackgroundColor = colorSchemeNucleotide.getBaseBackgroundColor(NucleotideUtilities.UNKNOWN); } } if(highlightCons){ NucleotideHistogram nucHistogram = (NucleotideHistogram) alignment.getHistogram(); if(baseVal == NucleotideUtilities.GAP){ // no color on gap even if they are in maj.cons } else if(! nucHistogram.isMajorityRuleConsensus(x,baseVal)){ baseBackgroundColor = colorSchemeNucleotide.getBaseConsensusBackgroundColor(); //baseBackgroundColor = colorSchemeNucleotide.getBaseBackgroundColor(NucleotideUtilities.UNKNOWN); } } // adjust colors if selected and temp selection if(alignment.isBaseSelected(x,y) || (tempSelectionRect != null && isPointWithinSelectionRect)){ baseBackgroundColor = colorSchemeNucleotide.getBaseSelectionBackgroundColor(baseVal); baseForegroundColor = colorSchemeNucleotide.getBaseSelectionForegroundColor(baseVal); } // Draw background if(baseBackgroundColor == colorSchemeNucleotide.getBaseBackgroundColor(NucleotideUtilities.GAP)){ // dont draw if gap or anything with gap-color (already bg-color is drawn on whole pane) // this is to improve performance }else{ // drawNucleotideBackground(g2d, xPaneCoord, yPaneCoord, width, height, 1, baseBackgroundColor); } // Put char letter in buffer drawCharBuffer.append(byteToDraw, baseForegroundColor, baseBackgroundColor); } private void drawCharsBuffered(Graphics2D g2d, byte[] bytesToDraw, int startPos, int drawCount, int x, int y, Color baseForegroundColor, int charCenterXOffset, int charCenterYOffset) { g2d.setColor(baseForegroundColor); if(charHeight > MAX_CHARSIZE_TO_DRAW){ g2d.drawBytes(bytesToDraw, startPos, drawCount, (int)((x + 0) * charWidth + charCenterXOffset), (int)(y * charHeight + charHeight - charCenterYOffset)); //g2d.drawBytes(bytesToDraw, startPos, drawCount, x + charCenterXOffset, (int)(y * charHeight + charHeight - charCenterYOffset)); } } private void drawNucleotideLetter(Graphics2D g2d, byte[] bytesToDraw, int x, int y, Color baseForegroundColor, int charCenterXOffset, int charCenterYOffset) { g2d.setColor(baseForegroundColor); if(charHeight > MAX_CHARSIZE_TO_DRAW){ g2d.drawBytes(bytesToDraw, 0, bytesToDraw.length, (int)((x + 0) * charWidth + charCenterXOffset), (int)(y * charHeight + charHeight - charCenterYOffset)); } } private void drawNucleotideBackground(Graphics2D g2d, int xPaneCoord, int yPaneCoord, int width, int height, Color baseBackgroundColor){ g2d.setColor(baseBackgroundColor); g2d.fillRect(xPaneCoord,yPaneCoord,width,height); } // // TODO it is not working with very large alignments // private void drawNucleotideBackground(Graphics2D g2d, int xPaneCoord, int yPaneCoord, int width, int height, Color baseBackgroundColor, byte b){ g2d.setColor(baseBackgroundColor); g2d.drawRect(xPaneCoord,yPaneCoord,width,height); String draw = "" + (char) b; char[] drawChars = new char[(char) b]; g2d.setColor(Color.BLACK); // g2d.setColor(Color.BLACK); // logger.info("" + (char) b ); // g2d.drawBytes(new byte[(byte)'e'], 0, 1, xPaneCoord, yPaneCoord); // g2d.drawBytes(data, offset, length, x, y) // g2d.drawChars(drawChars, 0, 1, xPaneCoord + 1, yPaneCoord + 12); g2d.drawString(draw, xPaneCoord + 1, yPaneCoord + 12); //g2d.drawBytes(bytesToDraw, 0, bytesToDraw.length, (int)((x + 0) * charWidth + charCenterXOffset), (int)(y * charHeight + charHeight - charCenterYOffset)); } private void drawAminoAcidCode(Graphics2D g2d, int xAlignmentCoord, int yAlignmentCoord, AminoAcid acid, Color foregroundColor, int charCenterXOffset, int charCenterYOffset) { g2d.setColor(foregroundColor); if(charHeight > MAX_CHARSIZE_TO_DRAW){ g2d.drawBytes(acid.getCodeByteArray(), 0, 1, (int)(xAlignmentCoord * charWidth + charCenterXOffset + charWidth), (int)(yAlignmentCoord * charHeight + charHeight - charCenterYOffset)); } } private void drawAminoAcidCodeSimple(Graphics2D g2d, int xAlignmentCoord, int yAlignmentCoord, AminoAcid acid, Color foregroundColor, int charCenterXOffset, int charCenterYOffset) { g2d.setColor(foregroundColor); if(charHeight > MAX_CHARSIZE_TO_DRAW){ g2d.drawBytes(acid.getCodeByteArray(), 0, 1, (int)(xAlignmentCoord * charWidth + charCenterXOffset), (int)(yAlignmentCoord * charHeight + charHeight - charCenterYOffset)); } } private void drawTranslatedTripletAminoAcidBackground(Graphics2D g2d, int xAlignmentCoord, int yAlignmentCoord, Color aminoAcidBackgroundColor, byte[] codon) { // draw background g2d.setColor(aminoAcidBackgroundColor); g2d.fillRect((int)(xAlignmentCoord * charWidth), (int)(yAlignmentCoord * charHeight), (int)charWidth * codon.length, (int)charHeight); } public Alignment getAlignment() { return alignment; } public void validateSequenceOrder(){ // verify that tracing sequence not is out of index if(differenceTraceSequencePosition >= alignment.getSize()){ differenceTraceSequencePosition = 0; } } public int selectWithin(Rectangle rect){ // First clear int selectionSize = addSelectionWithin(rect); return selectionSize; } public int selectColumnsWithin(Rectangle rect) { // First clear int selectionSize = addColumnSelectionWithin(rect); return selectionSize; } public int addColumnSelectionWithin(Rectangle rect){ int nSelection = 0; // grow so all sequences are included Rectangle columns = new Rectangle(rect.x, 0, rect.width, this.getHeight()); return addSelectionWithin(columns); } public int addSelectionWithin(Rectangle rect){ int nSelection = 0; // calculate what part of alignment matrix is in view (what part of matrix is in graphical view) Rectangle bounds = paneCoordToMatrixCoord(rect); alignment.setSelectionWithin(bounds); return nSelection; } public void setTempSelection(Rectangle selectRect) { // change rect to matrixCoordSys this.tempSelectionRect = paneCoordToMatrixCoord(selectRect); } public void clearTempSelection() { this.tempSelectionRect = null; } public Rectangle paneCoordToMatrixCoord(Rectangle rect){ // TODO maybe problem when calculating a 0-width rect - then it will give eg. xmin=34 xmax=35 // logger.info("rect.getMinX()" + rect.getMinX()); // logger.info("rect.getMaxX()" + rect.getMaxX()); // logger.info("rect.getMinX()/charWidth" + rect.getMinX()/charWidth); // int matrixMinX = (int) Math.floor(rect.getMinX()/charWidth); // always round down int matrixMaxX = (int) Math.floor(rect.getMaxX()/charWidth); // always round up int matrixMinY = (int) Math.floor(rect.getMinY()/charHeight); // always round down int matrixMaxY = (int) Math.floor(rect.getMaxY()/charHeight); // always round down // logger.info("matrixMinX" + matrixMinX); // logger.info("matrixMaxX" + matrixMaxX); //// logger.info(getMatrixTopOffset()); // Rectangle converted = new Rectangle(matrixMinX, matrixMinY, matrixMaxX - matrixMinX, matrixMaxY - matrixMinY); return converted; } // todo this should be listening to changes in alignmnet instead public void updateStatisticsLabel(){ // logger.info("unimplemented should be done by changelistener"); } public void validateSize() { // Set component preferred size Dimension prefSize = getCalculatedPreferredSize(); this.setPreferredSize(prefSize); this.updateStatisticsLabel(); this.rulerIsDirty = true; this.revalidate(); } @Override public void setSize(Dimension d) { super.setSize(d); } @Override public Dimension getPreferredSize() { return getCalculatedPreferredSize(); } private Dimension getCalculatedPreferredSize(){ if(showTranslationOnePos){ return new Dimension((int) (charWidth * alignment.getAlignentMeta().getCodonPositions().getLengthOfTranslatedPos()), (int)(charHeight * alignment.getSize())); }else{ return new Dimension((int) (charWidth * alignment.getMaximumSequenceLength()), (int)(charHeight * alignment.getSize())); } } public Point paneCoordToMatrixCoord(Point pos){ int matrixX = (int) Math.floor(pos.getX() / charWidth); int matrixY = (int) Math.floor(pos.getY() / charHeight); Point converted = new Point(matrixX, matrixY); return converted; } public Point matrixCoordToPaneCoord(Point pos){ int paneX = (int) (pos.getX() * charWidth); int paneY = (int) (pos.getY() * charHeight); Point converted = new Point(paneX, paneY); return converted; } public Rectangle matrixCoordToPaneCoord(Rectangle rect){ Point min = new Point((int)rect.getMinX(), (int)rect.getMinY()); // logger.info("min" + min); Point max = new Point((int)rect.getMaxX(), (int)rect.getMaxY()); // logger.info("max" + max); Rectangle converted = new Rectangle(matrixCoordToPaneCoord(min)); converted.add(matrixCoordToPaneCoord(max)); // logger.info("converted" + converted); return converted; } public boolean isPointWithinMatrix(Point pos) { Point matrixPoint = paneCoordToMatrixCoord(pos); return alignment.isPositionValid(matrixPoint.x, matrixPoint.y); } public void setInteractionMode(int interactionMode) { this.interactionMode = interactionMode; } public int getInteractionMode() { return this.interactionMode; } public double getCharHeight() { return this.charHeight; } public double getCharWidth() { return this.charWidth; } public void setDifferenceTraceSequence(Point pos) throws InvalidAlignmentPositionException { Point matrixPoint = paneCoordToMatrixCoord(pos); Sequence seq = null; if(alignment.isPositionValid(matrixPoint.x,matrixPoint.y)){ // todo this should be changed because problem when removed or moved this.differenceTraceSequencePosition = matrixPoint.y; } else{ throw new InvalidAlignmentPositionException("Position is out of range" + pos); } } public void setDifferenceTraceSequence(int nIndex){ this.differenceTraceSequencePosition = nIndex; } public Sequence getSequenceAt(Point pos) throws InvalidAlignmentPositionException { Point matrixPoint = paneCoordToMatrixCoord(pos); Sequence seq = null; if(alignment.isPositionValid(matrixPoint.x,matrixPoint.y)){ seq = (Sequence) alignment.getSequences().get(matrixPoint.y); } else{ throw new InvalidAlignmentPositionException("Position is out of range" + pos); } return seq; } public boolean isWithinExistingSelection(Point point) { boolean isSelected = false; try { Base base = getBaseAt(point); if(base != null){ isSelected = base.isSelected(); } } catch (InvalidAlignmentPositionException e) { // TODO Auto-generated catch block e.printStackTrace(); } return isSelected; } public void setShowTranslation(boolean showTranslation){ this.showTranslation = showTranslation; } public boolean isShowTranslation() { return showTranslation; } public void toggleTranslationOnePos() { this.showTranslationOnePos = ! this.showTranslationOnePos; this.validateSize(); } public boolean isShowTranslationOnePos() { return showTranslationOnePos; } public JComponent getRulerComponent(){ return this.alignmentRuler; } private class AlignmentRuler extends JPanel{ private NotUsed_AlignmentPane_Orig alignmentPane; public AlignmentRuler(NotUsed_AlignmentPane_Orig alignmentPane) { this.alignmentPane = alignmentPane; } public void paintComponent(Graphics g){ super.paintComponent(g); paintRuler(g); } public void paintRuler(Graphics g){ long startTime = System.currentTimeMillis(); //super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED); // g2d.setRenderingHint(RenderingHints.KEY_RENDERING, // RenderingHints.VALUE_RENDER_QUALITY); g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE); // g2d.setRenderingHint(RenderingHints.KEY_RENDERING, // RenderingHints.VALUE_RENDER_QUALITY); // g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, // RenderingHints.VALUE_ANTIALIAS_ON); // g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, // RenderingHints.VALUE_TEXT_ANTIALIAS_ON); // //g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, // RenderingHints.VALUE_FRACTIONALMETRICS_OFF); //g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, // RenderingHints.VALUE_COLOR_RENDER_SPEED); //g2d.setRenderingHint(RenderingHints.KEY_DITHERING, // RenderingHints.VALUE_DITHER_DISABLE); g2d.setFont(baseFont); // What part of alignment matrix is in view (what part of matrix is in graphical view) Rectangle alignmentPaneClip = alignmentPane.getVisibleRect(); Rectangle matrixClip = paneCoordToMatrixCoord(alignmentPaneClip); // todo calculate from font metrics double charCenterXOffset = 0.9997; // // Draw ruler background // Rectangle rulerRect = new Rectangle(this.getVisibleRect()); g2d.setColor(colorSchemeNucleotide.getBaseBackgroundColor(NucleotideUtilities.GAP)); g2d.fill(rulerRect); int offsetDueToScrollPanePosition = 0; if(charWidth >=1){ offsetDueToScrollPanePosition = alignmentPaneClip.x % (int)charWidth; offsetDueToScrollPanePosition = offsetDueToScrollPanePosition -1; } // Tickmarks int posTick = 0; int count = 0; int maxX = alignment.getMaxX(); // alignment maxX is int maxY = alignment.getMaxY(); for(int x = matrixClip.x ; x < matrixClip.getMaxX() + 1; x ++){ // TODO Ruler tickmark and numbers is off.... // draw background depending on codonpos // Only draw part of matrix that exists if(maxY > 0 && x >= 0 && x < maxX){ if(drawCodonPosRuler && ! showTranslationOnePos){ int codonPos = alignment.getCodonPosAt(x); //logger.info(codonPos); Color codonPosColor = Color.GREEN; if(codonPos == 0){ codonPosColor = Color.LIGHT_GRAY; }else if(codonPos == 1){ codonPosColor = Color.GREEN; }else if(codonPos == 2){ codonPosColor = Color.orange; }else if(codonPos == 3){ codonPosColor = Color.red; } g2d.setColor(codonPosColor); int boxHeight = 5; g2d.fillRect((int)(posTick * charCenterXOffset * charWidth - offsetDueToScrollPanePosition), (int) (rulerRect.getMaxY() - boxHeight), (int)charWidth, boxHeight); //g2d.fillRect((int)(x * charWidth), (int) (rulerRect.getMaxY() - 4), (int)charWidth, boxHeight); } g2d.setColor(Color.DARK_GRAY); // make every 5 a bit bigger if(x % 5 == 4 && charHeight > 0.6){ // it has to be 4 and not 0 due to the fact that 1:st base har position 0 in matrix g2d.drawLine((int)(posTick * charCenterXOffset * charWidth + charWidth/2 - offsetDueToScrollPanePosition), (int) (rulerRect.getMaxY() - 2), (int)(posTick * charCenterXOffset * charWidth + charWidth/2 - offsetDueToScrollPanePosition), (int)rulerRect.getMaxY() - 5); } // dont draw smallest tick if to small else if(charHeight > 4){ g2d.drawLine((int)(posTick * charCenterXOffset * charWidth + charWidth/2 - offsetDueToScrollPanePosition), (int) (rulerRect.getMaxY() - 2), (int)(posTick * charCenterXOffset * charWidth + charWidth/2 - offsetDueToScrollPanePosition), (int)rulerRect.getMaxY() - 3); } posTick ++; } count ++; } // NUMBERS int rulerCharWidth = 11; int rulerCharHeight = 11; Font rulerFont = new Font(baseFont.getName(), baseFont.getStyle(), (int)rulerCharWidth); g2d.setFont(rulerFont); // Only draw every 20-10000 pos int drawEveryNpos = 10; if(charHeight < 0.02){ drawEveryNpos = 10000; }else if(charHeight < 0.04){ drawEveryNpos = 5000; }else if(charHeight < 0.1){ drawEveryNpos = 1000; }else if(charHeight < 0.4){ drawEveryNpos = 500; }else if(charHeight < 1){ drawEveryNpos = 100; }else if(charHeight < 4){ drawEveryNpos = 50; }else if(charHeight < 5){ drawEveryNpos = 20; } // position numbers int pos = 0; for(int x = matrixClip.x ; x < matrixClip.getMaxX() + 1; x ++){ if(x % drawEveryNpos == 0){ String number = Integer.toString(x); int stringSizeOffset = (int)((number.length() * rulerCharWidth) / 2); int xPos = (int)(pos * charWidth - stringSizeOffset - offsetDueToScrollPanePosition); g2d.drawString(number, xPos, 10); // g2d.drawBytes(number.getBytes(), 0,number.getBytes().length,xPos, 10); } pos ++; } long endTime = System.currentTimeMillis(); logger.info("Ruler PaintComponent took " + (endTime - startTime) + " milliseconds"); } } public void setDrawAminoAcidCode(boolean drawCode){ this.drawAminoAcidCode = drawCode; } public boolean getDrawAminoAcidCode(){ return this.drawAminoAcidCode; } public void setColorSchemeAminoAcid(ColorScheme aScheme) { this.colorSchemeAminoAcid = aScheme; } public void setColorSchemeNucleotide(ColorScheme aScheme) { this.colorSchemeNucleotide = aScheme; } public Point getVisibleUpperLeftMatrixPos() { Rectangle rect = this.getVisibleRect(); Point ulPanePos = rect.getLocation(); Point ulMatrixPos = paneCoordToMatrixCoord(ulPanePos); return ulMatrixPos; } public void scrollToVisibleUpperLeftMatrixPos(Point ulPos) { Point ulPanePos = matrixCoordToPaneCoord(ulPos); this.setLocation(ulPanePos); } public void scrollMatrixX(int offset) { int offsetPane = (int)(offset * charWidth); this.setLocation( getLocation().x + offsetPane, getLocation().y ); } public boolean getIgnoreGapInTranslation(){ return ignoreGapInTranslation; } public void setIgnoreGapInTranslation(boolean ignoreGapInTranslation) { this.ignoreGapInTranslation = ignoreGapInTranslation; } // public void selectSequences(ArrayList<Sequence> selectedSequences) { // preserveBaseSelection = false; // // } */ }