/*******************************************************************************
* 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.shapes;
import java.util.HashMap;
import java.util.Map;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import com.pixate.freestyle.cg.math.PXOffsets;
import com.pixate.freestyle.cg.views.PXShapeView;
import com.pixate.freestyle.util.ObjectUtil;
/**
* A top-level container for PXShapes. This is used to define the bounds of a
* set of PXShapes. It also is a centralized container for all shape ids
* allowing you to retrieve shapes in a scene by their id.
*/
/*
* In several places herein we call methods that we have ourselves deprecated.
* Hopefully we can change these. Until then, we suppress the warnings.
*/
@SuppressWarnings("deprecation")
public class PXShapeDocument implements PXRenderable {
protected Map<String, PXRenderable> nameToShape;
/**
* The top-level shape rendered by this scene. If a collection of shapes are
* needed, then this shape will need to be a PXShapeGroup
*/
protected PXRenderable shape;
/**
* The bounds of the shapes in this scene
*/
protected RectF bounds;
/**
* The top-level view that this scene belongs to
*/
protected PXShapeView parentView;
protected Matrix transform;
protected PXOffsets padding;
/**
* Constructs a new PXScene
*/
public PXShapeDocument() {
transform = new Matrix();
}
/**
* Sets the bounds of the shapes in this scene.
*
* @param bounds the bounds to set
*/
public void setBounds(RectF bounds) {
if (ObjectUtil.areEqual(bounds, this.bounds)) {
return;
}
this.bounds = bounds;
// TODO: handle top-left as well
if (shape instanceof PXShapeGroup) {
PXShapeGroup group = (PXShapeGroup) shape;
group.setWidth(bounds.width());
group.setHeight(bounds.height());
}
}
/**
* Returns the bounds of the shapes in this scene.
*
* @return The bounds of the scene.
*/
public RectF getBounds() {
return bounds;
}
/**
* Returns a <code>null</code> parent for the scene.
*
* @see com.pixate.freestyle.cg.shapes.PXRenderable#getParent()
*/
public PXRenderable getParent() {
return null;
}
public PXOffsets getPadding() {
return padding;
}
public void setPadding(PXOffsets padding) {
if (!ObjectUtil.areEqual(padding, this.padding)) {
this.padding = padding;
}
// TODO Should we propagate the padding to the children?
}
/**
* Does nothing since scenes are always the top-most parent.
*
* @see com.pixate.freestyle.cg.shapes.PXRenderable#setParent(com.pixate.freestyle.cg.shapes.PXRenderable)
*/
public void setParent(PXRenderable parent) {
// No Op - scenes are always the top-most parent
}
/**
* Sets the top-level shape rendered by this scene. If a collection of
* shapes are needed, then this shape will need to be a PXShapeGroup
*
* @param shape A {@link PXRenderable} shape instance.
*/
public void setShape(PXRenderable shape) {
if (!ObjectUtil.areEqual(shape, this.shape)) {
// disconnect parent from old shape
if (this.shape != null) {
this.shape.setParent(null);
}
this.shape = shape;
// connect parent on new shape
if (this.shape != null) {
this.shape.setParent(this);
// XXX - Android only
if (this.shape instanceof PXShapeGroup) {
PXShapeGroup group = (PXShapeGroup) this.shape;
setBounds(new RectF(0, 0, group.getWidth(), group.getHeight()));
}
}
}
}
/**
* Returns the top-level shape rendered by this scene. If a collection of
* shapes exists in the scene, then this shape will be a PXShapeGroup.
*/
public PXRenderable getShape() {
return shape;
}
/**
* Return the shape in this scene with the specified name.
*
* @param name The name of the shape
* @returns A {@link PXRenderable} or <code>null</code>.
*/
public PXRenderable getShape(String name) {
if (nameToShape != null && name != null) {
return nameToShape.get(name);
}
return null;
}
/**
* Register a shape with the specified name with this scene.
*
* @param shape The shape to register
* @param name The shape's name
*/
public void addShape(String name, PXRenderable shape) {
if (name != null && shape != null) {
if (nameToShape == null) {
nameToShape = new HashMap<String, PXRenderable>(6);
}
nameToShape.put(name, shape);
}
}
/**
* Returns the top-level view that this scene belongs to.
*/
public PXShapeView getParentView() {
return parentView;
}
/**
* Sets the top-level view that this scene belongs to.
*
* @param parentView
*/
public void setParentView(PXShapeView parentView) {
this.parentView = parentView;
}
/**
* Sets the opacity for the scene. In case a shape was not set prior to this
* call, nothing happens.
*
* @param opacity An opacity value between 0.0 to 1.0.
*/
public void setOpacity(float opacity) {
if (shape instanceof PXShapeGroup) {
((PXShapeGroup) shape).setOpacity(opacity);
}
}
/**
* Returns the scene opacity. In case a shape was not set prior to this
* call, return 1.0F.
*
* @return The scene's opacity
*/
public float getOpacity() {
if (shape instanceof PXShapeGroup) {
return ((PXShapeGroup) shape).getOpacity();
}
return 1F;
}
public float getHeight() {
if (shape instanceof PXShapeGroup) {
return ((PXShapeGroup) shape).getHeight();
}
return 0F;
}
public float getWidth() {
if (shape instanceof PXShapeGroup) {
return ((PXShapeGroup) shape).getWidth();
}
return 0F;
}
public void setViewport(RectF viewport) {
if (shape instanceof PXShapeGroup) {
((PXShapeGroup) shape).setViewport(viewport);
}
}
/*
* (non-Javadoc)
* @see com.pixate.freestyle.pxengine.cg.PXRenderable#getTransform()
*/
public Matrix getTransform() {
return transform;
}
/**
* @param transform the transform to set. In case <code>null</code>, nothing
* will be set.
*/
public void setTransform(Matrix transform) {
if (transform != null) {
this.transform = transform;
}
}
/*
* (non-Javadoc)
* @see
* com.pixate.freestyle.pxengine.cg.PXRenderable#render(android.graphics
* .Canvas)
*/
public void render(Canvas context) {
if (shape != null) {
if (transform != null) {
context.concat(transform);
}
shape.render(context);
}
}
/**
* This implementation for render in the {@link PXShapeDocument} does
* exactly what the {@link #render(Canvas)} does.
*
* @see com.pixate.freestyle.cg.shapes.PXRenderable#render(android.graphics.Canvas,
* boolean)
* @see #render(Canvas)
*/
public void render(Canvas context, boolean cache) {
render(context);
}
public Drawable renderToImage(RectF bounds, boolean opaque) {
if (shape != null) {
return shape.renderToImage(bounds, opaque);
}
return null;
}
/*
* (non-Javadoc)
* @see com.pixate.freestyle.cg.shapes.PXRenderable#isAsynchronous()
*/
@Override
public boolean isAsynchronous() {
return shape != null && shape.isAsynchronous();
}
}