'Limon' est un framework MVC développé en ActionScript 3.0 et conçu pour la mise en place d'architectures d'applications Flash Based avec support de l'API 3D Molehill.

Flash

AIR

Molehill support

L'implémentation du pattern MVC est particulière car le controleur est remplacé par un système de commandes qui délèguent le travail à des macro-commandes et renvoient les informations aux vues ou aux modèles, le tout étant automatisé grâce à un système de surcharge.
Les envois de commandes et d'évènements sont injectés dans les objets qui constituent la triade MVC et le simple fait de surcharger les méthodes permet la réaction à ces interactions.
La surcharge est obligatoire puisque tous les éléments MVC de bas niveaux sont abstraits.

Le principe de ce framework est d'implémenter dans un Context des micro-MVC appelés Component.
Ces composants sont indépendants mais peuvent communiquer et réagir entre eux grâce à des évènements diffusés à partir du contexte (important !).

Le Context définit la couche basse de l'application, écoute les évènements nécessaires du Stage et permet l'ajout de composants, de calques 3D ou vidéos.

Pour ce qui est de l'état général de l'application, le Context remplacera le Stage car il se chargera d'écouter les informations de ce dernier afin de les traiter à sa manière et de diffuser entre autres des évènements comme :
- le redimensionnement dynamique de la fenêtre de l'application
- l'activation et la désactivation du focus de l'application
- les interactions avec les périphériques externes (clavier, souris...)
- la gestion des erreurs au cours de l'exécution
- la création et la destruction du contexte
- l'ajout et la destruction de composants
- l'ajout et la gestion des couches 3d et vidéos natives
- le rendu en temps réel
- l'accès aux informations concernant le player
Toutes ces informations seront traitées et diffusées sous forme d'évènements personnalisés tels que : ContextEvent, ContextDisplayEvent, ContextErrorEvent, ModelEvent, InputsEvent, RenderEngineEvent, Layer3DEvent, LayerVideoEvent...

Le Context impose des méthodes pour gérer les composants, sans avoir besoin de créer les instances au préalable, il faut simplement passer en paramètres les différentes classes et le Context se charge de créer les instances et les dépendances.

Lors de la création d'un composant, ce dernier doit obligatoirement être associé à une commande de type AbstractCommand et à un modèle de type AbstractModel. La vue est facultative car un composant MVC peut dans certains cas ne pas utiliser d'éléments visuels.

La commande reçoit les informations d'exécution mais délègue le travail à des macro-commandes de type AbstractMacroCommand, il est donc pour cela nécessaire d'enregistrer ces macros dans la commande en utilisant la méthode registerMacro().
Pour exécuter une commande, cela se fait grâce au Component en utilisant la méthode dispatchCommand() et en ciblant la commande avec son identifiant en passant un évènement en paramètre. L'injection se chargera ensuite d'exécuter la bonne macro-commande en invoquant la méthode execute() dans la macro-commande ciblée.

Concernant les vues, la classe Component étend la classe ViewMediator qui permet la gestion des vues en ajoutant des AbstractView.
Chaque Component possède son propre dispatcher d'évènements, permettant ainsi de l'utiliser si besoin entre les éléments MVC au sein du composant.
Egalement, dans une vue les éléments visuels doivent être ajoutés sur la propriété viewContainer, qui est tout simplement un objet Sprite crée lors de l'instanciation de la vue par le ViewMediator.

Pour mettre à jour la vue, cela se fait en appelant la méthode update() située dans le modèle. Cette méthode peut évidemment être appelée depuis le modèle lui-même ou depuis une commande puisque celle-ci a une référence au modèle.
Cette méthode update() contient plusieurs paramètres :
- updateType : une clé permettant de différencier les types de mises à jour
- data : object implémentant IViewData qui contiendra les nouvelles données à passer à la vue.
- viewID : (optionnel) spécifie la vue du composant à mettre à jour, si null, toutes les vues seront mises à jour.
- isViewSetup : (optionnel) indique si la vue à mettre à jour doit être à l'état 'setup', vrai par défaut.
Ensuite, le framework invoquera la méthode update() dans la ou les vues concernées et lui passera les paramètres passées dans le modèle, à savoir updateType et data.

