Advertisement
ISSOtm

Aevilia - Système de menus

Jul 21st, 2016
129
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.27 KB | None | 0 0
  1. AEVILIA
  2. Description du système de menus
  3. Version 0.0.2
  4.  
  5. Démo technique : https://dl.dropboxusercontent.com/u/54952583/Aevilia_0.0.1.tar.gz
  6. (Attention : compilée pour Linux)
  7.  
  8.  
  9. Le système de menus a été construit pour être simple à utiliser, sans que l'implémentation relève du kamoulox.
  10. Premier aspect : le chaînage des menus. Chaque menu est défini par la structure suivante :
  11. typedef struct Menu Menu;
  12. struct Menu {
  13. PosPixel positionVert;
  14. PosPixel positionHoriz;
  15. unsigned int tailleVert;
  16. unsigned int tailleHoriz;
  17. unsigned char texte[256];
  18. Commande* commande; // Commande à exécuter.
  19. Commande* prochaineCommande; // Pour se souvenir de quelle est la commande actuelle.
  20. Menu* prochainMenu; // Le prochain menu à rendre. Peut ne pas être initialisé à NULL, mais alors doit pointer vers une structure Menu.
  21. };
  22. Les champs positionVert et positionHoriz définissent les coordonnées - en pixels - du coin haut-gauche du menu.
  23. Les champs tailleVert et tailleHoriz définissent les dimensions - en tiles - du menu. Je n'ai jamais essayé de rendre ces valeurs nulles, mais ça me semble une mauvaise idée.
  24. Ces quatre champs permettent de rendre la structure de base du menu (à savoir son contour, plus de rendre l'intérieur du contour blanc). Ce travail est effectué par la fonction void rendreMenu(Menu* menu).
  25. Le champ suivant est une chaîne de caractères affichée par le menu. Puisque le menu est réaffiché à chaque frame, il n'est pas possible à un module externe d'afficher une chaîne de caractères : elle serait détruite à la frame suivante.
  26. Le champ prochainMenu est ce qui permet le chaînage des menus. Voici la fonction de gestion des menus :
  27. void activerMenus(void) {
  28. Menu* pointeur = menuArendre;
  29. if(pointeur == NULL) {
  30. return;
  31. }
  32. rendreMenu(pointeur);
  33. while(pointeur->prochainMenu != NULL) {
  34. pointeur = pointeur->prochainMenu;
  35. rendreMenu(pointeur);
  36. }
  37. (...)
  38. }
  39. Ce qu'il y a entre les parenthèses concerne la gestion des Commandes. Nous verrons cela plus tard.
  40. menuArendre est une variable globale (vous aurez deviné qu'elle est de type Menu*), qui sert de point de départ au chaînage des menus.
  41. La fonction recherche d'abord si il existe au moins un menu, sinon elle quitte tout de suite.
  42. Ensuite, elle effectue le rendu de ce menu, puis tant qu'il existe un menu suivant, elle passe au suivant, puis l'affiche.
  43. On notera qu'à la sortie de la boucle, pointeur pointe vers le dernier menu de la chaîne.
  44.  
  45. Voici ce qui était caché par les parenthèses :
  46. void activerMenus(void) {
  47. (...)
  48. Commande* cmd = pointeur->prochaineCommande;
  49.  
  50. if(cmd != NULL) {
  51. // On exécute la commande du menu.
  52. if(commandes[cmd->commande](cmd) == 0) {
  53. // La fonction indique qu'elle a terminé. On passe à la commande suivante.
  54. pointeur->prochaineCommande = cmd->suivante;
  55. }
  56. } else {
  57. // Il n'y a plus de commandes à exécuter.
  58. pointeur->prochaineCommande = pointeur->commande;
  59. retirerMenu();
  60. }
  61. }
  62. Ce morceau de la fonction quitte la partie graphique, et s'occupe du traitement des commandes du menu.
  63. Nous devons d'abord nous intéresser à la structure Commande :
  64. // Une commande envoyée au moteur textuel.
  65. typedef struct Commande Commande;
  66. struct Commande {
  67. IDCommande commande; // Indique quelle commande doit être exécutée, par sa clé.
  68.  
  69. // Arguments à la commande.
  70. void* pointeur;
  71. void* pointeur2;
  72.  
  73. unsigned int compteur;
  74. unsigned int compteur2;
  75.  
  76. unsigned int (*fonction)();
  77.  
  78. Commande* suivante; // Pointe vers la prochaine commande à exécuter. NULL signifie "fin".
  79. };
  80. IDCommande est une enum, donnée ci-dessous. La structure Commande devant servir à différentes opérations, ses champs sont très génériques. Pour vous en donner une idée, voici
  81. Voici la définition de l'enum IDCommande :
  82. typedef enum {
  83. #define CMD_CHAINE(chaine, suivante) {CHAINE, chaine, NULL, 0, 0, NULL, suivante}
  84. CHAINE, // Afficher une chaîne.
  85.  
  86. #define CMD_ATTENDRE(attente, suivante) {ATTENDRE, NULL, NULL, attente, 0, NULL, suivante}
  87. ATTENDRE, // Attendre un certain nombre de frames.
  88.  
  89. #define CMD_FONCTION(fonction, suivante) {FONCTION, NULL, NULL, 0, 0, fonction, suivante}
  90. FONCTION, // Écrire un octet en mémoire.
  91.  
  92. #define CMD_SAUTER_COND(condition, branche, suivante) {SAUTER, branche, suivante, 0, 0, condition, NULL}
  93. #define CMD_SAUTER(branche) CMD_SAUTER_COND(NULL, branche, NULL)
  94. SAUTER, // Continuer la lecture autre part.
  95.  
  96. #define CMD_APPELER_COND(condition, branche, suivante) {APPELER, branche, branche, 0, 0, condition, suivante}
  97. #define CMD_APPELER(branche, suivante) CMD_APPELER_COND(NULL, branche, suivante)
  98. APPELER, // Appeler d'autres commandes (comme le fait SAUTER) puis revenir ici.
  99.  
  100. #define CMD_AJOUTER_MENU(menu, suivante) {AJOUTER_MENU, menu, NULL, 0, 0, NULL, suivante}
  101. AJOUTER_MENU // Ajouter un autre menu par-dessus celui-ci.
  102. } IDCommande;
  103. A chaque commande est associée une macro, qui permet de définir plus clairement une commande en fonction de l'action qu'elle va réaliser.
  104.  
  105. Et voici un exemple de menu :
  106. unsigned char chaineTest[] = {2, 2, 3, 4, 5, 6, BLANC, '\0'};
  107. Commande commandeTest5 = CMD_ATTENDRE(180, NULL);
  108. Commande commandeTest4 = CMD_SAUTER(&commandeTest5);
  109. Commande commandeTest3 = CMD_CHAINE(chaineTest, &commandeTest4);
  110. Commande commandeTest2 = CMD_ATTENDRE(180, &commandeTest3);
  111. Commande commandeTest1 = CMD_CHAINE(chaineTest + sizeof(char), &commandeTest2);
  112. Menu menuTest = MENU(7, 50, 5, 5, &commandeTest1);
  113.  
  114. Ce menu affiche une chaîne de caractères, attend 180 frames, affiche une autre chaîne de caractères, attend 180 frames, et se ferme.
  115.  
  116.  
  117.  
  118. Fonctionnement individuel de chaque type de Commande
  119.  
  120. CMD_CHAINE
  121. Ajoute (en fait, liste de tiles) à la chaîne du dernier menu ouvert. Copie jusqu'au prochain '\0', sans vérification de longueur. Aucun métacaratère, aucun délai. Ne sera affichée qu'à la frame suivante.
  122.  
  123. CMD_ATTENDRE
  124. Ne fait rien pendant attente frames.
  125.  
  126. CMD_FONCTION
  127. Appelle la fonction fonction passée en argument.
  128.  
  129. CMD_SAUTER_COND
  130. Exécute la fonction condition. Si elle renvoie une valeur nulle, aller à suivante. Sinon, aller à branche. NULL n'est jamais exécuté, et "renvoie" toujours un.
  131. CMD_SAUTER
  132. Va à branche. Quasi-équivalent à CMD_ATTENDRE(1, branche), mais probablement plus lent.
  133.  
  134. CMD_APPELER_COND
  135. Exécute la fonction condition (sauf si elle vaut NULL), et si elle renvoie une valeur non-nulle (c'est toujours le cas pour NULL), exécute la Commande branche puis les suivantes jusqu'à tomber sur un NULL, puis continue l'exécution à la Commande suivante.
  136. En pratique, exécute le script de la fonction branche, puis de chacune des suivantes, et déclare avoir terminé lorsqu'elle trouve un NULL.
  137. Les appels récursifs sont prohibés, car ils causent des erreurs sur les appels de niveau non-maximal. tl;dr : ça fait buguer.
  138. CMD_APPELER
  139. Même effet que CMD_APPELER_COND, mais exécute branche et le reste sans condition.
  140.  
  141. CMD_AJOUTER_MENU
  142. Ajoute le menu menu par-dessus le dernier. Son script démarrera à la frame suivante.
  143. NB : le script du menu courant est "mis en pause" (simplement, il cesse d'être exécuté) en attendant. Notez quand même que l'exécution du script du nouveau menu peut causer des appels récursifs.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement