lundi, octobre 11 2004

BroadcasterMX : une hérésie !

Actuellement en train de recoder "maison" certaines classe fournies par Macromédia (principalement mx.transitions.Tween et mx.transitions.OnEnterFrameBeacon), j'ai encore du mal à comprendre pourquoi la classe BroadcasterMX est utilisée ... :\

En effet, il existe toujours son ancêtre historique du nom de AsBroadcaster (attention aux majuscules :P). Cette classe, présente depuis Flash 5, a l'immense avantage d'être native au player, codée en C (ou autre langage compilé), et donc bien plus performante !!! Son successeur est quant-à lui codé en AS2 (donc en bytecode interprété). Etant donné qu'il n'existe strictement aucune différence de fonctionnalité, pourquoi faire le sacrifice de l'éfficacité ??? :o

Quoi qu'il en soit, depuis pas si longtemps que ça, je suis devenu bien plus adepte du modèle EventDispatcher, dont je me sers dans les nouvelles classes que je publierai ici-même dans trés peu de temps ... 8)

samedi, octobre 9 2004

Strucutures de données : Grid et HashTable

J'entame un petit package 'data' qui contiendra différentes structures de données parfois bien utiles. L'idée m'est venue du besoin d'une HashTable, que j'avais eu l'occasion de manipuler durant mes quelques aventures avec Java. J'en ai ainsi profité pour refaire la classe Grid que vous connaissez déjà peut-être ...

Pour ceux qui n'ont pas la chance de la connaitre, la classe HashTable correspond à l'utilisation d'un tableau, sauf que les clés n'ont pas de contrainte et peuvent être de n'importe quel type, contrairement au tableau qui a besoin de clés numériques, ou au tableau associatif qui a besoin de clés alphanumériques. Il s'agit donc d'un "simple" système d'association clés/valeurs.
import com.lalex.data.*;
var ht:HashTable = new HashTable();
var k1 = new Date();
var k2 = ["un", "tableau", "comme", "clé"];
ht.put("clé", "valeur");
ht.put(k1, "date");
ht.put(k2, ["un", "tableau", "comme", "valeur"]);
trace(ht);
/** Sortie
[ clé => valeur
  Sat Oct 9 14:14:53 GMT+0200 2004 => date
  un,tableau,comme,clé => un,tableau,comme,valeur ]
*/

// Récupère un élément
trace("k2 : " + ht.get(k2));
/** Sortie
k2 : un,tableau,comme,valeur
*/

// Supprime un élément
ht.remove(k2);
trace(ht);
/** Sortie
[ clé => valeur
  Sat Oct 9 14:14:53 GMT+0200 2004 => date ]
*/
La classe Grid, quant à elle, est un simple tableau à deux dimensions, agrémenté de quelques méthodes assez pratiques. ;)import com.lalex.data.*;
var gr:Grid = new Grid(2,3);
gr.fill(1,2,3,4,5,6);
trace(gr);
/** Sortie
[[1 , 2]
 [3 , 4]
 [5 , 6]]
*/

// Inverse la grille
gr.reverse();
trace(gr);
/** Sortie
[[1 , 3 , 5]
 [2 , 4 , 6]]
*/

// Met tous les éléments de la grille au carré
gr.map(function(n) { return n*n; });
trace(gr);
/** Sortie
[[1 , 9 , 25]
 [4 , 16 , 36]]
*/

::Télecharger data.zip::

vendredi, septembre 17 2004

Tween2 : quand Tween rencontre EventDispatcher

Sortant tout juste d'un développement utilisant des composants Macromedia à profusion, j'ai pas la même occasion eu l'opportunité de commencer à fréquenter le model évenementiel de ceux-ci, introduit par la classe EventDispatcher ... En effet, jusqu'à aujourd'hui, j'étais assez satisfait des services de AsBroadcaster (d'ailleurs, je ne trouve toujours pas d'utilité à la classe BroadcasterMX, offrant exactement la même chose mais en AS, donc moins performant) ...

