Qu'appelle-t'on une opération? C'est l'emploi d'un outil de dessin. Par exemple, le tracé libre à la main d'un pinceau (ou d'une brosse) est une opération. Plus exactement, c'est tout comportement de la souris lorsqu'elle se trouve sur les pixels de l'image éditée. De ce fait, la gestion de la pipette se fait également au travers des opérations.
Le moteur chargé de gérer ces opérations est simplifié autant que possible. Son principe est le suivant : lorsque la souris est au-dessus de l'image, la boucle principale de gestion de GrafX2 (située dans MOTEUR.C) détermine la partie atomique d'instructions à exécuter, puis l'exécute, pour chaque combinaison d'un type d'opération (un entier, que l'on nommera pour les besoins de cette page ID_OP), d'un état de la souris (état de ses boutons plus exactement, codé sur un entier également), et d'un nombre de valeurs présentes dans une pile (pas la pile système, mais une pile de mots 16-bits spécialement mise en place pour les opérations, afin qu'elles y stockent des paramètres pour les opérations suivantes). On appelle "partie atomique" une séquence d'instructions qui doivent être exécutées intégralement à chaque itération de la boucle principale. Elle se contente de ne faire que ce qu'elle doit faire face à la situation qu'implique la combinaison (ID_OP,Code souris, Etat pile) pour laquelle elle est appelée.
En fait, le moteur doit être aidé pour déterminer les insctructions à exécuter. Chacune de ces parties atomiques est écrite sous la forme d'une fonction contenant tout le code qui lui est nécessaire. Ces fonctions sont ce que l'on a appelé des "fonction_action" (définition dans STRUCT.H), c'est à dire une simple fonction qui ne reçoit pas de paramètres et qui n'en renvoie pas. Un simple void Ma_fonction(void)...
Il n'est pas dans mon intention de vous apprendre à écrire ces fonctions atomiques. Dans le cas des opérations les plus simples à implémenter selon ce principe, la conception des parties atomiques est assez intuitive, mais il arrive dans certains cas que la méthode trouve certaines limites, il faut alors tricher un peu (mais gentiment! - en plaçant des valeurs arbitraires dans la pile uniquement pour permettre la transition vers une autre combinaison choisie, donc une autre partie atomique, par exemple). Vous pourrez trouver tous les exemples que vous voudrez dans le fichier OPERATIO.C.
Après avoir écrit les parties atomiques qui vont être nécessaires pour la gestion complète d'une opération (dans le fichier OPERATIO.C), et avoir renseigné les prototypes de ces fonctions (dans OPERATIO.H), il faut indiquer au moteur dans quelles conditions utiliser ces fonctions. Cela se fait dans la phase d'initialisation du programme (située dans le fichier INIT.C), où l'on renseigne chacune des fonctions atomiques, en décrivant les valeurs de combinaison qui doivent déclencher leur appel. La fonction appelée se contente d'en prendre note en remplissant un tableau nommé "Operation" (variable globale déclarée dans GLOBAL.H, et indexée par les 3 valeurs de la combinaison : ID_OP, code souris, état pile) à l'aide de l'adresse de la fonction à appeler. Ce tableau va servir au moteur à faire un appel direct de la fonction atomique d'après la combinaison, sans avoir à faire toute une série de tests (swich/case) fastidieux.
Comme nous avons pressenti qu'il arriverait fréquemment que des fonctions atomiques auraient besoin systématiquement d'effacer la souris pour faire des affichages à l'écran ou dans l'image, et de la rafficher ensuite, et dans le souci d'éviter de faire abusivement du copier/coller de code, nous avons rajouté un booléen dans le tableau Operation qui permet d'indiquer que la fonction atomique demande au moteur de se charger lui-même de l'effacement et de la restauration du curseur de la souris à l'écran. Finalement, je ne suis pas certain que cela s'est révelé d'une grande utilité, mais je vous le signale tout de même pour que vous compreniez l'existance du paramètre "Effacer souris" qu'il faut indiquer lorsqu'on renseigne une fonction atomique lors de l'initialisation.
Il est important de noter qu'une fonction atomique est appelée en permanence par la boucle principale, indépendamment du fait que la souris change d'état ou non. Ces appels répétés permettent par exemple d'avoir un spray qui continue à agir lorsqu'on presse le bouton de la souris sans la déplacer.
De plus, les fonctions atomiques n'ont pas à se soucier du positionnement de la souris car dès que la pile contient des données (généralement dès le premier clic), la souris est limitée par le moteur afin de ne pas sortir de l'image. Le moteur s'assure également que la souris ne franchis pas la barre de split en mode "loupe". Enfin, n'oubliez pas de vider complètement la pile en temps voulu, lorsque l'opération peut s'achever! ;-)
Initialisation_operation(ID_OP, Etat souris, Taille pile, Callback, Effacer souris);
Comment rajouter une opération?
Dans CONST.H :
|
Dans GLOBAL.H :
|
Dans OPERATIO.C :
|
Dans OPERATIO.H :
|
Dans INIT.C :
|