// -*- mode: java; c-basic-offset: 2; -*- // Copyright 2009-2011 Google, All Rights reserved // Copyright 2011-2012 MIT, All rights reserved // Released under the Apache License, Version 2.0 // http://www.apache.org/licenses/LICENSE-2.0 package com.google.appinventor.components.runtime; import com.google.appinventor.components.annotations.DesignerComponent; import com.google.appinventor.components.annotations.DesignerProperty; import com.google.appinventor.components.annotations.PropertyCategory; import com.google.appinventor.components.annotations.SimpleFunction; import com.google.appinventor.components.annotations.SimpleObject; import com.google.appinventor.components.annotations.SimpleProperty; import com.google.appinventor.components.annotations.UsesPermissions; import com.google.appinventor.components.common.ComponentCategory; import com.google.appinventor.components.common.PropertyTypeConstants; import com.google.appinventor.components.common.YaVersion; import com.google.appinventor.components.runtime.errors.IllegalArgumentError; import com.google.appinventor.components.runtime.util.AnimationUtil; import com.google.appinventor.components.runtime.util.ErrorMessages; import com.google.appinventor.components.runtime.util.HoneycombUtil; import com.google.appinventor.components.runtime.util.MediaUtil; import com.google.appinventor.components.runtime.util.SdkLevel; import com.google.appinventor.components.runtime.util.ViewUtil; import android.graphics.drawable.Drawable; import android.util.Log; import android.view.View; import android.widget.ImageView; import java.io.IOException; /** * Component for displaying images and animations. * */ @DesignerComponent(version = YaVersion.IMAGE_COMPONENT_VERSION, category = ComponentCategory.USERINTERFACE, description = "Component for displaying images. The picture to display, " + "and other aspects of the Image's appearance, can be specified in the " + "Designer or in the Blocks Editor.") @SimpleObject @UsesPermissions(permissionNames = "android.permission.INTERNET") public final class Image extends AndroidViewComponent { private final ImageView view; private String picturePath = ""; // Picture property private double rotationAngle = 0.0; private int scalingMode = Component.SCALING_SCALE_PROPORTIONALLY; /** * Creates a new Image component. * * @param container container, component will be placed in */ public Image(ComponentContainer container) { super(container); view = new ImageView(container.$context()) { @Override public boolean verifyDrawable(Drawable dr) { super.verifyDrawable(dr); // TODO(user): multi-image animation return true; } }; view.setFocusable(true); // Adds the component to its designated container container.$add(this); } @Override public View getView() { return view; } /** * Returns the path of the image's picture. * * @return the path of the image's picture */ @SimpleProperty( category = PropertyCategory.APPEARANCE) public String Picture() { return picturePath; } /** * Specifies the path of the image's picture. * * <p/>See {@link MediaUtil#determineMediaSource} for information about what * a path can be. * * @param path the path of the image's picture */ @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_ASSET, defaultValue = "") @SimpleProperty public void Picture(String path) { picturePath = (path == null) ? "" : path; Drawable drawable; try { drawable = MediaUtil.getBitmapDrawable(container.$form(), picturePath); } catch (IOException ioe) { Log.e("Image", "Unable to load " + picturePath); drawable = null; } ViewUtil.setImage(view, drawable); } /** * Specifies the angle at which the image picture appears rotated. * * @param rotated the rotation angle */ @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_FLOAT, defaultValue = "0.0") @SimpleProperty public void RotationAngle(double rotationAngle) { if (this.rotationAngle == rotationAngle) { return; // Nothing to do... // This also means that you can always set the // the angle to 0.0 even on older Android devices } if (SdkLevel.getLevel() < SdkLevel.LEVEL_HONEYCOMB) { container.$form().dispatchErrorOccurredEvent(this, "RotationAngle", ErrorMessages.ERROR_IMAGE_CANNOT_ROTATE); return; } HoneycombUtil.viewSetRotate(view, rotationAngle); this.rotationAngle = rotationAngle; } @SimpleProperty(description = "The angle at which the image picture appears rotated. " + "This rotation does not appear on the designer screen, only on the device.", category = PropertyCategory.APPEARANCE) public double RotationAngle() { return rotationAngle; } @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_BOOLEAN, defaultValue = "False") // @Deprecated -- We will deprecate this in a future release (jis: 2/12/2016) @SimpleProperty(description = "Specifies whether the image should be resized to match the size of the ImageView.") public void ScalePictureToFit(boolean scale) { if (scale) view.setScaleType(ImageView.ScaleType.FIT_XY); else view.setScaleType(ImageView.ScaleType.FIT_CENTER); } /** * Animation property setter method. * * @see AnimationUtil * * @param animation animation kind */ @SimpleProperty(description = "This is a limited form of animation that can attach " + "a small number of motion types to images. The allowable motions are " + "ScrollRightSlow, ScrollRight, ScrollRightFast, ScrollLeftSlow, ScrollLeft, " + "ScrollLeftFast, and Stop", category = PropertyCategory.APPEARANCE) // TODO(user): This should be changed from a property to an "animate" method, and have the choices // placed in a dropdown. Aternatively the whole thing should be removed and we should do // something that is more consistent with sprites. public void Animation(String animation) { AnimationUtil.ApplyAnimation(view, animation); } @Deprecated // @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_SCALING, // defaultValue = Component.SCALING_SCALE_PROPORTIONALLY + "") @SimpleProperty(description = "This property determines how the picture " + "scales according to the Height or Width of the Image. Scale " + "proportionally (0) preserves the picture aspect ratio. Scale to fit " + "(1) matches the Image area, even if the aspect ratio changes.") public void Scaling(int mode) { switch (mode) { case 0: view.setScaleType(ImageView.ScaleType.FIT_CENTER); break; case 1: view.setScaleType(ImageView.ScaleType.FIT_XY); break; default: throw new IllegalArgumentError("Illegal scaling mode: " + mode); } scalingMode = mode; } @SimpleProperty public int Scaling() { return scalingMode; } }