Il ne m'a pas fallu longtemps pour me rendre compte de l'interêt de ce nouveau système, que ce soit en terme d'externalisation de l'interception des événements (même si c'était déjà possible avant), de performance acrues du fait de la diffusion propre à chaque évenement, mais aussi et surtout de souplesse grâce à la délégation d'évenement. D'ailleurs, je suis bien fan de la classe EventDelegate à mon sens bien plus élégante que Delegate, fourni avec la MAJ 7.2 de Flash.

J'ai donc suivi la voie tracée par Grant Skinner, qui propose ses classes XML2 et LoadVars2, utilisant EventDispatcher, en créant ma classe fille de l'illustre Tween de Penner (maintenant intégrée à la distribution de Flash MX 2004 en tant que mx.transitions.Tween), qui utilise dorénavant EventDispatcher.

Deux petits avantages mineurs amenés aussi par cette version sont qu'on ne peut du coup plus utiliser les méthodes "old-school" directement avec l'objet Tween, qui sont devenues des membres privés, forcant à externaliser le code sous forme d'écouteurs, et également le typage fort des paramètres du constructeur ... En gros, ca oblige un peu plus à faire les choses correctement ;)

Exemple d'utilisation :import com.lalex.animation.Tween2;
import com.robertpenner.easing.Expo;
var tw:Tween2 = new Tween2(myClip, "_x", Expo.easeOut, 100, 300, 32);
var listen:Object = {};
listen.motionChanged = function(e:Object) {
   trace("Clip position : " + e.position);
}
tw.addEventListener("motionChanged", listen);

On peut imaginer que les "classes" (?) telles que Mouse; Stage ou Keyboard pourraient être remplacées par leur "version 2" assez facilement (sans héritage celle-là par contre), mais cela mérite des tests : je ne suis pas persuadé des performances prodiguées par des évenements qui interviennent aussi souvent ... :o

::Télécharger Tween2.zip::

lundi, septembre 13 2004

Essential ActionScript 2.0 : la review

Colin Moock s'est imposé depuis son livre ActionScript for Flash MX : the Definitive Guide comme ayant écris l'ouvrage de référence des programmeurs Flash. Aujourd'hui, il remet le couvert et se penche sur le "nouveau" langage de Macromedia, introduit dans Flash MX 2004, avec Essential ActionScript 2.0.

Loin de remplacer son précédant ouvrage, cette nouvelle référence se veut comme étant un complément de celui-ci. En effet, alors que le premier était une liste quasi-exhaustive de l'AS1, EAS2 s'attaque à la philosophie de développement complètement revue d'AS2, du fait de son orientation objet. Il s'adresse donc en bloc aux programmeurs AS1 intermédiaires, ainsi qu'aux développeurs objets issus de langages plus "traditionnels" tels que Java ou C++, et aux programmeurs AS2 intermédiaires et même confirmés.

La première partie du livre aborde la syntaxe AS2. Mêlant habilement l'initiation à la programmation objet, et la description des instructions introduites par la nouvelle mouture d'ActionScript, cette partie fourni au futur programmeur AS2 tous les outils nécessaires à ses premiers développements. N'oubliant pas d'aller au fond des choses, Colin Moock décortique chaque instruction à l'extrême, soulignant les particularités des nombreuses situations qui peuvent se présenter au codeur face aux instructions AS2.
Parfois répétitif dans son discours, mais jamais rébarbatif, il mets systématiquement le doigt sur les erreurs que l'on fait fréquemment lorsque l'on aborde l'AS2, et souligne les avantages indéniables qu'apporte ce nouveau langage, mais aussi cette nouvelle façon d'aborder le développement dans Flash.
Non content de donner une explication théorique exhaustive des syntaxes de base, des exemples concrets sont apportés avant d’aborder chaque nouvelle notion importante, nous guidant ainsi au travers du développement d'une classe ImageViewer, dans laquelle sont utilisées les notions précédemment abordées de manière plus formelle.

La deuxième partie aborde les méthodes à utiliser lors du développement d'application. L'auteur nous y présente tout d'abord sa méthode de travail "de base" notamment en terme de hiérarchie des dossiers et documents. Sans être révolutionnaire, elle a le mérite d'être simple, claire et efficace. Si vous n'avez pas déjà vos propres habitudes de développement objet, je dirais tout simplement que l'essayer c'est l'adopter, et si vous les avez déjà, vous pourrez ainsi les confronter à celles qui sont données dans ce chapitre.
Les chapitres suivant nous emmènent vers la programmation "visuelle", tout d'abord en abordant les composants et leur utilisation, en exposant notamment leur intégration à une application concrète de convertisseur de devises, puis en consacrant un chapitre entier à l'héritage de MovieClip, nous en dévoilant ainsi toutes ses subtilités, et également les aspects à prendre en compte pour effectuer un choix entre l'héritage et la composition avec MovieClip.
Cette partie se finit en décortiquant les différents moyens mis à notre disposition pour distribuer un code, que ce soit en OpenSource ou sans mettre les fichiers sources à dispositions des utilisateurs, en énonçant clairement les avantages, inconvénients et difficultés de chacune des méthodes.

La troisième partie se penche sur 4 Design Patterns, parmi les plus utilisés dans Flash que sont l'Observer, le Singleton, le Model-View-Controller (MVC) et la Délégation d'événements. Plus qu'une description approfondie de ces patterns, il s'agit plutôt dans cette partie de montrer leur utilité au sein d'applications AS2, ainsi que leur implémentation au sein d'exemple toujours aussi concrets.

Je ne peux que supposer la réaction des différentes catégories de lecteurs visées par ce livre :

  • Pour les développeurs AS1, il introduit en douceur mais également en profondeur toutes les subtilités de AS2. Etant déjà convaincu, je ne peux que suggérer, mais je dirais que ce livre peut réussir à convaincre ceux qui sont encore réfractaire à l'AS2, en soulignant tous les avantages que cela emmène, que ce soit en terme d'organisation du code, mais aussi d'aide au développement prodiguée par les erreurs de compilation. Un coup de chapeau concernant le détail exhaustif des différentes possibilités qui existent quand on surcharge une méthode, et concernant le chapitre sur le gestion d'erreurs qui est un bijou de précision qui sont tout deux des bijoux de précision, allant vraiment au fond des choses.
  • Pour les développeurs Objet découvrant l'AS2, en plus de décrire précisément les différences avec des langages reconnus tels que Java, l'ouvrage s'attache à faire découvrir la philosophie de développement à aborder avec Flash, qui diffère de par son orientation clairement graphique. Pour ceux qui sont déjà à l'aise avec les Design Patterns, il s'agit aussi de voir de bonnes implémentations AS2, pour ainsi se plonger dans le langage.
  • Pour les développeurs AS2, qu'ils soient intermédiaires ou aguerris, il s'agit là d'une revue de détail, répondant la plupart du temps aux questions que l'on peut se poser sur quelques finesses du langage. Si l'on peut finir le livre en pensant ne pas avoir appris énormément par rapport à ce que l'on savait déjà, le simple fait de se remettre à programmer après cette lecture change la manière dont on voit le code. En gros, pour moi, j'ai vraiment l'impression que les qualités pédagogiques de l'auteur ont clarifié certaines notions qui m'étaient connues jusque là, mais peut-être un peu embrouillées ! :$

En conclusion, je dirais que Colin Moock nous offre un nouvel ouvrage de référence, qui saura satisfaire de par son contenu riche et détaillé tous les développeurs accomplis ou en devenir. Véritable fondation des connaissances à posséder en ActionScript 2.0, il s'avère la rampe de lancement idéale pour aller encore plus loin dans la Programmation Orientée Objet avec AS2.

Pour finir, je vous conseille de lire suite à ce livre celui sur les Design Patterns par le Gang Of Four, que j'ai moi-même lu sur les conseil de Francis BOURRE, et qui est d'ailleurs cités par Colin Moock dans la troisième partie de l'ouvrage. Il s'agit là d'une véritable mine d'or sur les DP.

mercredi, août 25 2004

StageManager 0.1

Pour continuer dans la série des 0.1, voici aujourd'hui une classe que je termine tout juste, servant à gérer le positionnement et la taille de clips dans des animations Flash plein écran. En effet, alors qu'il est maintenant possible de créer des site Flash occupant la totalité d'une fenêtre grâce à la classe Stage, trés peu de site l'utilisent ...

J'ai donc crée ce set de classe afin de faciliter la gestion des clips dans cette situation précise. On peut ainsi décider de la position d'un clip et de son alignement sur la scène, ainsi que sa taille. Il est ainsi possible de profiter presque de la même souplesse qu'offre HTML pour des applications qui pourraient ainsi occuper la totalité de la surface de l'animation.

Voici un exemple d'utilisation:import com.lalex.stage.StageManager;
import com.lalex.movieclip.SuperClip;
var stageMgr:StageManager = StageManager.getInstance();
// Alignement en haut à gauche, sans marge, de largeur 100%, hauteur inchangée
stageMgr.addElement(new SuperClip(_root.taskbar), {align:"left,top", margin:0, size:"100%,none"});
// Aligné à droite, avec une marge (à droite) de 10px
stageMgr.addElement(new SuperClip(_root.rightMenu), {align:"right", margin:10});
// Aligné en bas avec une marge (verticale) de 5% de la hauteur de l'anim
stageMgr.addElement(new SuperClip(_root.footer), {align:"bottom", margin:"none,5%"});

Bien qu'il manque encore des fonctionnalités ou des options de positionnement, StageManager est dors et déjà utilisable, et la classe SuperClip devrait donner naissance à une fonctionnalité similaire aux méthodes de positionnement de Stéphan Guénette.

L'utilisation de la composition dans SuperClip permet ainsi de gérer des clips dont le redimensionnement devrait se faire de manière spécifique, comme des composants par exemple. Il suffirait alors de créer une classe qui implémente l'interface IClip. Bref, en créant la classe appropriée, vous pouvez gérer virtuellement tout objet qui s'affiche à l'écran. 8)

