/******************************************************************************* * Copyright 2012-present Pixate, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ /** * Copyright (c) 2012-2013 Pixate, Inc. All rights reserved. */ package com.pixate.freestyle.cg.views; import java.io.IOException; import android.content.Context; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Picture; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; import android.net.Uri; import android.util.AttributeSet; import android.view.View; import com.pixate.freestyle.cg.parsing.PXSVGLoader; import com.pixate.freestyle.cg.shapes.PXShapeDocument; import com.pixate.freestyle.util.ObjectUtil; import com.pixate.freestyle.util.PXLog; public class PXShapeView extends View { private static String TAG = PXShapeView.class.getSimpleName(); private static final String SVG_RESOURCE_TYPE = "svg"; private PXShapeDocument document; @SuppressWarnings("unused") private String resourcePath; // We set but never access this. Consider // deletion. private PointF shapeCenter; private PointF shapeTranslation; private PointF shapeScale; private float shapeRotation; private Matrix shapeTransform; // hold a Rect that will be re-used when drawing. private Rect bounds = new Rect(); /** * Constructs a new PXShapeView. * * @param context */ public PXShapeView(Context context) { super(context); resetTransforms(); } /** * Constructs a new PXShapeView. * * @param context * @param attrs * @param defStyle */ public PXShapeView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); resetTransforms(); } /** * Constructs a new PXShapeView. * * @param context * @param attrs */ public PXShapeView(Context context, AttributeSet attrs) { super(context, attrs); resetTransforms(); } public void setResourcePath(String resourcePath) { this.resourcePath = resourcePath; if (resourcePath != null) { if (resourcePath.endsWith(SVG_RESOURCE_TYPE)) { loadDocument(resourcePath); } else { document = null; } } else { document = null; } } public void setResourceURL(String url) { this.resourcePath = url; if (url != null) { loadDocumentFromURL(url); } } public void setShapeCenter(PointF center) { if (!ObjectUtil.areEqual(center, this.shapeCenter)) { shapeCenter = center; applyTransform(); } } public void setShapeTranslation(PointF translation) { if (!ObjectUtil.areEqual(translation, this.shapeTranslation)) { shapeTranslation = translation; applyTransform(); } } public void setShapeScale(PointF scale) { if (shapeScale != scale) { shapeScale = scale; applyTransform(); } } public void setDocument(PXShapeDocument document) { if (this.document != null) { this.document.setParentView(null); } this.document = document; if (this.document != null) { this.document.setParentView(this); } resetTransforms(); applyBoundsToDocument(); } public void setShapeRotation(float rotation) { if (shapeRotation != rotation) { shapeRotation = rotation; applyTransform(); } } protected Matrix shapeTransform() { // TODO: consider caching to ivar if used frequently shapeTransform = new Matrix(); shapeTransform.setTranslate(shapeCenter.x, shapeCenter.y); shapeTransform.setScale(shapeScale.x, shapeScale.y); shapeTransform.setRotate(shapeRotation); shapeTransform.setTranslate(-shapeCenter.x, -shapeCenter.y); shapeTransform.setTranslate(shapeTranslation.x, shapeTranslation.y); return shapeTransform; } protected void applyTransform() { document.setTransform(shapeTransform); } protected void resetTransforms() { shapeCenter = new PointF(); shapeTranslation = new PointF(); shapeScale = new PointF(1, 1); shapeRotation = 0f; } protected void loadDocument(String resourcePath) { try { document = PXSVGLoader.loadFromStream(getContext().getAssets().open(resourcePath)); } catch (IOException e) { PXLog.e(TAG, e, "Error loading the document at " + resourcePath); } } protected void loadDocumentFromURL(String url) { try { document = PXSVGLoader.loadFromURL(Uri.parse(url)); } catch (IOException e) { PXLog.e(TAG, e, "Error loading the document at " + url); } } protected void applyBoundsToDocument() { if (document != null) { // XXX Android only // TODO - need testing... if (shapeTransform != null) { RectF rect = new RectF(0, 0, (float) this.getWidth(), (float) getHeight()); shapeTransform.mapRect(rect); rect.offset((float) this.getLeft(), (float) this.getTop()); // in case the view is partially out of the screen if (getRight() < 0 || getLeft() > ((View) getParent()).getWidth()) { rect = new RectF(getLeft(), getTop(), getRight(), getBottom()); } document.setBounds(rect); } else { document.setBounds(new RectF(getLeft(), getTop(), getRight(), getBottom())); } } } @Override protected void onDraw(Canvas canvas) { canvas.getClipBounds(bounds); Picture picture = renderToImage(bounds); canvas.drawPicture(picture); } public Picture renderToImage(Canvas canvas) { if (canvas != null) { canvas.getClipBounds(bounds); return renderToImage(bounds); } return null; } public Picture renderToImage(Rect bounds) { if (document != null) { Picture image = new Picture(); try { Canvas c = image.beginRecording(bounds.width(), bounds.height()); document.render(c); } catch (Exception ioe) { PXLog.e(TAG, ioe, "Error rendering to image"); } finally { image.endRecording(); } return image; } return null; } }