Création de fonctions de callback.

ODFAEG possède une classe similaire à std::function, cette classe est capable de pouvoir stocker n'importe
quel type de pointeur sur fonction et de paramètre dans le but d'appeler la fonction plus tard.
Contrairement à std::function et à std::bind, la classe odfaeg::core::FastDelegate n'attend que le type
de retour de la fonction en paramètre template, ceci permet de pouvoir faire des tableaux de foncteurs
retournant un même type d'objet.
En général il existe deux type de foncteurs dans les frameworks pouvant créer leur propre type d'événements :
Les slots : ce sont des foncteurs ne retournant rien, il ne font que d'appeler un foncteur lorsqu'un événement
est déclenché.
Les signaux : ceux-ci retournent un booléen qui indique si un signal a été émis ou pas, et si le signal a été émis
alors le slot est appelé.
C'est le cas par exemple de la librairie QT mais celles-ci nécessite de faire appel à un générteur externe afin de
générer des fichiers .moc, avec ODFAEG, tout ce fait à la compilation, il n'y a donc pas besoin de générer de .moc!

Pour créer un slot ou un signal avec ODFAEG il suffit de définir un objet de type odfaeg::core::FastDelegate
et de lui fournir en paramètre template le type de retour du foncteur, voici un example de code source qui permet
de créer, différent foncteurs à l'aide de la classe odfaeg::core::FastDelegate!


          #include
          #include
          #include 
          #include 
          #include "odfaeg/Core/fastDelegate.h"
          #include "odfaeg/Core/serialization.impl"
          using namespace std::literals;
          using namespace std::placeholders;
           
          void foo(int i, int j)
          { std::cout << i << j; }
           
          struct A {
              A() {
                  var = 10;
              }
                  void foo(int i)
                  { std::cout << i; }
                  template 
                  void serialize (A & ar) {
                  ar(var);
                  }
                  int var;
          };
           
          struct B {
              B() {
                  c = "serialize base";
              }
                  virtual void foo()
                  { std::cout << 1; }
                  virtual void print() {
                  std::cout< f1(f, 3, 4);
              f1.setParams(5, 6);
                  f1();
                  std::cout << std::endl;
           
                  odfaeg::FastDelegate f2(
                          [](int i, int j){ std::cout << i << j; },
                          7,8
                  );
                  f2();
                  f2.setParams(9,10);
                  f2();
                  std::cout << std::endl;
           
                  int i = 11;
                  odfaeg::FastDelegate f3(
                          [i](int j){ std::cout << i << j; },
                          12
                  );
                  f3();
                  f3.setParams(13);
                  f3();
                  std::cout << std::endl;
           
                  A a;
                  odfaeg::FastDelegate f4(&A::foo,&a,14);
                  f4();
                  f4.setParams(&a,15);
                  f4();
                  std::cout << std::endl;
                  odfaeg::FastDelegate f5 = f1;
                  f5();
                  f5=f3;
                  f5();
                  std::cout << std::endl;
           
                  C c;
                  B* b = &c;
                  odfaeg::FastDelegate f6(&C::foo,&c);
                  f6();
                  f6.setParams(b);
                  f6();
                  std::cout << std::endl;
           
                  odfaeg::FastDelegate f7(D(),16);
                  f7();
                  f7.setParams(17);
                  f7();
                  std::cout << std::endl;
           
                  odfaeg::FastDelegate f8(bar,"ab"s);
                  f8();
                  f8.setParams("abc"s);
                  f8();
                  std::cout << std::endl;
                  int pi = 1;
              odfaeg::FastDelegate f9(foo, &pi);
                  f9();
                  std::cout << std::endl;
                  pi=2;
                  f9();
                  std::cout << std::endl;
                  odfaeg::FastDelegate f10(goo,18);
                  std::cout << f10();
                  f10.setParams(19);
                  std::cout << f10();
                  std::cout << std::endl;
                  void(*fu)(int&) = &foo;
                  int vi=1;
                  odfaeg::FastDelegate f11(fu, std::ref(vi));
                  f11();
                  std::cout << std::endl;
                  vi=2;
                  f11();
                  std::cout<

ODFAEG permet également l'utilisation de placeholders pour les slot et les signaux.


          void f (int i, int j, int l) {
              std::cout<<"i : "< fd(&f, 1, 2, odfaeg::ph<0,int>()) ;
          	fd.bind(3);
          	fd() ;
          }
        

Création des commandes et des actions.

Création d'actions.

Les foncteurs de ODFAEG sont très pratique pour créer ses propres type de signaux et de slots, malheureusement, ils
ne permettent pas d'appeler un slots lorsque un ou plusieurs événements système (événements SFML) sont déclenchés.
Heureusement ODFAEG possède également une classe permettant de créer ses propres événements utilisateurs à partir
d'événements système!
Cette classe s'appelle odfaeg::core::Action!
Voici par exemple comment créer une action qui va se déclencher lorsque l'une ou plusieurs de ses quatre touches (Z, Q, S, D)
est enfoncée :


            Action a1 (Action::EVENT_TYPE::KEY_HELD_DOWN, sf::Keyboard::Key::Z);
            Action a2 (Action::EVENT_TYPE::KEY_HELD_DOWN, sf::Keyboard::Key::Q);
            Action a3 (Action::EVENT_TYPE::KEY_HELD_DOWN, sf::Keyboard::Key::S);
            Action a4 (Action::EVENT_TYPE::KEY_HELD_DOWN, sf::Keyboard::Key::D);
            Action combined (a1 || a2 || a3 || a4);
          

Comme pour les conditions, ou peut combiner plusieurs actions à l'aide des opérateurs logiques ||, |, && et !.
La sémantique est la même que pour les conditions c'est à dire que l'événement utilisateur sera déclenché si
l'une des quatre touche ou plusieurs seront enfoncées.
Pour les touches et le boutons il y a 3 types dévénements :
KEY/BUTTON_HELD_DOWN signifie que l'action sera déclenchée tant que la touche ou le bouton restera enfoncé.
KEY/BUTTON_PRESSED_ONCE signifie que l'action sera déclenchée lorsque l'on appuira sur la touche ou le bouton.
KEY_BUTTON_RELEASE signifie que l'action sera déclenchée lorsque l'on relâchera la touche ou le bouton.

Voila maintenant vous savez comment définir des signaux, des slots ainsi que des actions.
Maintenant il va falloir indiquer quel slot appeler lorsque une action et/ou un signal est/sont déclenché(s).

Création des commandes

Pour ce faire il faut créer un objet de type odfaeg::core::Command, cette classe possède trois constructeurs :
Le premier permet de lier une action à un slot, le second permet de lier un signal à un slot, et le dernier permet
de lier une action et un signal à un slot. (un exemple)
Command moveCommand(combined, FastDelegate(&MyAppli::keyHeldDown, this, sf::Keyboard::Key::Unknown, realTime.restart()));
Ici par exemple, la fonction keyHeldDown de la classe MyAppli sera appelée lorsque l'une ou plusieurs des quatre touches
(A, Z, S, D) sera enfoncée.

Evidemment comme tout foncteur il faut lui passer des paramètres : this qui est le pointeur sur l'application courante,
pour la touche je mets sf::Keyboard::Unknown car aucune touche ne peut être traitée lors de la création de la commande.
Et le dernier paramètre est juste le temps écoulé depuis le dernier appel à la méthode exec.

Voici un autre exemple qui va exécuter la commande si la souris se trouve dans une zone particulière de la fenêtre.
Command mouseInsideCommand(FastDelegate(&MyAppli::mouseInside,this,Vector2f(-1, -1)),
FastDelegate(&MyAppli::onMouseInside, this, Vector2f(-1,-1)));
Et une dernière qui va appeler la fonction onMouseInside si l'on a cliqué dans la zone avec le bouton
gauche de la souris :


          Action action(Action::EVENT_TYPE::MOUSE_PRESSED_ONCE,sf::Mouse::Left);
          Command mouseInsideLeftPressedCommand(action,FastDelegate(&MyAppli::mouseInside,this,Vector2f(-1, -1)), FastDelegate(&MyAppli::onMouseInside, this, Vector2f(-1,-1)));
          

Connexion et changement des paramètres.

Maintenant il ne reste plus qu'à connecter la commande au gestionnaire d'événements, le gestionnaire d'événement
va vérifier à chaque tour si une commande n'a pas été déclenchée, et si oui, il va exécuter la commande en lui passant
la valeur des paramètres que l'on a défini lors de la création de la commande.
Chaque application possède donc un gestionnaire d'événement, pour le récupérer il suffit d'appeler la méthode getListener()
de la classe odfaeg::core::Application.
Chaque commande est référencée par un nom (de type std::string) qui est le nom de la connexion.
getListener().connect(«mouseInsideCommand»,mouseInsideCommand);

Il serait bien de pouvoir changer la valeur des paramètres des slots et des signaux à chaque tour de boucle,
pour que la fonction reçoive la bonne position de la souris à chaque tour de boucle.
Les méthodes setCommandSlotParams et setCommandSigParams permettent de faire cela, dans le cas de placeholders,
les méthodes s'appellent bindCommandSlotParams et bindCommandSigParams.
Un exemple :
getListener().setCommandSigParams("MouseInside", this, mousePos);
Dans le cas des actions combinées, le slot ne sera appelé qu'une seule fois par tout de boucle, si vous voulez
appelé le slot plusieurs fois si plusieurs touche sont enfoncée alors il faudra créer une commande par touche.

Voilà maintenant vous savez comment créer n'importe quel type d'événement avec ODFAEG.