::Télécharger StageManager.zip::

vendredi, août 20 2004

Propriétés virtuelles et méthodes

Dans un post précédent, on me demandait s'il n'était pas plus pratique de créer directement des propriétés virtuelles plutôt que des méthodes accesseurs et des propriétés virtuelles qui utilisent ces méthodes. Ma réponse est simple : NON !

C'est tout à fait flagrant dans le cadre de la problématique qui se pose à moi actuellement. Je désire créer une classe qui pourrait prendre en entrée un objet "affichable" qu'il est possible de positionner et de déplacer au moyen de méthodes prédéfinies. Je voudrais également que les composants v2 puissent être gérés par cette application.

Or, dans les composants v2, et plus particulièrement la classe UIObject, il est en effet possible de déplacer un composant et de le redimensionner respectivement au moyen des méthode move() et setSize() ... Par contre, le seul moyen de récupérer ses dimensions ou sa position est d'utiliser les propriétés virtuelles x, y, width, height ... Aucune méthode getX(), getY(), getWidth() ou getHeight() n'est au rendez-vous.

Il m'est donc impossible de créer une interface dont je puisse me servir pour le typage du paramètre de ma méthode, étant donné que les propriétés virtuelles ne peuvent être renseignées dans une interface ... et donc d'utiliser ces propriétés dans ma méthode ! :x A moins d'utiliser des hacks pour déjouer les erreurs du compilateur, mais les interfaces servant uniquement au moment de la compilation, ca n'aurait aucun sens ! 8|