Ce framework permet également d'implémenter des couches 3D et vidéos basées respectivement sur Stage3D et StageVideo.
Il suffit simplement de créer ses propres classes qui étendent Layer3D et LayerVideo. Pour ces deux types de classes, le Context se charge d'instancier des objets natifs Stage3D et StageVideo et de leur attribuer un index disponible tout en respectant l'ordre de la pile et la disponibilité des couches (4 chacunes au maximum). La surcharge de méthode est également possible pour ces deux couches.
La classe Layer3D est associé à une couche Stage3D et se charge de créer le Context3D. Elle contient également des informations concernant les possibilités de rendu 3D sur la machine affichant le lecteur. La méthode attachTemplate() permet d'ajouter un template de moteur 3D que vous avez crée, cette classe doit étendre AbstractEngineTemplate.
La classe LayerVideo est quand à elle associée à une couche StageVideo et contient également des informations sur les possibilités d'affichages vidéos sur la machine affichant le lecteur. Cette couche implémente des méthodes permettant de contrôler des flux vidéos comme play(stream:String), pause(), stop(), resume(), seekOffset(offset:Number), setVolume(value:Number)... des évènements sont envoyés lors d'une lecture en cours ainsi que sur les différentes actions disponibles. Lors de la lecture d'un flux, il est possible d'avoir accès aux métadonnées de la vidéo dans un objet LayerVideoMetaData ainsi qu'à des informations comme la durée de lecture jouée, le pourcentage d'avancement, de chargement, de buffering...

Le Context donne également accès à un RenderEngine basé sur l'évènement Event.EnterFrame. Il calcul en temps réel le framerate, la mémoire consommée, le temps écoulé et envoi des évènements lors d'actions sur son lancement, son arrêt et son rafraichissement.
Il est accessible depuis le Context via un accesseur et contrôlable de cette manière : this.renderEngine.start().
Il suffit ensuite d'écouter RenderEngineEvent.ON_RENDER pour pouvoir rafraîchir des scènes en temps réel.
Un accesseur heartbeatFunction permet de passer en paramètre une méthode qui sera automatiquement invoquée toutes les secondes.

Tous ces éléments contiennent des méthodes communes, notamment de construction et de destruction qui doivent obligatoirement être surchargées afin de garantir un cycle de vie optimal pour l'application.

Des utilitaires tels qu'un chargeur de ressources, une console de log et des opérations sur les objets Array, Math, Object, RegExp, String sont également disponibles dans le framework.

Création du contexte depuis la classe Main.

                    private function setupApplication():void {
                      _application = new MyApplication();
                      
                      _application.addEventListener(ContextEvent.CONTEXT_SETUP, handleApplication, false, 0, true);
                      _application.addEventListener(ContextEvent.CONTEXT_SETUP, handleApplication, false, 0, true);
                      
                      _application.contextView = this;			// REQUIRED !
                      _application.setup();						// REQUIRED !
                    }
                

Exemple de classe : la classe MyApplication avec les méthodes nécessaires.

                  package artcustomer.com.citruslimon.api {
                    import artcustomer.framework.context.*;
                    import artcustomer.framework.core.*;
                    import artcustomer.framework.events.*;
                    
                    
                    public class MyApplication extends FlashContext {
                      
                      
                      public function MyApplication() {
                        super();
                      }
                      
                      
                      /**
                       * Setup instance. Set params before call this method.
                       */
                      override public function setup():void {
                        this.name = 'My Application';
                        this.mode = ContextMode.DEBUG;
						
                        super.setup();
                      }
                      
                      /**
                       * Destroy instance.
                       */
                      override public function destroy():void {
                        super.destroy();
                      }
                    }
                  }
                

Ajout d'un composant.

                  override public function setup():void {
                    super.setup();                    

                    this.addComponent(MyComponent, MyModel, MyCommand);
                  }
                

Ajout de couches 3D et Videos.

                  override public function setup():void {
                    super.setup();
                    
                    this.addLayer3D(AppLayer3D);
                    this.addLayerVideo(AppLayerVideo);
                  }
                

Méthodes surchargées contenues dans la classe d'un composant.

                /**
                 * Entry point of the component.
                 */
                override public function build():void {
                  super.build();
                }

                /**
                 * End point of the component.
                 */
                override public function destroy():void {
                  super.destroy();
                }

                /**
                 * Resize component.
                 */
                override public function resize():void {
                  
                }
                

Ajout d'une vue depuis un composant.

                override public function build():void {
                    super.build();
                    super.add();
                    
                    this.registerView(MyView, 'myView', true, true);
                }
                

Enregistrement d'une macro-commande depuis une commande.

                override public function setup():void {
                  super.setup();
                  
                  this.registerMacro(MyMacroCommand);
                }
                

Diffusion d'une commande depuis une vue, avec un évènement personnalisé en paramètre.

                private function dispatchCommand():void {
                  this.component.context.instance.dispatchCommand(new MyEvent(MyEvent.TYPE), 'myMacroCommand');
                }
                

Exemples d'implémentations du framework Limon.

N'oubliez pas d'ajouter aux projets le code source du framework, le code source des extensions ainsi que celui de la librairie si besoin.

Hello World
Starling
Alternativa3D
Away3D
Minko

Consultez l'AsDoc en ligne.
Téléchargez le package d'extensions.
Téléchargez le package Flash de Limon version 3.0.0.0.
Téléchargez le package AIR de Limon version 3.1.8.1.
Accéder au repository de Limon sur Github.