import javax.swing.Scrollable;
import javax.swing.ToolTipManager;
+import jalview.api.AlignViewportI;
import jalview.datamodel.AlignmentAnnotation;
import jalview.datamodel.AlignmentI;
import jalview.datamodel.Annotation;
import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.ContactListI;
import jalview.datamodel.HiddenColumns;
import jalview.datamodel.SequenceI;
import jalview.gui.JalviewColourChooser.ColourChooserListener;
import jalview.renderer.AnnotationRenderer;
import jalview.renderer.AwtRenderPanelI;
+import jalview.renderer.ContactGeometry;
import jalview.schemes.ResidueProperties;
import jalview.util.Comparison;
import jalview.util.MessageManager;
{
int yPos = evt.getY();
AlignmentAnnotation[] aa = av.getAlignment().getAlignmentAnnotation();
-
- int row = getRowIndex(yPos, aa);
+ int rowAndOffset[] = getRowIndexAndOffset(yPos, aa);
+ int row = rowAndOffset[0];
if (row == -1)
{
if (row > -1 && ann.annotations != null
&& column < ann.annotations.length)
{
- String toolTip = buildToolTip(ann, column, aa);
+ String toolTip = buildToolTip(ann, column, aa, rowAndOffset[1], av);
setToolTipText(toolTip == null ? null
: JvSwingUtils.wrapTooltip(true, toolTip));
- String msg = getStatusMessage(av.getAlignment(), column, ann);
+ String msg = getStatusMessage(av.getAlignment(), column, ann,
+ rowAndOffset[1], av);
ap.alignFrame.setStatus(msg);
}
else
{
return -1;
}
+ return getRowIndexAndOffset(yPos, aa)[0];
+ }
+
+ static int[] getRowIndexAndOffset(int yPos, AlignmentAnnotation[] aa)
+ {
+ int[] res = new int[2];
+ if (aa == null)
+ {
+ res[0] = -1;
+ res[1] = 0;
+ return res;
+ }
int row = -1;
- int height = 0;
+ int height = 0, lheight = 0;
for (int i = 0; i < aa.length; i++)
{
if (aa[i].visible)
{
+ lheight = height;
height += aa[i].height;
}
if (height > yPos)
{
row = i;
+ res[0] = row;
+ res[1] = yPos - lheight;
break;
}
}
- return row;
+ return res;
}
/**
* @param ann
* @param column
* @param anns
+ * @param rowAndOffset
*/
static String buildToolTip(AlignmentAnnotation ann, int column,
- AlignmentAnnotation[] anns)
+ AlignmentAnnotation[] anns, int rowAndOffset, AlignViewportI av)
{
String tooltip = null;
if (ann.graphGroup > -1)
{
tooltip = ann.annotations[column].description;
}
-
+ // TODO abstract tooltip generator so different implementations can be built
+ if (ann.graph == AlignmentAnnotation.CUSTOMRENDERER)
+ {
+ ContactListI clist = av.getContactList(ann, column);
+ if (clist != null)
+ {
+ ContactGeometry cgeom = new ContactGeometry(clist, ann.graphHeight);
+ ContactGeometry.contactInterval ci = cgeom.mapFor(rowAndOffset,
+ rowAndOffset);
+ tooltip += "Contact from " + ci.cStart + " to " + ci.cEnd;
+ }
+ }
return tooltip;
}
* @param al
* @param column
* @param ann
+ * @param rowAndOffset
*/
static String getStatusMessage(AlignmentI al, int column,
- AlignmentAnnotation ann)
+ AlignmentAnnotation ann, int rowAndOffset, AlignViewportI av)
{
/*
* show alignment column and annotation description if any
Graphics2D gg = (Graphics2D) image.getGraphics();
- if (imgWidth>Math.abs(horizontal*av.getCharWidth())) {
- //scroll is less than imgWidth away so can re-use buffered graphics
+ if (imgWidth > Math.abs(horizontal * av.getCharWidth()))
+ {
+ // scroll is less than imgWidth away so can re-use buffered graphics
gg.copyArea(0, 0, imgWidth, getHeight(),
-horizontal * av.getCharWidth(), 0);
-
+
if (horizontal > 0) // scrollbar pulled right, image to the left
{
transX = (er - sr - horizontal) * av.getCharWidth();
final int column = pos.column;
final int rowIndex = pos.annotationIndex;
+ // TODO - get yOffset for annotation, too
if (column < 0 || !av.getWrapAlignment() || !av.isShowAnnotation()
|| rowIndex < 0)
{
AlignmentAnnotation[] anns = av.getAlignment().getAlignmentAnnotation();
String tooltip = AnnotationPanel.buildToolTip(anns[rowIndex], column,
- anns);
+ anns, 0, av);
if (tooltip == null ? tooltip != lastTooltip
: !tooltip.equals(lastTooltip))
{
}
String msg = AnnotationPanel.getStatusMessage(av.getAlignment(), column,
- anns[rowIndex]);
+ anns[rowIndex], 0, av);
ap.alignFrame.setStatus(msg);
}
--- /dev/null
+package jalview.renderer;
+
+import java.util.Iterator;
+
+import jalview.datamodel.ContactListI;
+
+public class ContactGeometry
+{
+ final int pixels_step;
+
+ final double contacts_per_pixel;
+
+ final int contact_height;
+
+ public ContactGeometry(ContactListI contacts, int graphHeight)
+ {
+ contact_height = contacts.getContactHeight();
+ // fractional number of contacts covering each pixel
+ contacts_per_pixel = ((double) contact_height) / ((double) graphHeight);
+
+ if (contacts_per_pixel >= 1)
+ {
+ // many contacts rendered per pixel
+ pixels_step = 1;
+ }
+ else
+ {
+ // pixel height for each contact
+ pixels_step = (int) Math
+ .ceil(((double) graphHeight) / (double) contact_height);
+ }
+ }
+
+ public class contactInterval
+ {
+ public contactInterval(int cStart, int cEnd, int pStart, int pEnd)
+ {
+ this.cStart = cStart;
+ this.cEnd = cEnd;
+ this.pStart = pStart;
+ this.pEnd = pEnd;
+ }
+
+ // range on contact list
+ public final int cStart;
+
+ public final int cEnd;
+
+ // range in pixels
+ public final int pStart;
+
+ public final int pEnd;
+ }
+
+ /**
+ *
+ * @param pStart
+ * @param pEnd
+ * @return range for
+ */
+ public contactInterval mapFor(int pStart, int pEnd)
+ {
+ int cStart = (int) Math.floor(pStart * contacts_per_pixel);
+ contactInterval ci = new contactInterval(cStart,
+ (int) Math.min(contact_height,
+ Math.ceil(
+ cStart + (pEnd - pStart) * contacts_per_pixel)),
+ pStart, pEnd);
+
+ return ci;
+ }
+
+ public Iterator<contactInterval> iterateOverContactIntervals(
+ int graphHeight)
+ {
+ // NOT YET IMPLEMENTED
+ return null;
+ // int cstart = 0, cend;
+ //
+ // for (int ht = y2,
+ // eht = y2 - graphHeight; ht >= eht; ht -= pixels_step)
+ // {
+ // cstart = (int) Math.floor(((double) y2 - ht) * contacts_per_pixel);
+ // cend = (int) Math.min(contact_height,
+ // Math.ceil(cstart + contacts_per_pixel * pixels_step));
+ //
+ // return new Iterator<contactIntervals>() {
+ //
+ // @Override
+ // public boolean hasNext()
+ // {
+ // // TODO Auto-generated method stub
+ // return false;
+ // }
+ //
+ // @Override
+ // public contactIntervals next()
+ // {
+ // // TODO Auto-generated method stub
+ // return null;
+ // }
+ //
+ // }
+ }
+}
\ No newline at end of file
{
return;
}
- int contact_height = contacts.getContactHeight();
- // fractional number of contacts covering each pixel
- double contacts_per_pixel = ((double) contact_height)
- / ((double) _aa.graphHeight);
+ // Bean holding mapping from contact list to pixels
+ final ContactGeometry cgeom = new ContactGeometry(contacts,
+ _aa.graphHeight);
- int pixels_step;
-
- if (contacts_per_pixel >= 1)
- {
- // many contacts rendered per pixel
- pixels_step = 1;
- }
- else
- {
- // pixel height for each contact
- pixels_step = (int) Math
- .ceil(((double) _aa.graphHeight) / (double) contact_height);
- }
-
- int cstart = 0, cend;
-
- for (int ht = y2,
- eht = y2 - _aa.graphHeight; ht >= eht; ht -= pixels_step)
+ for (int ht = y2, eht = y2
+ - _aa.graphHeight; ht >= eht; ht -= cgeom.pixels_step)
{
- cstart = (int) Math.floor(((double) y2 - ht) * contacts_per_pixel);
- cend = (int) Math.min(contact_height,
- Math.ceil(cstart + contacts_per_pixel * pixels_step));
+ ContactGeometry.contactInterval ci = cgeom.mapFor(y2 - ht,
+ y2 - ht + cgeom.pixels_step);
+ // cstart = (int) Math.floor(((double) y2 - ht) * contacts_per_pixel);
+ // cend = (int) Math.min(contact_height,
+ // Math.ceil(cstart + contacts_per_pixel * pixels_step));
// TODO show maximum colour for range - sort of done
// also need a 'getMaxPosForRange(start,end)' to accurately render
{
if (_aa.sequenceRef == null)
{
- rowsel = columnSelection.intersects(cstart, cend);
+ rowsel = columnSelection.intersects(ci.cStart, ci.cEnd);
}
else
{
// TODO check we have correctly mapped cstart to local sequence
// numbering
- int s = _aa.sequenceRef.findIndex(cstart);
- int e = _aa.sequenceRef.findIndex(cend);
+ int s = _aa.sequenceRef.findIndex(ci.cStart);
+ int e = _aa.sequenceRef.findIndex(ci.cEnd);
if (s > 0 && s < _aa.sequenceRef.getLength())
{
rowsel = columnSelection.intersects(s, e);
if (colsel || rowsel)
{
- col = getSelectedColorForRange(min, max, contacts, cstart, cend);
+ col = getSelectedColorForRange(min, max, contacts, ci.cStart,
+ ci.cEnd);
g.setColor(col);
}
else
{
- col = getColorForRange(min, max, contacts, cstart, cend);
+ col = getColorForRange(min, max, contacts, ci.cStart, ci.cEnd);
g.setColor(col);
}
- if (pixels_step > 1)
+ if (cgeom.pixels_step > 1)
{
- g.fillRect(x * charWidth, ht, charWidth, 1 + pixels_step);
+ g.fillRect(x * charWidth, ht, charWidth, 1 + cgeom.pixels_step);
}
else
{