Voici le code de Macromedia :/**
* width of object
* Read-Only:  use setSize() to change.
* @helpid 3982
*/

        function get width():Number
        {
                return _width;
        }
/**
* height of object
* Read-Only:  use setSize() to change.
* @helpid 3964
*/

        function get height():Number
        {
                return _height;
        }
/**
* x = left of object
* Read-Only:  use move() to change.
* @helpid 3983
*/

        function get x():Number
        {
                return _x;
        }
/**
* y = top of object
* Read-Only:  use move() to change.
* @helpid 3984
*/

        function get y():Number
        {
                return _y;
        }
Imaginez ensuite que le code ait été le suivant :/**
* width of object
* Read-Only:  use setSize() to change.
* @helpid 3982
*/

        function getWidth():Number
        {
                return _width;
        }
/**
* width of object
* Read-Only:  use setSize() to change.
* @helpid 3982
*/

        function get width():Number
        {
                return getWidth();
        }
// etc ... pour les autres propriétés

J'aurais alors pu créer une interface listant les méthodes setWidth(), setHeight(), etc... et ainsi utiliser mes classes "home-made" ou des composants. Les interfaces n'ont vraisemblablement pas été une préoccupation principale de Macromedia. D'ailleurs, on n'en trouve aucune dans les classes fournies avec Flash ! :o

