package com.xenoage.zong.android.renderer.canvas;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Cap;
import android.graphics.Paint.Join;
import android.graphics.Paint.Style;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import com.xenoage.utils.android.Conversion;
import com.xenoage.utils.android.color.AndroidColorUtils;
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.android.renderer.path.AndroidPath;
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.CanvasDecoration;
import com.xenoage.zong.renderer.canvas.CanvasFormat;
import com.xenoage.zong.renderer.canvas.CanvasIntegrity;
import com.xenoage.zong.renderer.slur.SimpleSlurShape;
import com.xenoage.zong.symbols.PathSymbol;
import com.xenoage.zong.symbols.Symbol;
import com.xenoage.zong.symbols.path.Path;
import static com.xenoage.zong.android.renderer.symbols.AndroidSymbolsRenderer.androidSymbolsRenderer;
/**
* This class contains methods for painting
* on an Android device.
*
* @author Andreas Wenger
*/
public class AndroidCanvas
extends com.xenoage.zong.renderer.canvas.Canvas {
/** The Android graphics context. */
private Canvas canvas;
/**
* Creates an {@link AndroidCanvas} with the given size in mm for the given context,
* format, decoration mode and integrity.
*/
public AndroidCanvas(Canvas canvas, Size2f sizeMm, CanvasFormat format,
CanvasDecoration decoration, CanvasIntegrity integrity) {
super(sizeMm, format, decoration, integrity);
this.canvas = canvas;
}
/**
* Gets the Android graphics context.
*/
@Override public Canvas getGraphicsContext() {
return canvas;
}
/**
* Convenience method: Gets the {@link Canvas} graphics context from
* the given {@link com.xenoage.zong.renderer.canvas.Canvas}.
* If it is not a {@link AndroidCanvas}, a {@link ClassCastException} is thrown.
*/
public static Canvas getCanvas(com.xenoage.zong.renderer.canvas.Canvas canvas) {
return ((AndroidCanvas) canvas).getGraphicsContext();
}
/**
* {@inheritDoc}
* The text selection is ignored.
*/
@Override public void drawText(FormattedText text, TextSelection selection, Point2f position,
boolean yIsBaseline, float frameWidth) {
int oldTransform = canvas.save();
canvas.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;
Paint paint = new Paint(AndroidColorUtils.black);
paint.setTypeface(Typeface.SERIF);
paint.setTextSize(Units.pxToMm(t.getStyle().getFont().getSize(), 1));
paint.setFlags(Paint.LINEAR_TEXT_FLAG | Paint.ANTI_ALIAS_FLAG); //nice, smooth drawing
canvas.drawText(t.getText(), offsetX, offsetY, paint);
}
else {
//symbol
FormattedTextSymbol fts = (FormattedTextSymbol) e;
float scaling = fts.getScaling();
androidSymbolsRenderer.draw((PathSymbol) fts.getSymbol(), canvas, 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();
}
canvas.restoreToCount(oldTransform);
}
@Override public void drawLine(Point2f p1, Point2f p2, Color color, float lineWidth) {
Paint paint = new Paint();
paint.setColor(AndroidColorUtils.createColor(color));
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(lineWidth);
paint.setStrokeCap(Cap.BUTT);
paint.setStrokeJoin(Join.BEVEL);
canvas.drawLine(p1.x, p1.y, p2.x, p2.y, paint);
}
@Override public void drawStaff(Point2f pos, float length, int lines, Color color,
float lineWidth, float interlineSpace) {
Paint paint = AndroidColorUtils.createPaintFill(color);
for (int i = 0; i < lines; i++) {
float x = pos.x;
float y = pos.y + i * interlineSpace - lineWidth / 2;
canvas.drawRect(new RectF(x, y, x + length, y + lineWidth), paint);
}
}
@Override public void drawSimplifiedStaff(Point2f pos, float length, float height, Color color) {
Paint paint = AndroidColorUtils.createPaintFill(color);
canvas.drawRect(new RectF(pos.x, pos.y, pos.x + length, pos.y + height), paint);
}
@Override public void fillPath(Path path, Color color) {
Paint paint = AndroidColorUtils.createPaintFill(color);
android.graphics.Path p = AndroidPath.createPath(path);
canvas.drawPath(p, paint);
}
@Override public void fillRect(Rectangle2f rect, Color color) {
Paint paint = AndroidColorUtils.createPaintFill(color);
RectF r = Conversion.rectF(rect);
canvas.drawRect(r, paint);
}
@Override public void drawImage(Rectangle2f rect, String imagePath) {
//TODO: not supported yet
}
@Override public void transformSave() {
canvas.save();
}
@Override public void transformRestore() {
canvas.restore();
}
@Override public void transformTranslate(float x, float y) {
canvas.translate(x, y);
}
@Override public void transformScale(float x, float y) {
canvas.scale(x, y);
}
@Override public void transformRotate(float angle) {
canvas.rotate(angle);
}
}