id 'application'
id 'eclipse'
id "com.diffplug.gradle.spotless" version "3.28.0"
- id 'com.github.johnrengelman.shadow' version '7.1.2'
+ id 'com.github.johnrengelman.shadow' version '6.0.0'
id 'com.install4j.gradle' version '10.0.3'
id 'com.dorongold.task-tree' version '2.1.1' // only needed to display task dependency tree with gradle task1 [task2 ...] taskTree
id 'com.palantir.git-version' version '0.13.0' apply false
### Other improvements
- <!-- JAL-4250 --> Secondary structure annotation glyphs are rendered anti-aliasing when enabled
- <!-- JAL-325 --> Helix and Sheet glyphs vertically centered with respect to grey coil secondary structure annotation track
-- <!-- JAL-4253 --> Lower line of the sequence group border does not align with vertical and background residue box
+- <!-- JAL-4317 --> feature should be displayed when its rendering and filtering settings are adjusted
- <!-- JAL-4250 --> Updated JFreeSVG (https://www.jfree.org/jfreesvg) from 2.1 to 3.4.3
- <!-- JAL-3119 --> Name of alignment and view included in overview window's title
- <!-- JAL-4213 --> "add reference annotation" add all positions in reference annotation tracks, not just positions in the currently highlighted columns/selection range
- <!-- JAL-4182 --> reference annotation not correctly transferred to alignment containing a sub-sequence when a selection is active
- <!-- JAL-4177 --> Can press 'Add' or 'New View' multiple times when manually adding and viewing a 3D structure via structure chooser
- <!-- JAL-4133 --> Jalview project does not preserve font aspect ratio when Viewport is zoomed with mouse
+- <!-- JAL-4253 --> Lower line of the sequence group border does not align with vertical and background residue box
- <!-- JAL-4128 --> Resizing overview quickly with solid-drags enabled causes exception
- <!-- JAL-4150 --> Sequences copied to clipboard from within Jalview cannot be pasted via the desktop's popup menu to a new alignment window
- <!-- JAL-2528, JAL-1713 --> Overview window is saved in project file, and state of 'show hidden regions' is preserved.
}
}
alignPanel.validateAnnotationDimensions(true);
+ // TODO this triggers relayout of annotation panel - otherwise annotation label height is different to panel height
+ alignPanel.fontChanged();
alignPanel.alignmentChanged();
}
else
{
int newAnnotationIdWidth = drawLabels(g, clip, width, false, forGUI, null, false);
- width = Math.max(newAnnotationIdWidth, givenWidth);
+ width = newAnnotationIdWidth<givenWidth ? givenWidth: Math.min(newAnnotationIdWidth, givenWidth);
}
drawLabels(g, clip, width, true, forGUI, null, false);
}
}
}
- if (!resizePanel && dragEvent != null && aa != null)
+ if (!resizePanel && dragEvent != null && aa != null && selectedRow>-1 && selectedRow<aa.length)
{
if (actuallyDraw && g != null)
{
*/
final String ft = features.get(featureIndex).getType();
final String type = ft == null ? lastFeatureAdded : ft;
- FeatureTypeSettings fcc = new FeatureTypeSettings(fr, type);
+ FeatureTypeSettings fcc = new FeatureTypeSettings(fr, type,true);
fcc.setRequestFocusEnabled(true);
fcc.requestFocus();
fcc.addActionListener(new ActionListener()
*/
String ttl = MessageManager
.formatMessage("label.select_colour_for", type);
+ Object last=(Boolean)table.getValueAt(selectedRow, SHOW_COLUMN);
+ table.setValueAt(Boolean.TRUE, selectedRow, SHOW_COLUMN);
ColourChooserListener listener = new ColourChooserListener()
{
@Override
{
currentColor = new FeatureColour(c);
table.setValueAt(currentColor, rowSelected, COLOUR_COLUMN);
+ table.setValueAt(Boolean.TRUE, selectedRow, SHOW_COLUMN);
fireEditingStopped();
}
@Override
public void cancel()
{
+ table.setValueAt(last, selectedRow, SHOW_COLUMN);
fireEditingStopped();
}
};
/*
* variable colour and filters dialog
*/
- chooser = new FeatureTypeSettings(fr, type);
+ boolean last=(Boolean)table.getValueAt(selectedRow, SHOW_COLUMN);
+ table.setValueAt(Boolean.TRUE, selectedRow, SHOW_COLUMN);
+ chooser = new FeatureTypeSettings(fr, type,last);
if (!Platform.isJS())
/**
* Java only
{
if (button == e.getSource())
{
- FeatureTypeSettings chooser = new FeatureTypeSettings(fr, type);
+ boolean last = fr.getFeaturesDisplayed().isVisible(type);
+ ((FeatureTableModel) table.getModel()).setValueAt(Boolean.TRUE, rowSelected, SHOW_COLUMN);
+ FeatureTypeSettings chooser = new FeatureTypeSettings(fr, type,last);
chooser.addActionListener(this);
chooser.setRequestFocusEnabled(true);
chooser.requestFocus();
.getData()[rowSelected];
data[COLOUR_COLUMN] = currentColor;
data[FILTER_COLUMN] = currentFilter;
+ data[SHOW_COLUMN] = fr.getFeaturesDisplayed().isVisible(type);
+
fireEditingStopped();
// SwingJS needs an explicit repaint() here,
// rather than relying upon no validation having
private JPanel chooseFiltersPanel;
+ public boolean originalDisplay;
+
/**
* Constructor
*
* @param frender
* @param theType
+ * @param last - visibility of feature prior to adjustment
*/
- public FeatureTypeSettings(FeatureRenderer frender, String theType)
+ public FeatureTypeSettings(FeatureRenderer frender, String theType, boolean last)
{
this.fr = frender;
this.featureType = theType;
ap = fr.ap;
originalFilter = fr.getFeatureFilter(theType);
originalColour = fr.getFeatureColours().get(theType);
-
+ originalDisplay = last;
adjusting = true;
try
{
fr.setColour(featureType, originalColour);
fr.setFeatureFilter(featureType, originalFilter);
+ if (!originalDisplay) {
+ fr.getFeaturesDisplayed().setHidden(featureType);
+ }
refreshDisplay(true);
}
if (alignViewport.getWrapAlignment())
{
- drawIdsWrapped(g, alignViewport, startSeq, getHeight());
+ drawIdsWrapped(g, alignViewport, startSeq, getHeight(), manuallyAdjusted ? panelWidth : -1,forGUI);
return;
}
drawIdsWrapped(g, av2, totalHeight, totalHeight, i,false);
}
- void drawIdsWrapped(Graphics2D g, AlignViewport alignViewport,
+ public void drawIdsWrapped(Graphics2D g, AlignViewport alignViewport,
int startSeq, int pageHeight, int idWidth, boolean forGUI)
{
int alignmentWidth = alignViewport.getAlignment().getWidth();
AnnotationLabels labels = null;
if (alignViewport.isShowAnnotation())
{
+ // in wrapped mode, no alignPanel reference is available
+ // FIXME: make the renderer not create a new object in wrapped mode everytime!
labels = new AnnotationLabels(alignViewport);
}
@Override
public void mousePressed(MouseEvent evt)
{
- int x = (evt.getX() / av.getCharWidth()) + av.getRanges().getStartRes();
- final int res;
-
- if (av.hasHiddenColumns())
- {
- x = av.getAlignment().getHiddenColumns().visibleToAbsoluteColumn(x);
- }
- res = Math.min(x, av.getAlignment().getWidth() - 1);
+ int res = ap.getSeqPanel().findAlignmentColumn(evt);
min = res;
max = res;
mouseDragging = false;
ap.getSeqPanel().stopScrolling();
- // todo res calculation should be a method on AlignViewport
- int xCords = Math.max(0, evt.getX()); // prevent negative X coordinates
- ViewportRanges ranges = av.getRanges();
- int res = (xCords / av.getCharWidth()) + ranges.getStartRes();
- res = Math.min(res, ranges.getEndRes());
- if (av.hasHiddenColumns())
- {
- res = av.getAlignment().getHiddenColumns()
- .visibleToAbsoluteColumn(res);
- }
- res = Math.max(0, res);
-
+ int res = ap.getSeqPanel().findAlignmentColumn(evt);
+
if (!stretchingGroup)
{
if (evt.isPopupTrigger()) // Windows: mouseReleased
@Override
public void mouseDragged(MouseEvent evt)
{
- mouseDragging = true;
+ mouseDragging = true;
+ int res = ap.getSeqPanel().findAlignmentColumn(evt);
+
ColumnSelection cs = av.getColumnSelection();
- HiddenColumns hidden = av.getAlignment().getHiddenColumns();
-
- int res = (evt.getX() / av.getCharWidth())
- + av.getRanges().getStartRes();
- res = Math.max(0, res);
- res = hidden.visibleToAbsoluteColumn(res);
- res = Math.min(res, av.getAlignment().getWidth() - 1);
- min = Math.min(res, min);
+
+ min = Math.min(res,min);
max = Math.max(res, max);
SequenceGroup sg = av.getSelectionGroup();
{
this.setToolTipText(null);
reveal = null;
- if (!av.hasHiddenColumns())
- {
- int res = (evt.getX() / av.getCharWidth())
- + av.getRanges().getStartRes();
- highlightAllStructPos(res);
+ final int res = ap.getSeqPanel().findAlignmentColumn(evt);
+
+ highlightAllStructPos(res);
+ if (!av.hasHiddenColumns()) {
return;
}
-
- int res = (evt.getX() / av.getCharWidth())
- + av.getRanges().getStartRes();
-
reveal = av.getAlignment().getHiddenColumns()
- .getRegionWithEdgeAtRes(res);
-
- res = av.getAlignment().getHiddenColumns().visibleToAbsoluteColumn(res);
- highlightAllStructPos(res);
+ .getRegionWithEdgeAtRes(av.getAlignment().getHiddenColumns().absoluteToVisibleColumn(res));
+ if (reveal==null)
+ {
+ return;
+ }
ToolTipManager.sharedInstance().registerComponent(this);
this.setToolTipText(
MessageManager.getString("label.reveal_hidden_columns"));
if (vertical > 0) // scroll down
{
- startSeq = endSeq - vertical;
+ startSeq = endSeq - vertical + 1;
if (startSeq < ranges.getStartSeq())
{ // ie scrolling too fast, more than a page at a time
}
else
{
- transY = img.getHeight() - ((vertical + 1) * charHeight);
+ transY = img.getHeight() - (vertical * charHeight);
}
}
- else if (vertical < 0)
+ else if (vertical < 0) // scroll up
{
- endSeq = startSeq - vertical;
+ endSeq = startSeq - vertical - 1;
if (endSeq > ranges.getEndSeq())
{
}
}
- // jalview.bin.Console.errPrintln(">>> FastPaint to " + transX + " " + transY + " "
+ // jalview.bin.Console.errPrintln(">>> FastPaint to " + transX + " " +
+ // transY + " "
// + horizontal + " " + vertical + " " + startRes + " " + endRes
// + " " + startSeq + " " + endSeq);
// Call repaint on alignment panel so that repaints from other alignment
// panel components can be aggregated. Otherwise performance of the
// overview window and others may be adversely affected.
- // jalview.bin.Console.outPrintln("SeqCanvas fastPaint() repaint() request...");
+ // jalview.bin.Console.outPrintln("SeqCanvas fastPaint() repaint()
+ // request...");
av.getAlignPanel().repaint();
} finally
{
if (av.getWrapAlignment())
{
- drawWrappedPanel(seqRdr, gg, getWidth(), getHeight(), ranges.getStartRes());
+ drawWrappedPanel(seqRdr, gg, getWidth(), getHeight(),
+ ranges.getStartRes());
}
else
{
- drawPanel(seqRdr,gg, startRes, endRes, startSeq, endSeq, 0);
+ drawPanel(seqRdr, gg, startRes, endRes, startSeq, endSeq, 0);
}
drawSelectionGroup(gg, startRes, endRes, startSeq, endSeq);
int startSeq, int endSeq)
{
SequenceRenderer localSeqR = new jalview.gui.SequenceRenderer(av);
- drawPanel(localSeqR,g1, startRes, endRes, startSeq, endSeq, 0);
+ drawPanel(localSeqR, g1, startRes, endRes, startSeq, endSeq, 0);
drawSelectionGroup((Graphics2D) g1, startRes, endRes, startSeq, endSeq);
}
* @param startColumn
* the first column (0...) of the alignment to draw
*/
- public void drawWrappedPanel(SequenceRenderer seqRdr, Graphics g, int canvasWidth,
- int canvasHeight, final int startColumn)
+ public void drawWrappedPanel(SequenceRenderer seqRdr, Graphics g,
+ int canvasWidth, int canvasHeight, final int startColumn)
{
int wrappedWidthInResidues = calculateWrappedGeometry(canvasWidth,
canvasHeight);
* @param endColumn
* @param canvasHeight
*/
- protected void drawWrappedWidth(SequenceRenderer seqRdr, Graphics g, final int ypos,
- final int startColumn, final int endColumn,
+ protected void drawWrappedWidth(SequenceRenderer seqRdr, Graphics g,
+ final int ypos, final int startColumn, final int endColumn,
final int canvasHeight)
{
ViewportRanges ranges = av.getRanges();
g.fillRect(0, ypos, (endx - startColumn + 1) * charWidth,
wrappedRepeatHeightPx);
- drawPanel(seqRdr, g, startColumn, endx, 0, av.getAlignment().getHeight() - 1,
- ypos);
+ drawPanel(seqRdr, g, startColumn, endx, 0,
+ av.getAlignment().getHeight() - 1, ypos);
int cHeight = av.getAlignment().getHeight() * av.getCharHeight();
* are hidden column markers in the visible region, then each sub-region
* between the markers is drawn separately, followed by the hidden column
* marker.
- * @param localSeqR - sequence renderer implementation - when null, uses the one used for rendering interactive GUI
+ *
+ * @param localSeqR
+ * - sequence renderer implementation - when null, uses the one used
+ * for rendering interactive GUI
*
* @param g1
* the graphics context, positioned at the first residue to be drawn
* @param yOffset
* vertical offset at which to draw (for wrapped alignments)
*/
- public void drawPanel(SequenceRenderer localSeqR, Graphics g1, final int startRes, final int endRes,
- final int startSeq, final int endSeq, final int yOffset)
+ public void drawPanel(SequenceRenderer localSeqR, Graphics g1,
+ final int startRes, final int endRes, final int startSeq,
+ final int endSeq, final int yOffset)
{
int charHeight = av.getCharHeight();
int charWidth = av.getCharWidth();
- if (localSeqR==null)
+ if (localSeqR == null)
{
localSeqR = seqRdr;
}
*/
g1.translate(screenY * charWidth, 0);
- draw(localSeqR, g1, blockStart, blockEnd, startSeq, endSeq, yOffset);
+ draw(localSeqR, g1, blockStart, blockEnd, startSeq, endSeq,
+ yOffset);
/*
* draw the downline of the hidden column marker (ScalePanel draws the
/**
* Draws a region of the visible alignment
- * @param seqRdr
+ *
+ * @param seqRdr
*
* @param g1
* @param startRes
* @param yOffset
* vertical offset at which to draw (for wrapped alignments)
*/
- private void draw(SequenceRenderer seqRdr, Graphics g, int startRes, int endRes, int startSeq,
- int endSeq, int offset)
+ private void draw(SequenceRenderer seqRdr, Graphics g, int startRes,
+ int endRes, int startSeq, int endSeq, int offset)
{
int charHeight = av.getCharHeight();
int charWidth = av.getCharWidth();
else if (inGroup)
{
drawVerticals(g, sx, xwidth, visWidth, oldY, bottom);
- drawHorizontals(g, sx, xwidth, visWidth, top, bottom+1);
+ drawHorizontals(g, sx, xwidth, visWidth, top, bottom);
// reset top and bottom
top = -1;
if (inGroup)
{
sy = verticalOffset + ((i - startSeq) * charHeight);
- drawVerticals(g, sx, xwidth, visWidth, oldY, bottom);
- drawHorizontals(g, sx, xwidth, visWidth, top, bottom+1);
+ drawVerticals(g, sx, xwidth, visWidth, oldY,
+ bottom == -1 ? sy : bottom);
+ drawHorizontals(g, sx, xwidth, visWidth, top, bottom);
}
}
}
public void propertyChange(PropertyChangeEvent evt)
{
String eventName = evt.getPropertyName();
- // jalview.bin.Console.errPrintln(">>SeqCanvas propertyChange " + eventName);
+ // jalview.bin.Console.errPrintln(">>SeqCanvas propertyChange " +
+ // eventName);
if (eventName.equals(SequenceGroup.SEQ_GROUP_CHANGED))
{
fastPaint = true;
else if (eventName.equals(ViewportRanges.MOVE_VIEWPORT))
{
fastPaint = false;
- // jalview.bin.Console.errPrintln("!!!! fastPaint false from MOVE_VIEWPORT");
+ // jalview.bin.Console.errPrintln("!!!! fastPaint false from
+ // MOVE_VIEWPORT");
repaint();
return;
}
if (scrollX < 0)
{
int startRes = ranges.getStartRes();
- drawWrappedWidth(seqRdr,gg, wrappedSpaceAboveAlignment, startRes,
+ drawWrappedWidth(seqRdr, gg, wrappedSpaceAboveAlignment, startRes,
startRes - scrollX - 1, getHeight());
}
else
{
matchFound = true;
gg.translate(transX, transY);
- drawPanel(seqRdr,gg, displayColumn, displayColumn, seqNo, seqNo,
- yOffset);
+ drawPanel(seqRdr, gg, displayColumn, displayColumn, seqNo,
+ seqNo, yOffset);
gg.translate(-transX, -transY);
}
}
}
/**
+ * @param evt
+ * @return absolute column in alignment nearest to the mouse pointer
+ */
+ int findAlignmentColumn(MouseEvent evt)
+ {
+ return findNearestColumn(evt,true);
+ }
+ /**
* Returns the aligned sequence position (base 0) at the mouse position, or
* the closest visible one
* <p>
*/
int findColumn(MouseEvent evt)
{
+ return findNearestColumn(evt, false);
+ }
+
+ /**
+ * @param nearestColumn when false returns negative values for out of bound positions - -1 for scale left/right, <-1 if far to right
+ * @return nearest absolute column to mouse pointer
+ */
+ private int findNearestColumn(MouseEvent evt, boolean nearestColumn)
+ {
int res = 0;
int x = evt.getX();
if (x < 0)
{
// mouse is over left scale
- return -1;
+ if (!nearestColumn) {
+ return -1;
+ } else {
+ x = 0;
+ }
}
int cwidth = seqCanvas.getWrappedCanvasWidth(this.getWidth());
}
if (x >= cwidth * charWidth)
{
- // mouse is over right scale
- return -1;
+ if (!nearestColumn) {
+ // mouse is over right scale
+ return -1;
+ } else {
+ x = cwidth*charWidth -1;
+ }
}
wrappedBlock = y / cHeight;
* rather than right-hand gutter
*/
x = Math.min(x, seqCanvas.getX() + seqCanvas.getWidth());
+ if (nearestColumn)
+ {
+ x = Math.max(x, 0);
+ }
+
res = (x / charWidth) + startRes;
res = Math.min(res, av.getRanges().getEndRes());
+
}
+
if (av.hasHiddenColumns())
{
ScalePanel scalePanel = alignFrame.alignPanel.getScalePanel();
MouseEvent mouse = new MouseEvent(scalePanel, 0, 1, 0, 4, 0, 1, false);
+
+ // check the bounded lookup is not returning negatives
+ assertEquals(alignFrame.alignPanel.getSeqPanel().findAlignmentColumn(mouse),0);
+
scalePanel.mousePressed(mouse);
scalePanel.mouseDragged(mouse);
}
@Test(groups = "Functional")
- public void testFindColumn_wrapped()
+ public void testFindColumn_and_FindAlignmentColumn_wrapped()
{
Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true");
AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(
MouseEvent evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0,
x, 0, 0, 0, 0, false, 0);
assertEquals(testee.findColumn(evt), 0);
+ assertEquals(testee.findAlignmentColumn(evt), 0);
/*
* not quite one charWidth across
evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0,
0, false, 0);
assertEquals(testee.findColumn(evt), 0);
+ assertEquals(testee.findAlignmentColumn(evt), 0);
/*
* one charWidth across
evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0,
0, false, 0);
assertEquals(testee.findColumn(evt), 1);
+ assertEquals(testee.findAlignmentColumn(evt), 1);
/*
* x over scale left (before drawn columns) results in -1
evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0,
0, false, 0);
assertEquals(testee.findColumn(evt), -1);
+ assertEquals(testee.findAlignmentColumn(evt), 0);
+
x = labelWidth;
evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0,
0, false, 0);
assertEquals(testee.findColumn(evt), 0);
+ assertEquals(testee.findAlignmentColumn(evt), 0);
+
/*
* x over right edge of last residue (including scale left)
evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0,
0, false, 0);
assertEquals(testee.findColumn(evt), residuesWide - 1);
+ assertEquals(testee.findAlignmentColumn(evt), residuesWide-1);
+
/*
* x over scale right (beyond drawn columns) results in -1
x += 1; // just over left edge of scale right
evt = new MouseEvent(testee, MouseEvent.MOUSE_MOVED, 0L, 0, x, 0, 0, 0,
0, false, 0);
+ // on scale
assertEquals(testee.findColumn(evt), -1);
+ // return right-most column visible
+ assertEquals(testee.findAlignmentColumn(evt), residuesWide2-1);
+
// todo add startRes offset, hidden columns