jeudi, août 19 2004

SuperColor 0.3 : le contraste en plus

On vient de me faire remarquer que la dernière version du color_toolkit de Robert PENNER permet également de gérer le contraste d'un clip. Je me suis donc empressé de rajouter ces fonctionnalités à ma classe SuperColor qui passe pour l'occasion en version 0.3.

J'en ai également profité pour modifier le nom du package : en effet, avec un nom de domaine comme www.lalex.com, il est plus logique de garder com.lalex en nom de package ... même si le coté commercial ne me plait pas vraiment ! :o

/**
 * Super Color
 * extended Color class
 *
 * -----------------------------------
 *
 * Based on <a href="http://www.robertpenner.com/">Robert PENNER</a> Color Toolkit v1.3
 *
 * Properties
 *
 *   _brightness
 *   _brightOffset
 *   _contrast
 *   _negative
 *
 *   _rgb
 *   _rgbStr
 *   _red
 *   _green
 *   _blue
 *
 *   _redPercent
 *   _greenPercent
 *   _bluePercent
 *
 *   _redOffset
 *   _greenOffset
 *   _blueOffset
 *
 * Methods
 *
 *   getTarget()
 *
 *   setRGBStr()
 *   getRGBStr()
 *   setRGB2()
 *   getRGB2()
 *   reset()
 *
 *   setBrightness()
 *   getBrightness()
 *   setBrightOffset()
 *   getBrightOffset()
 *       setContrast()
 *   getContrast()
 *
 *   getNegative()
 *   setNegative()
 *   invert()
 *
 *   setTint()
 *   getTint()
 *   setTint2()
 *   getTint2()
 *   setTintOffset()
 *   getTintOffset()
 *
 *   setRed()
 *   getRed()
 *   setGreen()
 *   getGreen()
 *   setBlue()
 *   getBlue()
 *
 *   setRedPercent()
 *   getRedPercent()
 *   setGreenPercent()
 *   getGreenPercent()
 *   setBluePercent()
 *   getBluePercent()
 *
 *   setRedOffset()
 *   getRedOffset()
 *   setGreenOffset()
 *   getGreenOffset()
 *   setBlueOffset()
 *   getBlueOffset()
 *
 * @version 0.3
 * @author <a href="http://www.lalex.com/">LAlex</a>
 * @since 19/08/2004
 */

class com.lalex.movieclip.SuperColor extends Color {
        private var _targetMC:MovieClip;
        /**
         * Constructor
         * @param clip Clip to apply the color
         */

        function SuperColor(clip:MovieClip) {
                super(clip);
                _targetMC = clip;
        }
        /**
         * Returns affected clip
         * @return Targeted MovieClip
         */

        public function getTarget():MovieClip {
                return _targetMC;
        }
                // ----------o RGB


        /**
         * Set an RGB value from an hexadecimal string
         * @param hexStr Hexadecimal value string
         */

        public function setRGBStr(hexStr:String) {
                // grab the last six characters of the string
                hexStr = hexStr.substr (-6, 6);
                setRGB (parseInt (hexStr, 16));
        }
        /**
         * Get the RGB value as a string
         * @return Hexadecimal value string
         */

        public function getRGBStr():String {
                var hexStr:String = getRGB().toString(16);
                // fill in zeroes as needed
                var toFill:Number = 6 - hexStr.length;
                while (toFill--) hexStr = "0" + hexStr;
                return hexStr.toUpperCase();
        }
        /**
         * Set red, green, and blue with normal numbers
         * @param r Red value between 0 and 255
         * @param g Greeb value between 0 and 255
         * @param b Blue value between 0 and 255
         */

