blob: 01a21037b7cde258bacd0a63463581b8916cb3b6 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You 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.
//
////////////////////////////////////////////////////////////////////////////////
package mx.graphics
{
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.geom.Matrix;
import mx.core.mx_internal;
import mx.events.PropertyChangeEvent;
import mx.geom.CompoundTransform;
use namespace mx_internal;
[DefaultProperty("entries")]
/**
* The GradientBase class is the base class for
* LinearGradient, LinearGradientStroke, and RadialGradient.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public class GradientBase extends EventDispatcher
{
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Constructor.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function GradientBase()
{
super();
}
//--------------------------------------------------------------------------
//
// Variables
//
//--------------------------------------------------------------------------
/**
* @private
*/
mx_internal var colors:Array /* of uint */ = [];
/**
* @private
*/
mx_internal var ratios:Array /* of Number */ = [];
/**
* @private
*/
mx_internal var alphas:Array /* of Number */ = [];
//--------------------------------------------------------------------------
//
// Class Properties
//
//--------------------------------------------------------------------------
/**
* Value of the width and height of the untransformed gradient
*
* @langversion 3.0
* @playerversion Flash 10
* @playerversion AIR 1.5
* @productversion Flex 4
*/
public static const GRADIENT_DIMENSION:Number = 1638.4;
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
//----------------------------------
// angle
//----------------------------------
/**
* @private
* Storage for the angle property.
*/
mx_internal var _angle:Number;
[Inspectable(category="General")]
[Deprecated(replacement="rotation")]
/**
* By default, the LinearGradientStroke defines a transition
* from left to right across the control.
* Use the <code>angle</code> property to control the transition direction.
* For example, a value of 180.0 causes the transition
* to occur from right to left, rather than from left to right.
*
* @default 0.0
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get angle():Number
{
return _angle / Math.PI * 180;
}
/**
* @private
*/
public function set angle(value:Number):void
{
var oldValue:Number = _angle;
_angle = value / 180 * Math.PI;
dispatchGradientChangedEvent("angle", oldValue, _angle);
}
//----------------------------------
// compoundTransform
//----------------------------------
/**
* Holds the matrix and the convenience transform properties (<code>x</code>, <code>y</code>, and <code>rotation</code>).
* The compoundTransform is only created when the <code>matrix</code> property is set.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
protected var compoundTransform:CompoundTransform;
//----------------------------------
// entries
//----------------------------------
/**
* @private
* Storage for the entries property.
*/
private var _entries:Array = [];
[Bindable("propertyChange")]
[Inspectable(category="General", arrayType="mx.graphics.GradientEntry")]
/**
* An Array of GradientEntry objects
* defining the fill patterns for the gradient fill.
*
* @default []
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get entries():Array
{
return _entries;
}
/**
* @private
*/
public function set entries(value:Array):void
{
var oldValue:Array = _entries;
_entries = value;
processEntries();
dispatchGradientChangedEvent("entries", oldValue, value);
}
//----------------------------------
// interpolationMethod
//----------------------------------
/**
* @private
* Storage for the interpolationMethod property.
*/
private var _interpolationMethod:String = "rgb";
[Inspectable(category="General", enumeration="rgb,linearRGB", defaultValue="rgb")]
/**
* A value from the InterpolationMethod class
* that specifies which interpolation method to use.
*
* <p>Valid values are <code>InterpolationMethod.LINEAR_RGB</code>
* and <code>InterpolationMethod.RGB</code>.</p>
*
* @default InterpolationMethod.RGB
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get interpolationMethod():String
{
return _interpolationMethod;
}
/**
* @private
*/
public function set interpolationMethod(value:String):void
{
var oldValue:String = _interpolationMethod;
if (value != oldValue)
{
_interpolationMethod = value;
dispatchGradientChangedEvent("interpolationMethod", oldValue, value);
}
}
//----------------------------------
// matrix
//----------------------------------
/**
* @private
* Storage for the matrix property.
*/
private var _matrix:Matrix;
[Inspectable(category="General")]
/**
* An array of values used for matrix transformation.
*
* <p>The gradient <code>scaleX</code> and <code>scaleY</code> properties represent pixels while the Matrix scale properties represent multipliers.
* Thus they are not compatible.
* Another difference is the most of the transform properties (<code>x</code>, <code>y</code>, <code>scaleX</code>, and <code>scaleY</code>)
* support NaN values while the matrix does not. A NaN value means that the gradient will choose an appropriate value.</p>
*
* <p>The <code>scaleX</code> and <code>scaleY</code> properties can not be represented by the matrix.
* Once the matrix is set, <code>scaleX</code> and <code>scaleY</code> can no longer be set.
* Also, <code>x</code> and <code>y</code> can not be set to NaN.
* The matrix can be set back to null which also resets all of the convenience transform properties back to their default values.</p>
*
* <p>If the matrix is set, then the gradient draw logic will scale the gradient to fit the bounds of the graphic element.
* It will then position the gradient in the upper left corner of the graphic element.
* Finally, it will apply the matrix transformations.</p>
* <p>By default, the LinearGradientStroke defines a transition
* from left to right across the control.
* Use the <code>rotation</code> property to control the transition direction.
* For example, a value of 180.0 causes the transition
* to occur from right to left, rather than from left to right.</p>
*
* @default null
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get matrix():Matrix
{
return compoundTransform ? compoundTransform.matrix : null;
}
/**
* @private
*/
public function set matrix(value:Matrix):void
{
var oldValue:Matrix = matrix;
var oldX:Number = x;
var oldY:Number = y;
var oldRotation:Number = rotation;
if (value == null)
{
compoundTransform = null;
x = NaN;
y = NaN;
rotation = 0;
}
else
{
// Create the transform if none exists.
if (compoundTransform == null)
compoundTransform = new CompoundTransform();
compoundTransform.matrix = value; // CompoundTransform will create a clone
dispatchGradientChangedEvent("x", oldX, compoundTransform.x);
dispatchGradientChangedEvent("y", oldY, compoundTransform.y);
dispatchGradientChangedEvent("rotation", oldRotation, compoundTransform.rotationZ);
}
}
//----------------------------------
// rotation
//----------------------------------
/**
* @private
* Storage for the rotation property.
*/
private var _rotation:Number = 0.0;
[Bindable("propertyChange")]
[Inspectable(category="General")]
/**
* By default, the LinearGradientStroke defines a transition
* from left to right across the control.
* Use the <code>rotation</code> property to control the transition direction.
* For example, a value of 180.0 causes the transition
* to occur from right to left, rather than from left to right.
*
* @default 0.0
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get rotation():Number
{
return compoundTransform ? compoundTransform.rotationZ : _rotation;
}
/**
* @private
*/
public function set rotation(value:Number):void
{
if (value != rotation)
{
var oldValue:Number = rotation;
if (compoundTransform)
compoundTransform.rotationZ = value;
else
_rotation = value;
dispatchGradientChangedEvent("rotation", oldValue, value);
}
}
//----------------------------------
// spreadMethod
//----------------------------------
/**
* @private
* Storage for the spreadMethod property.
*/
private var _spreadMethod:String = "pad";
[Bindable("propertyChange")]
[Inspectable(category="General", enumeration="pad,reflect,repeat", defaultValue="pad")]
/**
* A value from the SpreadMethod class
* that specifies which spread method to use.
*
* <p>Valid values are <code>SpreadMethod.PAD</code>,
* <code>SpreadMethod.REFLECT</code>,
* and <code>SpreadMethod.REPEAT</code>.</p>
*
* @default SpreadMethod.PAD
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get spreadMethod():String
{
return _spreadMethod;
}
/**
* @private
*/
public function set spreadMethod(value:String):void
{
var oldValue:String = _spreadMethod;
if (value != oldValue)
{
_spreadMethod = value;
dispatchGradientChangedEvent("spreadMethod", oldValue, value);
}
}
//----------------------------------
// x
//----------------------------------
private var _x:Number;
[Bindable("propertyChange")]
[Inspectable(category="General")]
/**
* The distance by which to translate each point along the x axis.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get x():Number
{
return compoundTransform ? compoundTransform.x : _x;
}
/**
* @private
*/
public function set x(value:Number):void
{
var oldValue:Number = x;
if (value != oldValue)
{
if (compoundTransform)
{
// If we have a compoundTransform, only non-NaN values are allowed
if (!isNaN(value))
compoundTransform.x = value;
}
else
{
_x = value;
}
dispatchGradientChangedEvent("x", oldValue, value);
}
}
//----------------------------------
// y
//----------------------------------
private var _y:Number;
[Bindable("propertyChange")]
[Inspectable(category="General")]
/**
* The distance by which to translate each point along the y axis.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get y():Number
{
return compoundTransform ? compoundTransform.y : _y;
}
/**
* @private
*/
public function set y(value:Number):void
{
var oldValue:Number = y;
if (value != oldValue)
{
if (compoundTransform)
{
// If we have a compoundTransform, only non-NaN values are allowed
if (!isNaN(value))
compoundTransform.y = value;
}
else
{
_y = value;
}
dispatchGradientChangedEvent("y", oldValue, value);
}
}
mx_internal function get rotationInRadians():Number
{
return rotation / 180 * Math.PI;
}
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* @private
* Extract the gradient information in the public <code>entries</code>
* Array into the internal <code>colors</code>, <code>ratios</code>,
* and <code>alphas</code> arrays.
*/
private function processEntries():void
{
colors = [];
ratios = [];
alphas = [];
if (!_entries || _entries.length == 0)
return;
var ratioConvert:Number = 255;
var i:int;
var n:int = _entries.length;
for (i = 0; i < n; i++)
{
var e:GradientEntry = _entries[i];
e.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE,
entry_propertyChangeHandler, false, 0, true);
colors.push(e.color);
alphas.push(e.alpha);
ratios.push(e.ratio * ratioConvert);
}
if (isNaN(ratios[0]))
ratios[0] = 0;
if (isNaN(ratios[n - 1]))
ratios[n - 1] = 255;
i = 1;
while (true)
{
while (i < n && !isNaN(ratios[i]))
{
i++;
}
if (i == n)
break;
var start:int = i - 1;
while (i < n && isNaN(ratios[i]))
{
i++;
}
var br:Number = ratios[start];
var tr:Number = ratios[i];
for (var j:int = 1; j < i - start; j++)
{
ratios[j] = br + j * (tr - br) / (i - start);
}
}
}
/**
* Dispatch a gradientChanged event.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
mx_internal function dispatchGradientChangedEvent(prop:String,
oldValue:*, value:*):void
{
dispatchEvent(PropertyChangeEvent.createUpdateEvent(this, prop,
oldValue, value));
}
//--------------------------------------------------------------------------
//
// Event handlers
//
//--------------------------------------------------------------------------
/**
* @private
*/
private function entry_propertyChangeHandler(event:Event):void
{
processEntries();
dispatchGradientChangedEvent("entries", entries, entries);
}
}
}