/*
* This file is part of LaTeXDraw.
* Copyright (c) 2005-2017 Arnaud BLOUIN
* LaTeXDraw is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later version.
* LaTeXDraw is distributed without any warranty; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*/
package net.sf.latexdraw.ui;
import com.google.inject.Inject;
import java.awt.BasicStroke;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.util.Objects;
import javax.accessibility.Accessible;
import javax.accessibility.AccessibleContext;
import javax.accessibility.AccessibleRole;
import javax.swing.JComponent;
import net.sf.latexdraw.util.Unit;
import net.sf.latexdraw.view.jfx.Canvas;
import net.sf.latexdraw.view.pst.PSTricksConstants;
import org.malai.mapping.ActiveUnary;
import org.malai.mapping.IUnary;
import org.malai.picking.Pickable;
import org.malai.picking.Picker;
/**
* An abstract scale ruler.
* @author Arnaud BLOUIN
*/
public abstract class ScaleRuler extends JComponent implements Pickable, Accessible, AdjustmentListener {
/** The current unit of the rulers. */
protected static final IUnary<Unit> UNIT = new ActiveUnary<>(Unit.CM);
/** The stroke of the ruler. */
protected static final BasicStroke STROKE = new BasicStroke(0, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER);
/** This value defines the threshold under which sub-lines of the rule will be not drawn. */
protected static final double MIN_PCC_SUBLINES = 20.;
/** The canvas that the ruler manages. */
protected final Canvas canvas;
// /** The event manager that listens events produced by the panel. */
// protected final SwingEventManager eventManager;
/** The size of the lines in axes */
public static final int SIZE = 10;
/**
* Creates the ruler.
* @param canvas The canvas that the ruler manages.
* @throws IllegalArgumentException If the given canvas is null.
*/
@Inject
protected ScaleRuler(final Canvas canvas) {
super();
this.canvas = Objects.requireNonNull(canvas);
// eventManager = new SwingEventManager();
// eventManager.attachTo(this);
setDoubleBuffered(true);
// canvas.getScrollpane().getVerticalScrollBar().addAdjustmentListener(this);
// canvas.getScrollpane().getHorizontalScrollBar().addAdjustmentListener(this);
}
@Override
public void adjustmentValueChanged(final AdjustmentEvent e) {
repaint();
}
/**
* @return The starting position where the ruler must be drawn.
* @since 3.0
*/
protected abstract double getStart();
/**
* @return The length of the ruler.
* @since 3.0
*/
protected abstract double getLength();
/**
* Draws a line of the ruler.
* @param g2 The graphics where the line will be drawn. Must not be null.
* @param positionA The static position of the vertical or horizontal line.
* @param positionB1 The starting point of the line.
* @param positionB2 The ending point of the line.
* @throws NullPointerException if the given graphics is null.
* @since 3.0
*/
protected abstract void drawLine(final Graphics2D g2, final double positionA, final double positionB1, final double positionB2);
/**
* Adapts the given graphics to the current position of the grid.
* @param g The graphics of the ruler.
* @since 3.1
*/
protected abstract void adaptGraphicsToViewpoint(final Graphics2D g);
/**
* @return The gap between the origin (0) and the current position of the painted view.
* @since 3.1
*/
protected abstract double getClippingGap();
@Override
public void paintComponent(final Graphics g) {
super.paintComponent(g);
if(!(g instanceof Graphics2D)) return;
final double zoom = canvas.getZoom();
final double lgth = getLength()/zoom;
final double start = getStart()/zoom;
double ppc = canvas.getPPCDrawing();
final Graphics2D g2 = (Graphics2D)g;
final double sizeZoomed = SIZE/zoom;
double i;
double j;
double cpt;
// adjusting the ppc value according to the current unit.
if(getUnit()==Unit.INCH)
ppc*=PSTricksConstants.INCH_VAL_CM;
// Optimisation for limitating the painting to the visible part only.
final double clipStart = (int)(getClippingGap()/zoom/ppc)*ppc;
// Settings the parameters of the graphics.
adaptGraphicsToViewpoint(g2);
g2.scale(zoom, zoom);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2.setStroke(STROKE);
g2.setColor(java.awt.Color.BLACK);
// If the ppc is not to small sub-lines are drawn.
if(ppc>MIN_PCC_SUBLINES/zoom) {
final double ppc10 = ppc/10.;
final double halfSizeZoomed = sizeZoomed/2.;
for(i=start+ppc10+clipStart; i<lgth; i+=ppc)
for(j=i, cpt=1; cpt<10; j+=ppc10, cpt++)
drawLine(g2, j, halfSizeZoomed, sizeZoomed);
}
// Major lines of the ruler are drawn.
for(i=start+clipStart; i<lgth;i+=ppc)
drawLine(g2, i, 0., sizeZoomed);
}
@Override
public boolean contains(final double x, final double y) {
return contains((int)x, (int)y);
}
@Override
public Picker getPicker() {
return null;// SwingWidgetUtilities.INSTANCE.getPicker(this);
}
/**
* @return the current unit used by the rulers.
* @since 3.0
*/
public static Unit getUnit() {
return UNIT.getValue();
}
/**
* @param unit The unit that the rulers must use. Must not be null.
* @since 3.0
*/
public static void setUnit(final Unit unit) {
if(unit!=null)
ScaleRuler.UNIT.setValue(unit);
}
/**
* @return The singleton that contains the unit value.
* @since 3.0
*/
public static IUnary<Unit> getUnitSingleton() {
return ScaleRuler.UNIT;
}
@Override
public AccessibleContext getAccessibleContext() {
if(accessibleContext==null)
accessibleContext = new AccessibleScaleRuler();
return accessibleContext;
}
/**
* This class implements accessibility support for the
* <code>ScaleRuler</code> class. It provides an implementation of the
* Java Accessibility API appropriate to panel user-interface elements.
*/
protected class AccessibleScaleRuler extends AccessibleJComponent {
private static final long serialVersionUID = 1L;
@Override
public AccessibleRole getAccessibleRole() {
return AccessibleRole.RULER;
}
}
}