        public function setRGB2(r:Number, g:Number, b:Number) {
                setRGB (r << 16 | g << 8 | b);
        } // Branden Hall - <a href="http://www.figleaf.com">www.figleaf.com</a>
        /**
         * @return Object with r, g, and b properties
         */

        public function getRGB2():Object {
                var t = getTransform();
                return {r:t.rb, g:t.gb, b:t.bb};
        }
        /**
         * Reset the color object to normal
         */

        public function reset() : Void {
                setTransform ({ra:100, ga:100, ba:100, rb:0, gb:0, bb:0});
        }


                // ----------o Brightness


        /**     
         * Brighten just like Property Inspector of MovieClip
         * @param val Brightness between -100 and 100
         */

        public function setBrightness(val:Number) {
                var trans:Object = getTransform();
                with (trans) {
                        ra = ga = ba =  100 - Math.abs(val);
                        rb = gb = bb = (val > 0) ? val * (256/100) : 0;
                }
                setTransform(trans);
        }
        /**
         * @return Brightness set with setBrightness
         * @see setBrightness
         */

        public function getBrightness():Number {
                var trans:Object = getTransform();
                with (trans) {
                        return rb ? 100 - ra : ra - 100;
                }
        }
        /**
         * Set brightness offset
         * @param val Offset between -255 and 255
         */

        public function setBrightOffset(val:Number) {
                var trans:Object = getTransform();
                with (trans) {
                        rb = gb = bb = val;
                }
                setTransform(trans);
        }
        /**
         * @return Brightness set with setBrightOffset
         * @see setBrightOffset
         */

        public function getBrightOffset():Number {
                return getTransform().rb;
        }


                // ----------o Contrast
        /**
         * Set contrast
         * @param val Percent between -100 and 100
         */

        public function setContrast(val:Number) {
                var trans:Object = {};
                trans.ra = trans.ga = trans.ba = val;
                trans.rb = trans.gb = trans.bb = 128 - (128/100 * val);
                setTransform(trans);
        }
        /**
         * @return Contrast set with setContrast
         * @see setContrast
         */

        public function getContrast():Number {
            return getTransform().ra;
        }
                // ----------o Negative and invert

        /**
         * Produce a negative image of the normal appearance
         * @param percent Between 0 and 100
         */

        public function setNegative(percent:Number) {
            var t:Object = {};
            t.ra = t.ga = t.ba = 100 - 2 * percent;
            t.rb = t.gb = t.bb = percent * (255/100);
            setTransform (t);
        }
        /**
         * @return Negative percentage
         * @see setNegative
         */

        public function getNegative():Number {
            return getTransform().rb * (100/255);
        }
        /**
         * Invert the current color values
         */

        public function invert() {
                var trans:Object = getTransform();
                with (trans) {
                        ra = -ra;
                        ga = -ga;
                        ba = -ba;
                        rb = 255 - rb;
                        gb = 255 - gb;
                        bb = 255 - bb;
                }
                setTransform (trans);
        }


                // ----------o Tint


        /**
         * Tint with a color just like Property Inspector
         * @param r Red value between 0 and 255
         * @param g Greeb value between 0 and 255
         * @param b Blue value between 0 and 255
         * @param percent Between 0 and 100
         */

        public function setTint(r:Number, g:Number, b:Number, percent:Number) {
                var ratio = percent / 100;
                var trans = {rb:r*ratio, gb:g*ratio, bb:b*ratio};
                trans.ra = trans.ga = trans.ba = 100 - percent;
                setTransform (trans);
        }
        /**
         * @return tint object containing r, g, b, and percent properties
         * @see setTint
         */

        public function getTint():Object {
                var trans:Object = getTransform();
                var tint:Object = {percent: 100 - trans.ra};
                var ratio:Number = 100 / tint.percent;
                tint.r = trans.rb * ratio;
                tint.g = trans.gb * ratio;
                tint.b = trans.bb * ratio;
                return tint;
        }
        /**
         * tint with a color - alternate approach
         * @param rgb Color number between 0 and 0xFFFFFF
         * @param percent Between 0 and 100
         */

