package com.xenoage.zong.renderer.javafx.canvas; import static com.xenoage.utils.jse.javafx.color.JfxColorUtils.toJavaFXColor; import static com.xenoage.utils.jse.javafx.font.JfxFontUtils.toJavaFXFont; import static com.xenoage.utils.kernel.Range.range; import javafx.scene.canvas.GraphicsContext; import javafx.scene.shape.StrokeLineCap; import javafx.scene.text.Font; import com.xenoage.utils.color.Color; import com.xenoage.utils.font.TextMetrics; import com.xenoage.utils.math.Units; 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.Alignment; import com.xenoage.zong.core.text.FormattedText; import com.xenoage.zong.core.text.FormattedTextElement; import com.xenoage.zong.core.text.FormattedTextParagraph; import com.xenoage.zong.core.text.FormattedTextString; import com.xenoage.zong.core.text.FormattedTextSymbol; import com.xenoage.zong.io.selection.text.TextSelection; 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.renderer.javafx.path.JfxPath; import com.xenoage.zong.renderer.symbol.SymbolsRenderer; import com.xenoage.zong.symbols.path.Path; /** * JavaFX implementation of a {@link Canvas} * * @author Andreas Wenger */ public class JfxCanvas extends Canvas { private final GraphicsContext context; /** * Creates an {@link JfxCanvas} with the given size in mm for the given context, * format, decoration mode and itegrity. */ public JfxCanvas(GraphicsContext context, Size2f sizeMm, CanvasFormat format, CanvasDecoration decoration, CanvasIntegrity integrity) { super(sizeMm, format, decoration, integrity); this.context = context; } /** * Gets the JavaFX graphics context. */ @Override public GraphicsContext getGraphicsContext() { return context; } /** * Convenience method: Gets the JavaFX graphics context from * the given {@link Canvas}. If it is not a {@link JfxCanvas}, a {@link ClassCastException} * is thrown. */ public static GraphicsContext getGraphicsContext(Canvas canvas) { return ((JfxCanvas) canvas).getGraphicsContext(); } @Override public void drawText(FormattedText text, TextSelection selection, Point2f position, boolean yIsBaseline, float frameWidth) { context.save(); context.translate(position.x, position.y); //print the text frame paragraph for paragraph float offsetX = 0; float offsetY = 0; for (FormattedTextParagraph p : text.getParagraphs()) { TextMetrics pMetrics = p.getMetrics(); if (!yIsBaseline) offsetY += pMetrics.getAscent(); //adjustment if (p.getAlignment() == Alignment.Center) offsetX = (frameWidth - pMetrics.getWidth()) / 2; else if (p.getAlignment() == Alignment.Right) offsetX = frameWidth - pMetrics.getWidth(); else offsetX = 0; //draw elements for (FormattedTextElement e : p.getElements()) { if (e instanceof FormattedTextString) { //TODO formatting FormattedTextString t = (FormattedTextString) e; context.setFill(toJavaFXColor(t.getStyle().getColor())); Font font = toJavaFXFont(t.getStyle().getFont()); context.setFont(font); context.save(); context.scale(Units.pxToMm_1_1, Units.pxToMm_1_1); context.fillText(t.getText(), offsetX / Units.pxToMm_1_1, offsetY / Units.pxToMm_1_1); context.restore(); } else { //symbol FormattedTextSymbol fts = (FormattedTextSymbol) e; float scaling = fts.getScaling(); SymbolsRenderer.draw(fts.getSymbol(), this, Color.black, new Point2f( offsetX + fts.getOffsetX(), offsetY + fts.getSymbol().baselineOffset * scaling), new Point2f(scaling, scaling)); } offsetX += e.getMetrics().getWidth(); } //next line offsetY += p.getMetrics().getAscent() + p.getMetrics().getDescent() + p.getMetrics().getLeading(); } context.restore(); } @Override public void drawLine(Point2f p1, Point2f p2, Color color, float lineWidth) { context.setStroke(toJavaFXColor(color)); context.setLineWidth(lineWidth); context.setLineCap(StrokeLineCap.BUTT); context.strokeLine(p1.x, p1.y, p2.x, p2.y); } @Override public void drawStaff(Point2f pos, float length, int lines, Color color, float lineWidth, float interlineSpace) { context.setFill(toJavaFXColor(color)); for (int i : range(lines)) context.fillRect(pos.x, pos.y + i * interlineSpace - lineWidth / 2, length, lineWidth); } @Override public void drawSimplifiedStaff(Point2f pos, float length, float height, Color color) { context.setFill(toJavaFXColor(color)); context.fillRect(pos.x, pos.y, length, height); } @Override public void fillPath(Path path, Color color) { context.setFill(toJavaFXColor(color)); JfxPath.drawPath(path, context); context.fill(); } @Override public void fillRect(Rectangle2f rect, Color color) { context.setFill(toJavaFXColor(color)); context.fillRect(rect.position.x, rect.position.y, rect.size.width, rect.size.height); } @Override public void drawImage(Rectangle2f rect, String imagePath) { //TODO } @Override public void transformSave() { context.save(); } @Override public void transformRestore() { context.restore(); } @Override public void transformTranslate(float x, float y) { context.translate(x, y); } @Override public void transformScale(float x, float y) { context.scale(x, y); } @Override public void transformRotate(float angle) { context.rotate(angle * Math.PI / 180f); } }