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;
//
// }
*/
}