        public function setTint2(rgb:Number, percent:Number) {
                var r:Number = (rgb >> 16) ;
                var g:Number = (rgb >> <img src="http://common.lalex.com/themes/devblog/smilies/icon_cool.gif" alt="8)" class="smiley" /> & 0xFF;
                var b:Number = rgb & 0xFF;
                var ratio:Number = percent / 100;
                var trans:Object = {rb:r*ratio, gb:g*ratio, bb:b*ratio};
                trans.ra = trans.ga = trans.ba = 100 - percent;
                setTransform (trans);
        }
        /**
         * @return a tint object containing rgb (a 0xFFFFFF number) and percent properties
         * @see setTint2
         */

        public function getTint2():Object {
                var trans:Object = getTransform();
                var tint:Object = {percent: 100 - trans.ra};
                var ratio:Number = 100 / tint.percent;
                tint.rgb = (trans.rb*ratio)<<16 | (trans.gb*ratio)<<8 | trans.bb*ratio;
                return tint;
        }


                // ----------o Tint offset


        /**
         * @param r Red value between 0 and 255
         * @param g Greeb value between 0 and 255
         * @param b Blue value between 0 and 255
         */

        public function setTintOffset(r:Number, g:Number, b:Number) {
                var trans:Object = getTransform();
                with (trans) {
                        rb = r;
                        gb = g;
                        bb = b;
                }
                setTransform (trans);
        }
        /**
         * @return Object containing r, g, b properties
         * @see setTintOffset
         */

        public function getTintOffset():Object {
                var t:Object = getTransform();
                return {r:t.rb, g:t.gb, b:t.bb};
        }


                // ----------o Color values

        /**
         * Set red value
         * @param amount Between 0 and 255
         */

        public function setRed(amount:Number) {
                var t = getTransform();
                setRGB (amount << 16 | t.gb << 8 | t.bb);
        }
        /**
         * Get red value
         * @return Value between 0 and 255
         * @see setRed
         */

        public function getRed():Number {
                return getTransform().rb;
        }
        /**
         * Set green value
         * @param amount Between 0 and 255
         */

        public function setGreen(amount:Number) {
                var t = getTransform();
                setRGB (t.rb << 16 | amount << 8 | t.bb);
        }
        /**
         * Get green value
         * @return Value between 0 and 255
         * @see setGreen
         */

        public function getGreen():Number {
                return getTransform().gb;
        }
        /**
         * Set blue value
         * @param amount Between 0 and 255
         */

        public function setBlue(amount:Number) {
                var t = getTransform();
                setRGB (t.rb << 16 | t.gb << 8 | amount);
        }
        /**
         * Get blue value
         * @return Value between 0 and 255
         * @see setBlue
         */

        public function getBlue():Number {
                return getTransform().bb;
        }


                // ----------o Color percentages

        /**
         * Set red percentage
         * @param percent Between -100 and 100
         */

        public function setRedPercent(percent:Number) {
                var trans:Object = getTransform();
                trans.ra = percent;
                setTransform (trans);
        }
        /**
         * Get red percentage
         * @return Value between -100 and 100
         * @see setRedPercent
         */

        public function getRedPercent():Number {
                return getTransform().ra;
        }
        /**
         * Set green percentage
         * @param percent Between -100 and 100
         */

        public function setGreenPercent(percent:Number) {
                var trans:Object = getTransform();
                trans.ga = percent;
                setTransform (trans);
        }
        /**
         * Get green percentage
         * @return Value between -100 and 100
         * @see setGreenPercent
         */

        public function getGreenPercent():Number {
                return getTransform().ga;
        }
        /**
         * Set blue percentage
         * @param percent Between -100 and 100
         */

        public function setBluePercent(percent:Number) {
                var trans:Object = getTransform();
                trans.ba = percent;
                setTransform (trans);
        }
        /**
         * Get blue percentage
         * @return Value between -100 and 100
         * @see setBluePercent
         */

        public function getBluePercent():Number {
                return getTransform().ba;
        }


                // ----------o Color offsets

        /**
         * Set red offset
         * @param offset Between -255 and 255
         */

        public function setRedOffset(offset:Number) {
                var trans:Object = getTransform();
                trans.rb = offset;
                setTransform (trans);
        }
        /**
         * Get red offset
         * @return Value between -255 and 255
         * @see setRedOffset
         */

        public function getRedOffset():Number {
                return getTransform().rb;
        }
        /**
         * Set green offset
         * @param offset Between -255 and 255
         */

        public function setGreenOffset(offset:Number) {
                var trans:Object = getTransform();
                trans.gb = offset;
                setTransform (trans);
        }
        /**
         * Get green offset
         * @return Value between -255 and 255
         * @see setGreenOffset
         */

        public function getGreenOffset():Number {
                return getTransform().gb;
        }
        /**
         * Set blue offset
         * @param offset Between -255 and 255
         */

        public function setBlueOffset(offset:Number) {
                var trans:Object = getTransform();
                trans.bb = offset;
                setTransform (trans);
        }
        /**
         * Get blue offset
         * @return Value between -255 and 255
         * @see setBlueOffset
         */

        public function getBlueOffset():Number {
                return getTransform().bb;
        }

                // ----------o Getter/Setter

        /**
         * RGB value
         * @type Number
         */

        function set _rgb(val:Number) {
                setRGB(val);
        }
        function get _rgb():Number {
                return getRGB();
        }
        /**
         * RGB value
         * @type String
         */

        function set _rgbStr(val:String) {
                setRGBStr(val);
        }
        function get _rgbStr():String {
                return getRGBStr();
        }
        /**
         * Brightness value
         * @type Number
         */

        function set _brightness(b:Number) {
                setBrightness(b);
        }
        function get _brightness():Number {
                return getBrightness();
        }
        /**
         * Brightness offset
         * @type Number
         */

        function set _brightOffset (b:Number) {
                setBrightOffset(b);
        }
        public function get _brightOffset():Number {
                return getBrightOffset();
        }
        /**
         * Contrast
         * @type Number
         */

        function set _contrast (c:Number) {
                setContrast(c);
        }
        public function get _contrast():Number {
                return getContrast();
        }
        /**
         * Negative percentage
         * @type Number
         */

        public function set _negative(p:Number) {
                setNegative(p);
        }
        public function get _negative():Number {
                return getNegative();
        }
        /**
         * Red value
         * @type Number
         */

        public function set _red(v:Number) {
                setRed(v);
        }
        public function get _red():Number {
                return getRed();
        }
        /**
         * Green value
         * @type Number
         */

        public function set _green(v:Number) {
                setGreen(v);
        }
        public function get _green():Number {
                return getGreen();
        }
        /**
         * Blue value
         * @type Number
         */

        public function set _blue(v:Number) {
                setBlue(v);
        }
        public function get _blue():Number {
                return getBlue();
        }
        /**
         * Red percentage
         * @type Number
         */

        public function set _redPercent(v:Number) {
                setRedPercent(v);
        }
        public function get _redPercent():Number {
                return getRedPercent();
        }
        /**
         * Green percentage
         * @type Number
         */

        public function set _greenPercent(v:Number) {
                setGreenPercent(v);
        }
        public function get _greenPercent():Number {
                return getGreenPercent();
        }
        /**
         * Blue percentage
         * @type Number
         */

        public function set _bluePercent(v:Number) {
                setBluePercent(v);
        }
        public function get _bluePercent():Number {
                return getBluePercent();
        }
        /**
         * Red offset
         * @type Number
         */

        public function set _redOffset(v:Number) {
                setRedOffset(v);
        }
        public function get _redOffset():Number {
                return getRedOffset();
        }
        /**
         * Green offset
         * @type Number
         */

        public function set _greenOffset(v:Number) {
                setGreenOffset(v);
        }
        public function get _greenOffset():Number {
                return getGreenOffset();
        }
        /**
         * Blue offset
         * @type Number
         */

        public function set _blueOffset(v:Number) {
                setBlueOffset(v);
        }
  &nbs