import jalview.datamodel.ColumnSelection;
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
+import jalview.renderer.ScaleRenderer;
+import jalview.renderer.ScaleRenderer.ScaleMark;
import jalview.util.MessageManager;
+import jalview.util.Platform;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
+import java.util.List;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
+import javax.swing.SwingUtilities;
import javax.swing.ToolTipManager;
/**
- * DOCUMENT ME!
- *
- * @author $author$
- * @version $Revision$
+ * The panel containing the sequence ruler (when not in wrapped mode), and
+ * supports a range of mouse operations to select, hide or reveal columns.
*/
public class ScalePanel extends JPanel implements MouseMotionListener,
MouseListener
{
protected int offy = 4;
- /** DOCUMENT ME!! */
public int width;
protected AlignViewport av;
boolean stretchingGroup = false;
- int min; // used by mouseDragged to see if user
+ /*
+ * min, max hold the extent of a mouse drag action
+ */
+ int min;
- int max; // used by mouseDragged to see if user
+ int max;
boolean mouseDragging = false;
- // wants to delete columns
+ /*
+ * holds a hidden column range when the mouse is over an adjacent column
+ */
+ int[] reveal;
+
+ /**
+ * Constructor
+ *
+ * @param av
+ * @param ap
+ */
public ScalePanel(AlignViewport av, AlignmentPanel ap)
{
this.av = av;
@Override
public void mousePressed(MouseEvent evt)
{
- int x = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+ int x = (evt.getX() / av.getCharWidth()) + av.getRanges().getStartRes();
final int res;
if (av.hasHiddenColumns())
min = res;
max = res;
- if (evt.isPopupTrigger())
+ if (evt.isPopupTrigger()) // Mac: mousePressed
{
rightMouseButtonPressed(evt, res);
}
+ else if (SwingUtilities.isRightMouseButton(evt) && !Platform.isAMac())
+ {
+ /*
+ * defer right-mouse click handling to mouse up on Windows
+ * (where isPopupTrigger() will answer true)
+ * but accept Cmd-click on Mac which passes isRightMouseButton
+ */
+ return;
+ }
else
{
leftMouseButtonPressed(evt, res);
*/
protected void leftMouseButtonPressed(MouseEvent evt, final int res)
{
- if (!evt.isControlDown() && !evt.isShiftDown())
+ /*
+ * Ctrl-click/Cmd-click adds to the selection
+ * Shift-click extends the selection
+ */
+ // TODO Problem: right-click on Windows not reported until mouseReleased?!?
+ if (!Platform.isControlDown(evt) && !evt.isShiftDown())
{
av.getColumnSelection().clear();
}
{
mouseDragging = false;
- int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+ int res = (evt.getX() / av.getCharWidth())
+ + av.getRanges().getStartRes();
if (av.hasHiddenColumns())
{
if (!stretchingGroup)
{
- ap.paintAlignment(false);
-
+ if (evt.isPopupTrigger()) // Windows: mouseReleased
+ {
+ rightMouseButtonPressed(evt, res);
+ }
+ else
+ {
+ ap.paintAlignment(false);
+ }
return;
}
}
/**
- * DOCUMENT ME!
+ * Action on dragging the mouse in the scale panel is to expand or shrink the
+ * selection group range (including any hidden columns that it spans)
*
* @param evt
- * DOCUMENT ME!
*/
@Override
public void mouseDragged(MouseEvent evt)
{
mouseDragging = true;
+ ColumnSelection cs = av.getColumnSelection();
- int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
- if (res < 0)
- {
- res = 0;
- }
-
- if (av.hasHiddenColumns())
- {
- res = av.getColumnSelection().adjustForHiddenColumns(res);
- }
-
- if (res >= av.getAlignment().getWidth())
- {
- res = av.getAlignment().getWidth() - 1;
- }
-
- if (res < min)
- {
- min = res;
- }
-
- if (res > max)
- {
- max = res;
- }
+ int res = (evt.getX() / av.getCharWidth())
+ + av.getRanges().getStartRes();
+ res = Math.max(0, res);
+ res = cs.adjustForHiddenColumns(res);
+ res = Math.min(res, av.getAlignment().getWidth() - 1);
+ min = Math.min(res, min);
+ max = Math.max(res, max);
SequenceGroup sg = av.getSelectionGroup();
-
if (sg != null)
{
stretchingGroup = true;
-
- if (!av.getColumnSelection().contains(res))
- {
- av.getColumnSelection().addElement(res);
- }
-
- if (res > sg.getStartRes())
- {
- sg.setEndRes(res);
- }
- if (res < sg.getStartRes())
- {
- sg.setStartRes(res);
- }
-
- int col;
- for (int i = min; i <= max; i++)
- {
- col = i; // av.getColumnSelection().adjustForHiddenColumns(i);
-
- if ((col < sg.getStartRes()) || (col > sg.getEndRes()))
- {
- av.getColumnSelection().removeElement(col);
- }
- else
- {
- av.getColumnSelection().addElement(col);
- }
- }
-
+ cs.stretchGroup(res, sg, min, max);
ap.paintAlignment(false);
}
}
{
}
+ /**
+ * Creates a tooltip when the mouse is over a hidden columns marker
+ */
@Override
public void mouseMoved(MouseEvent evt)
{
+ this.setToolTipText(null);
+ reveal = null;
if (!av.hasHiddenColumns())
{
return;
}
- int res = (evt.getX() / av.getCharWidth()) + av.getStartRes();
+ int res = (evt.getX() / av.getCharWidth())
+ + av.getRanges().getStartRes();
res = av.getColumnSelection().adjustForHiddenColumns(res);
- reveal = null;
if (av.getColumnSelection().getHiddenColumns() != null)
{
for (int[] region : av.getColumnSelection().getHiddenColumns())
ToolTipManager.sharedInstance().registerComponent(this);
this.setToolTipText(MessageManager
.getString("label.reveal_hidden_columns"));
- break;
- }
- else
- {
- this.setToolTipText(null);
+ repaint();
+ return;
}
}
}
- repaint();
}
- int[] reveal;
-
/**
* DOCUMENT ME!
*
@Override
public void paintComponent(Graphics g)
{
- drawScale(g, av.getStartRes(), av.getEndRes(), getWidth(), getHeight());
+ drawScale(g, av.getRanges().getStartRes(), av.getRanges().getEndRes(),
+ getWidth(), getHeight());
}
// scalewidth will normally be screenwidth,
ColumnSelection cs = av.getColumnSelection();
int avCharWidth = av.getCharWidth(), avCharHeight = av.getCharHeight();
- int s;
if (cs != null)
{
gg.setColor(new Color(220, 0, 0));
int widthx = 1 + endx - startx;
FontMetrics fm = gg.getFontMetrics(av.getFont());
- int y = avCharHeight, yOf = fm.getDescent();
+ int y = avCharHeight;
+ int yOf = fm.getDescent();
y -= yOf;
if (av.hasHiddenColumns())
{
continue;
}
- gg.fillPolygon(new int[] { res * avCharWidth - avCharHeight / 4,
- res * avCharWidth + avCharHeight / 4, res * avCharWidth },
- new int[] { y - avCharHeight / 2, y - avCharHeight / 2,
- y + 8 }, 3);
-
+ gg.fillPolygon(new int[] {
+ -1 + res * avCharWidth - avCharHeight / 4,
+ -1 + res * avCharWidth + avCharHeight / 4,
+ -1 + res * avCharWidth }, new int[] { y, y, y + 2 * yOf }, 3);
}
}
}
// Draw the scale numbers
gg.setColor(Color.black);
- int scalestartx = (startx / 10) * 10;
-
- SequenceI refSeq = av.getAlignment().getSeqrep();
- int refSp = 0, refEp = -1, refStart = 0, refEnd = -1, refStartI = 0, refEndI = -1;
- if (refSeq != null)
- {
- // find bounds and set origin appopriately
- // locate first visible position for this sequence
- int[] refbounds = av.getColumnSelection()
- .locateVisibleBoundsOfSequence(refSeq);
-
- refSp = refbounds[0];
- refEp = refbounds[1];
- refStart = refbounds[2];
- refEnd = refbounds[3];
- refStartI = refbounds[4];
- refEndI = refbounds[5];
- scalestartx = refSp + ((scalestartx - refSp) / 10) * 10;
- }
-
-
- if (refSeq == null && scalestartx % 10 == 0)
- {
- scalestartx += 5;
- }
+ int maxX = 0;
+ List<ScaleMark> marks = new ScaleRenderer().calculateMarks(av, startx,
+ endx);
- String string;
- int maxX = 0, refN, iadj;
- // todo: add a 'reference origin column' to set column number relative to
- for (int i = scalestartx; i < endx; i += 5)
+ for (ScaleMark mark : marks)
{
- if (((i - refSp) % 10) == 0)
+ boolean major = mark.major;
+ int mpos = mark.column; // (i - startx - 1)
+ String mstring = mark.text;
+ if (mstring != null)
{
- if (refSeq == null)
- {
- iadj = av.getColumnSelection().adjustForHiddenColumns(i - 1) + 1;
- string = String.valueOf(iadj);
- }
- else
- {
- iadj = av.getColumnSelection().adjustForHiddenColumns(i - 1);
- refN = refSeq.findPosition(iadj);
- // TODO show bounds if position is a gap
- // - ie L--R -> "1L|2R" for
- // marker
- if (iadj < refStartI)
- {
- string = String.valueOf(iadj - refStartI);
- }
- else if (iadj > refEndI)
- {
- string = "+" + String.valueOf(iadj - refEndI);
- }
- else
- {
- string = String.valueOf(refN) + refSeq.getCharAt(iadj);
- }
- }
- if ((i - startx - 1) * avCharWidth > maxX)
+ if (mpos * avCharWidth > maxX)
{
- gg.drawString(string, (i - startx - 1) * avCharWidth, y);
- maxX = (i - startx + 1) * avCharWidth + fm.stringWidth(string);
+ gg.drawString(mstring, mpos * avCharWidth, y);
+ maxX = (mpos + 2) * avCharWidth + fm.stringWidth(mstring);
}
-
- gg.drawLine(((i - startx - 1) * avCharWidth) + (avCharWidth / 2),
- y + 2,
- ((i - startx - 1) * avCharWidth) + (avCharWidth / 2), y
- + (yOf * 2));
}
- else
+ if (major)
{
- gg.drawLine(((i - startx - 1) * avCharWidth) + (avCharWidth / 2), y
- + yOf,
- ((i - startx - 1) * avCharWidth) + (avCharWidth / 2), y
- + (yOf * 2));
+ gg.drawLine((mpos * avCharWidth) + (avCharWidth / 2), y + 2,
+ (mpos * avCharWidth) + (avCharWidth / 2), y + (yOf * 2));
}
- }
-
- if (av.hasHiddenColumns())
- {
- if (reveal != null && reveal[0] > startx && reveal[0] < endx)
+ else
{
- gg.drawString(MessageManager.getString("label.reveal_columns"),
- reveal[0] * avCharWidth, 0);
+ gg.drawLine((mpos * avCharWidth) + (avCharWidth / 2), y + yOf,
+ (mpos * avCharWidth) + (avCharWidth / 2), y + (yOf * 2));
}
}
-
}
+
}