package com.xenoage.zong.renderer.awt.canvas;
import com.xenoage.utils.color.Color;
import com.xenoage.utils.math.geom.Point2f;
import com.xenoage.utils.math.geom.Rectangle2f;
import com.xenoage.utils.math.geom.Size2f;
import com.xenoage.zong.core.text.FormattedText;
import com.xenoage.zong.io.selection.text.TextSelection;
import com.xenoage.zong.renderer.awt.image.AwtImageRenderer;
import com.xenoage.zong.renderer.awt.path.AwtPath;
import com.xenoage.zong.renderer.awt.text.TextLayoutTools;
import com.xenoage.zong.renderer.awt.text.TextLayouts;
import com.xenoage.zong.renderer.canvas.Canvas;
import com.xenoage.zong.renderer.canvas.CanvasDecoration;
import com.xenoage.zong.renderer.canvas.CanvasFormat;
import com.xenoage.zong.renderer.canvas.CanvasIntegrity;
import com.xenoage.zong.symbols.path.Path;
import java.awt.*;
import java.awt.font.FontRenderContext;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.util.Stack;
import static com.xenoage.utils.jse.color.AwtColorUtils.toAwtColor;
import static com.xenoage.utils.kernel.Range.range;
/**
* AWT implementation of a {@link Canvas}
*
* @author Andreas Wenger
*/
public class AwtCanvas
extends Canvas {
/** The AWT graphics context. */
private final Graphics2D g2d;
//stack for stored transformation states
private Stack<AffineTransform> transformStack = new Stack<>();
/**
* Creates an {@link AwtCanvas} with the given size in mm for the given context,
* format, decoration mode and integrity.
*/
public AwtCanvas(Graphics2D g2d, Size2f sizeMm, CanvasFormat format, CanvasDecoration decoration,
CanvasIntegrity integrity) {
super(sizeMm, format, decoration, integrity);
this.g2d = g2d;
}
/**
* Gets the {@link Graphics2D} graphics context.
*/
@Override public Graphics2D getGraphicsContext() {
return g2d;
}
/**
* Convenience method: Gets the {@link Graphics2D} graphics context from
* the given {@link Canvas}. If it is not a {@link AwtCanvas}, a {@link ClassCastException}
* is thrown.
*/
public static Graphics2D getGraphics2D(Canvas canvas) {
return ((AwtCanvas) canvas).getGraphicsContext();
}
@Override public void drawText(FormattedText text, TextSelection selection, Point2f position,
boolean yIsBaseline, float frameWidth) {
if (decoration == CanvasDecoration.Interactive) {
//interactive mode: show text selection
}
FontRenderContext frc = g2d.getFontRenderContext();
TextLayouts textLayouts = TextLayoutTools.create(text, frameWidth, yIsBaseline, frc);
AffineTransform oldTransform = g2d.getTransform();
g2d.translate(position.x, position.y);
textLayouts.draw(g2d);
g2d.setTransform(oldTransform);
}
@Override public void drawLine(Point2f p1, Point2f p2, Color color, float lineWidth) {
g2d.setColor(toAwtColor(color));
g2d.setStroke(new BasicStroke(lineWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
g2d.draw(new Line2D.Float(p1.x, p1.y, p2.x, p2.y));
}
@Override public void drawStaff(Point2f pos, float length, int lines, Color color,
float lineWidth, float interlineSpace) {
g2d.setColor(toAwtColor(color));
for (int i : range(lines))
g2d.fill(new Rectangle2D.Float(pos.x, pos.y + i * interlineSpace - lineWidth / 2, length, lineWidth));
}
@Override public void drawSimplifiedStaff(Point2f pos, float length, float height, Color color) {
g2d.setColor(toAwtColor(color));
g2d.fill(new Rectangle2D.Float(pos.x, pos.y, length, height));
}
@Override public void fillPath(Path path, Color color) {
g2d.setColor(toAwtColor(color));
Shape shape = AwtPath.createShape(path);
g2d.fill(shape);
}
@Override public void fillRect(Rectangle2f rect, Color color) {
g2d.setColor(toAwtColor(color));
g2d.fill(new Rectangle2D.Float(rect.position.x, rect.position.y, rect.size.width,
rect.size.height));
}
@Override public void drawImage(Rectangle2f rect, String imagePath) {
boolean force = integrity == CanvasIntegrity.Perfect;
AwtImageRenderer.drawImage(imagePath, g2d, rect, force);
}
@Override public void transformSave() {
transformStack.push(g2d.getTransform());
}
@Override public void transformRestore() {
if (false == transformStack.isEmpty()) {
g2d.setTransform(transformStack.pop());
}
}
@Override public void transformTranslate(float x, float y) {
g2d.translate(x, y);
}
@Override public void transformScale(float x, float y) {
g2d.scale(x, y);
}
@Override public void transformRotate(float angle) {
g2d.rotate(angle * Math.PI / 180f);
}
}