1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view.animation;
18
19import android.annotation.FloatRange;
20import android.graphics.Matrix;
21import android.graphics.Rect;
22
23import java.io.PrintWriter;
24
25/**
26 * Defines the transformation to be applied at
27 * one point in time of an Animation.
28 *
29 */
30public class Transformation {
31    /**
32     * Indicates a transformation that has no effect (alpha = 1 and identity matrix.)
33     */
34    public static final int TYPE_IDENTITY = 0x0;
35    /**
36     * Indicates a transformation that applies an alpha only (uses an identity matrix.)
37     */
38    public static final int TYPE_ALPHA = 0x1;
39    /**
40     * Indicates a transformation that applies a matrix only (alpha = 1.)
41     */
42    public static final int TYPE_MATRIX = 0x2;
43    /**
44     * Indicates a transformation that applies an alpha and a matrix.
45     */
46    public static final int TYPE_BOTH = TYPE_ALPHA | TYPE_MATRIX;
47
48    protected Matrix mMatrix;
49    protected float mAlpha;
50    protected int mTransformationType;
51
52    private boolean mHasClipRect;
53    private Rect mClipRect = new Rect();
54
55    /**
56     * Creates a new transformation with alpha = 1 and the identity matrix.
57     */
58    public Transformation() {
59        clear();
60    }
61
62    /**
63     * Reset the transformation to a state that leaves the object
64     * being animated in an unmodified state. The transformation type is
65     * {@link #TYPE_BOTH} by default.
66     */
67    public void clear() {
68        if (mMatrix == null) {
69            mMatrix = new Matrix();
70        } else {
71            mMatrix.reset();
72        }
73        mClipRect.setEmpty();
74        mHasClipRect = false;
75        mAlpha = 1.0f;
76        mTransformationType = TYPE_BOTH;
77    }
78
79    /**
80     * Indicates the nature of this transformation.
81     *
82     * @return {@link #TYPE_ALPHA}, {@link #TYPE_MATRIX},
83     *         {@link #TYPE_BOTH} or {@link #TYPE_IDENTITY}.
84     */
85    public int getTransformationType() {
86        return mTransformationType;
87    }
88
89    /**
90     * Sets the transformation type.
91     *
92     * @param transformationType One of {@link #TYPE_ALPHA},
93     *        {@link #TYPE_MATRIX}, {@link #TYPE_BOTH} or
94     *        {@link #TYPE_IDENTITY}.
95     */
96    public void setTransformationType(int transformationType) {
97        mTransformationType = transformationType;
98    }
99
100    /**
101     * Clones the specified transformation.
102     *
103     * @param t The transformation to clone.
104     */
105    public void set(Transformation t) {
106        mAlpha = t.getAlpha();
107        mMatrix.set(t.getMatrix());
108        if (t.mHasClipRect) {
109            setClipRect(t.getClipRect());
110        } else {
111            mHasClipRect = false;
112            mClipRect.setEmpty();
113        }
114        mTransformationType = t.getTransformationType();
115    }
116
117    /**
118     * Apply this Transformation to an existing Transformation, e.g. apply
119     * a scale effect to something that has already been rotated.
120     * @param t
121     */
122    public void compose(Transformation t) {
123        mAlpha *= t.getAlpha();
124        mMatrix.preConcat(t.getMatrix());
125        if (t.mHasClipRect) {
126            Rect bounds = t.getClipRect();
127            if (mHasClipRect) {
128                setClipRect(mClipRect.left + bounds.left, mClipRect.top + bounds.top,
129                        mClipRect.right + bounds.right, mClipRect.bottom + bounds.bottom);
130            } else {
131                setClipRect(bounds);
132            }
133        }
134    }
135
136    /**
137     * Like {@link #compose(Transformation)} but does this.postConcat(t) of
138     * the transformation matrix.
139     * @hide
140     */
141    public void postCompose(Transformation t) {
142        mAlpha *= t.getAlpha();
143        mMatrix.postConcat(t.getMatrix());
144        if (t.mHasClipRect) {
145            Rect bounds = t.getClipRect();
146            if (mHasClipRect) {
147                setClipRect(mClipRect.left + bounds.left, mClipRect.top + bounds.top,
148                        mClipRect.right + bounds.right, mClipRect.bottom + bounds.bottom);
149            } else {
150                setClipRect(bounds);
151            }
152        }
153    }
154
155    /**
156     * @return The 3x3 Matrix representing the trnasformation to apply to the
157     * coordinates of the object being animated
158     */
159    public Matrix getMatrix() {
160        return mMatrix;
161    }
162
163    /**
164     * Sets the degree of transparency
165     * @param alpha 1.0 means fully opaqe and 0.0 means fully transparent
166     */
167    public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
168        mAlpha = alpha;
169    }
170
171    /**
172     * Sets the current Transform's clip rect
173     * @hide
174     */
175    public void setClipRect(Rect r) {
176        setClipRect(r.left, r.top, r.right, r.bottom);
177    }
178
179    /**
180     * Sets the current Transform's clip rect
181     * @hide
182     */
183    public void setClipRect(int l, int t, int r, int b) {
184        mClipRect.set(l, t, r, b);
185        mHasClipRect = true;
186    }
187
188    /**
189     * Returns the current Transform's clip rect
190     * @hide
191     */
192    public Rect getClipRect() {
193        return mClipRect;
194    }
195
196    /**
197     * Returns whether the current Transform's clip rect is set
198     * @hide
199     */
200    public boolean hasClipRect() {
201        return mHasClipRect;
202    }
203
204    /**
205     * @return The degree of transparency
206     */
207    public float getAlpha() {
208        return mAlpha;
209    }
210
211    @Override
212    public String toString() {
213        StringBuilder sb = new StringBuilder(64);
214        sb.append("Transformation");
215        toShortString(sb);
216        return sb.toString();
217    }
218
219    /**
220     * Return a string representation of the transformation in a compact form.
221     */
222    public String toShortString() {
223        StringBuilder sb = new StringBuilder(64);
224        toShortString(sb);
225        return sb.toString();
226    }
227
228    /**
229     * @hide
230     */
231    public void toShortString(StringBuilder sb) {
232        sb.append("{alpha="); sb.append(mAlpha);
233        sb.append(" matrix="); mMatrix.toShortString(sb);
234        sb.append('}');
235    }
236
237    /**
238     * Print short string, to optimize dumping.
239     * @hide
240     */
241    public void printShortString(PrintWriter pw) {
242        pw.print("{alpha="); pw.print(mAlpha);
243        pw.print(" matrix=");
244        mMatrix.printShortString(pw);
245        pw.print('}');
246    }
247}
248