Obligement - L'Amiga au maximum

Vendredi 21 juin 2019 - 01:49  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

 · Accueil
 · A Propos
 · Articles
 · Galeries
 · Glossaire
 · Liens
 · Liste jeux Amiga
 · Quizz
 · Téléchargements
 · Trucs et astuces


Articles

 · Actualité (récente)
 · Actualité (archive)
 · Comparatifs
 · Dossiers
 · Entrevues
 · Matériel (tests)
 · Matériel (bidouilles)
 · Points de vue
 · En pratique
 · Programmation
 · Reportages
 · Tests de jeux
 · Tests de logiciels
 · Tests de compilations
 · Articles divers

 · Articles in english
 · Articles en d'autres langues


Twitter

Suivez-nous sur Twitter




Liens

 · Sites de téléchargements
 · Associations
 · Pages Personnelles
 · Matériel
 · Réparateurs
 · Revendeurs
 · Presse et médias
 · Programmation
 · Logiciels
 · Jeux
 · Scène démo
 · Divers


Jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Partenaires

Annuaire Amiga

Amedia Computer

Relec

Hit Parade


Contact

David Brunet

Courriel

 


Programmation : C - Les menus déroulants
(Article écrit par Pascal Amiable et extrait d'Amiga News Tech - juillet 1991)


La création de menus déroulants sur Amiga s'effectue, comme bien d'autres choses d'ailleurs, avec l'aide de l'interface logicielle Intuition. Celle-ci permet l'affichage des menus et la gestion des interactions entre l'utilisateur et le programme via ce menu.

La première partie de cet article va donc consister en une description des menus : comment les créer et comment les gérer. Un programme d'exemple constituant la seconde partie mettra en pratique toute cette théorie. Dernier point avant que de commencer : les termes anglais entre parenthèses dissiminés tout au long de cet article, sont les termes "officiels" que vous trouverez dans la documentation développeur de Commodore, ceci afin de permettre à ceux qui la possèdent, de s'y retrouver plus facilement.

Définition et accès

Pour activer un menu Intuition, l'utilisateur doit appuyer sur le bouton droit de la souris. Intuition affiche alors la barre de menus (menu strip) liée à la fenêtre active, en haut de l'écran. Elle est composée d'un certain nombre de mots, baptisés "intitulés" ou "titres" des menus.

Quand l'utilisateur positionne le pointeur de la souris sur un menu, il le sélectionne : le titre du menu apparaît alors en surbrillance et une boîte contenant les différentes options qu'il propose (menu items) apparaît juste en dessous. La largeur de cette boîte est indépendante de celle du titre du menu. Sa hauteur dépend quant à elle du nombre d'options dans le menu et de leur hauteur. Lorsque l'utilisateur sélectionne une option (toujours à l'aide du pointeur de la souris), celle-ci apparaît à son tour en surbrillance. La confirmation de la sélection se fait tout simplement en relâchant le bouton droit de la souris, l'option choisie étant toujours en surbrillance. Une option de menu peut faire apparaître un sous-menu (sub-menu) présentant lui-même d'autres options.

Hiérarchie

La description ci-dessus, bien qu'un peu fastidieuse, nous permet d'appréhender la hiérarchie au sein des menus. En effet, on voit que l'on peut lier X menus à une fenêtre, chacun pouvant contenir Y options, pouvant elles-mêmes contenir Z sous-options. Chaque entité de même niveau est liée à la suivante par une liste chaînée simple.

Initialisation

Lorsque l'on veut gérer des menus, il faut d'abord les penser. On dessine sur papier la structure des menus, comprenant toutes les entités associées en partant des sous-options, puis les options, et en finissant par les menus. A noter que divers utilitaires du domaine public ou du commerce permettent de simplifier cette tâche. Leur principale caractéristique est de produire un code source C ou assembleur que le programmeur n'aura plus qu'à inclure dans son projet. Le plus célèbre est PowerWindows d'Innovatronics.

Structure d'un menu

Comme toujours dans l'Amiga, un menu (comprenez "un titre de menu") est défini par une structure C, que voici :

C

Les différents champs de cette structure sont décrits ci-après.

NextMenu : pointeur sur le menu suivant dans la liste. Lorsqu'il s'agit du dernier menu de la barre, NextMenu doit être initialisé à NULL.

LeftEdge, TopEdge, Width, Height : taille de la boîte de sélection du menu. LeftEdge représente la position de la boîte relativement à celle de l'écran. Width représente sa largeur. TopEdge et Height ne servent pas dans la version actuelle d'Intuition, plus tard peut-être (pour le moment on les met à 0 et on en parle plus).

Flags : peuvent être fixé par le programme et par Intuition. Ce sont :
  • MENUENABLED : indique si le menu est ou non sélectionnable. Si ce drapeau n'est pas présent lorsque l'on soumet le menu à Intuition, il n'est pas sélectionnable (de même que les options qui l'accompagnent). Il est possible d'autoriser ou non l'accès à un menu en cours de programme à l'aide des fonctions OnMenu() et Offflenu().
  • MIDRAWN : positionné par Intuition lorsque le menu est affiché.
MenuName : pointeur sur une chaîne de caractères (terminée par un "0") qui représente l'intitulé du menu. Intuition affichera ce texte dans la boîte de sélection du menu.

Firstftem : pointeur sur la première option du menu qui est une structure MenuItem.

Structure d'une option

La structure C associée aux fonctions et sous-fonctions est la même, mais elle ne s'utilise pas de la même manière. Cette structure est la suivante.

C

NextItem : pointeur sur la fonction suivante dans la liste chaînée. Le dernier élément dans la liste doit être initialisé à NULL.

LeftEdge, TopEdge, Width, Height : taille et position de la boîte de sélection de l'option (zone dans laquelle l'option est sélectionnée par le pointeur de souris). LeftEdge et TopEdge représentent la position relative du coin haut-gauche de la boîte par rapport à la position du coin haut-gauche de celle du menu. Width et Height représentent respectivement la largeur et la hauteur de la boîte.

Flags : positionnée par le programme ou par Intuition. Ce sont :
  • CHECKIT : place une coche (checkmark) devant l'option lorsqu'elle est sélectionnée (interrupteur on/off). La structure NewWindow de la fenêtre à laquelle le menu est associé, contient un champ nommé CheckMark pouvant pointer sur une imagerie personnelle pour la coche.
  • CHECKED : si CHECKIT est positionné, CHECKED rend l'option active (on) dès la mise en place du menu.
  • ITEMTEXT : mis à 1 si l'option de menu est un texte, à 0 si c'est une image.
  • COMMSEQ : mis à 1 si l'option peut également être sélectionnée au clavier (Amiga droite + une touche). Le code ASCII de cette touche se trouve alors dans le champ Command (voir ci-dessous).
  • ITEMENABLED : mis à 1 l'option est sélectionnable, sinon elle apparaît en grisé. Il est possible d'autoriser ou d'interdire l'accès à une option en cours de programme à l'aide des fonctions OnMenu() et OffMenu() que nous décrirons ultérieurement.
Note : si une option devient non sélectionnable, toutes les sous-options qui lui sont associées sont également inaccessibles.
  • HIGH Flags : indique le mode de surbrillance à appliquer à cette option. Il faut positionner un et un seul des bits ci-dessous.
    • HIGHCONIP : l'option sélectionnée apparaît en vidéo inversée (cas le plus fréquent).
    • HIGHBOX : traçage d'une boîte (rectangle) autour de la boîte de sélection de l'option (souvent pour "Quit").
    • HIGHIMAGE : affichage d'un intitulé complémentaire (texte ou image).
    • HIGHNONE : aucune surbrillance, il n'y pas de différence entre l'intitulé sélectionné ou non.
Les drapeaux suivants sont positionnés plus particulièrement par Intuition.
  • ISDRAWN : mis à 1 quand le sous-menu associé à cette option est affiché.
  • HIGHITEM : mis à 1 lorsque l'option est actuellement affichée en surbrillance.
MutualExclude : là, de plus amples explications me semblent nécessaires. Vous pouvez choisir d'avoir certaines options, déclarées avec le drapeau CHECKIT qui, sélectionnées, désélectionnent d'autres options. C'est ce que l'on appelle l'exclusion mutuelle. Prenons un exemple porté sur la boisson. Un personnage a la possibilité de choisir d'emporter à boire dans quatre types de contenants : une fiole, une bouteille, un bidon ou un tonneau. Il est raisonnable de penser que le personnage choisissant le tonneau ne pourra pas emporter en plus une bouteille ou un bidon. La fiole, elle, peut toujours se glisser dans une poche. Par contre, il pourra très bien prendre le bidon, la bouteille et la fiole en même temps (les camarades de l'ANT y arrivent sans problème). Cela signifie que la possession du tonneau exclut la bouteille et le bidon, de même que la possession du bidon ou de la bouteille (à fortiori des deux) exclut le tonneau.

Le champ MutualExclusion est un mot long (type LONG sur 32 bits) où chaque bit représente une option dans la liste correspondant a un menu. Le premier dans la liste a le bit 0, le second le bit 1, etc. Ce qui signifie dans un premier temps que seules 32 options appartenant à un même menu peuvent utiliser ce champ (ce qui n'est déjà pas si mal !). Lorsque le énième bit du champ MutualExclude de l'option X est positionné, l'option N est automatiquement exclue lorsque l'option X est sélectionnée. Dans notre exemple, on va mettre $fff6 pour tonneau (on exclut tous les autres sauf la fiole et lui). Pour le bidon et la bouteille, on met $0001 car on exclut le tonneau seulement. Pour la fiole on mettra $0000 car on n'exclut rien du tout.

ItemFill : pointeur sur l'intitulé de la fonction, en l'occurrence une structure IntuiText si le drapeau ITEMTEXT est positionné, sinon c'est une structure Image.

SelectFill : si le drapeau HIGHIMAGE est positionné, Intuition substituera à la structure contenue dans ItemFill celle contenue dans SelectFill lorsque l'option sera sélectionnée. SelectFill est donc un pointeur sur une structure IntuiText ou Image, selon la présence ou non du drapeau ITEMTEXT.

Note : on ne peut pas afficher une image à la place d'un texte, et vice-versa.

Command : code ASCII du caractère composant le raccourci clavier lorsque le drapeau COMMSEQ est positionné. L'utilisateur peut choisir directement l'option en appuyant simultanément sur la touche Amiga droite et sur le caractère contenu dans ce champ. Au niveau programme proprement dit, tout se passe comme si la fonction avait été sélectionnée à la souris.

Note : aucune vérification n'est faite pour voir si une même commande est utilisée plusieurs fois dans un menu. De plus, Intuition ne fait pas la différence entre les majuscules et minuscules ; s'il en a besoin, le programme doit tester lui-même si une touche Shift (ou verrouillage nulérique) est enfoncée au moyen du champ Qualifier de la structure IntuiMessage (Cf. plus loin).

SubItem : pointeur sur la première sous-option de cette option. Ce champ est ignoré si l'option courante fait déjà partie d'un sous-menu.

NextSelect : dernier champ de la structure, mais il est loin d'être le moins important. En effet, si l'utilisateur a la possibilité de sélectionner plusieurs options dans un menu en une seule opération (en cliquant avec le bouton de gauche de la souris les différentes options, tout en maintenant le bouton droit de la souris appuyé), rien dans l'IntuiMessage n'indique au programme que c'est bel et bien ce qui s'est passé. Pour garder une trace de cette sélection multiple et donc permettre de traiter toutes les options choisies, Intuition remplit le champ NextSelect avec le numéro de l'option suivante. Bon allez, je suis compréhensif et vous livre un petit bout de source qui illustre la manière de s'y prendre.

C

Mise en place du menu

On a donc décrit la structure de son petit menu, en suivant les explications ci-dessus et en s'imprégnant de l'exemple ci-dessous (le va-et-vient est terminé, on continue).

Première opération à réaliser, ouvrir une fenêtre à l'aide de la fonction OpenWindow(). En effet, pour attacher un menu à une fenêtre, il semble raisonnable d'ouvrir une fenêtre (si, si, j'vous jure !). Comme déjà dit plus haut, le champ CheckMark de la structure NewWindow peut pointer sur une structure Image décrivant une coche personnelle à utiliser pour toutes les options du menu ayant les drapeau CHECKIT et CHECKED positionnés. Ensuite, on attache le menu à la fenêtre, à l'aide de la fonction SetMenuStrip().

SetMenuStrip(fenêtre, menu)

"fenêtre" est un pointeur sur une structure Window créée par OpenWindow(). Il s'agit de la fenêtre à laquelle on veut attacher le menu. "menu" est un pointeur sur le premier menu de la liste chaînée des menus à afficher.

Bien entendu, il ne se passe rien de particulier lorsque l'utilisateur sélectionne une option du menu. C'est au programme de réagir en conséquence. Il faut donc écrire un petit bout de code pour savoir ce que l'utilisateur a sélectionné et quelle fonction activer. Pour ce faire, on va encore se faire aider par Intuition.

A chaque fois que l'utilisateur active le système de gestion de menus en pressant le bouton droit de la souris, Intuition génère un message (sous la forme d'une structure IntuiMessage) de classe MENUPICK. Vous pouvez donc tester les messages que vous envoie Intuition pour savoir si oui ou non il s'agit de l'activation d'un menu. Voici le résultat en quelques lignes.

C

Le programme fournit ci-dessous utilise ce principe. Il nous faut maintenant déterminer quels menus, options, et sous-options ont été sélectionnés. Une fois de plus, Intuition nous aide. En effet, lorsqu'il envoie une structure IntuiMessage de classe MENUPICK, celle-ci contient également dans son champ Code un WORD correspondant au menu, à l'option et éventuellement à la sous-option sélectionnée. Ce mot long étant assez peu parlant par lui-même, on va déterminer quelle option précisément a été sélectionnée à l'aide des macros :
  • MENUNUM(Code) qui renvoie le numéro du menu sélectionné.
  • ITEMMENU(Code) qui renvoie le numéro de la fonction sélectionnée.
  • SUBNUM(Code) qui renvoie le numéro de la sous-fonction.
Les numéros commencent toujours à zéro et non à un.

Si l'on active la fonction 2 du menu 4 on a :
  • MENUNUM(Code) = 3
  • ITEMNUM(Code) = 1
  • SUBNUM(Code) = NOSUB
Si l'on active là sous-fonction 3 de la fonction 4 du menu 1 on a :
  • MENUNUM(Code) = 0
  • ITEMNUM(Code) = 3
  • SUBNUM(Code) = 2
Comme on peut le remarquer, lorsqu'aucune sous-option n'est sélectionnée, SUBNUM() renvoie NOSUB. De même, si aucune option n'est sélectionnée, ITEMNUM() renvoie NOITEM. Enfin, si aucun menu n'est sélectionné (on clique le bouton droit et on relâche en dehors de la zone des menus), MENUNUM() vaut NOMENU.

On notera qu'Intuition envoie systématiquement un message MENUPICK lorsque l'utilisateur a enfoncé le bouton droit de la souris, et ce même si aucune sélection n'a été effectuée. D'où l'utilité de vérifier que le champ Code soit différent de MENUNULL. Le programme d'exemple fournit une fonction testmenu() qui utilise ce principe. Il ne nous reste plus qu'à étudier quelques fonctions qui permettent de travailler dynamiquement sur les menus et nous aurons fait le tour de cet outil si pratique.

Fonctions utiles

Nous avons entrevu la possibilité qui nous était donnée d'interdire ou d'autoriser l'accès à un menu, une option ou une sous-option en plein milieu de l'exécution du programme. L'interdiction est réalisée à l'aide de la fonction OffMenu()

OffMenu(fenetre, numero)

"fenetre" est un pointeur sur la fenêtre à laquelle est lié le menu. "numero" correspond au numéro de la fonction ou du menu à interdire (sous une forme équivalente au champ Code de la structure IntuiMessage de type MENUPICK que renvoie Intuition quand une fonction a été sélectionnée). On le calcule avec la formule :

numero=numero_sousfonction*2048+numero_fonction*32+numero_menu

C'est tout simple et en plus ça fonctionne très bien.

Pour autoriser un menu à nouveau on utilise OnMenu() :

OnMenu(fenetre, numero)

Enfin, la dernière fonction :

ItemAddress(premier_menu, numero)

...calcule l'adresse d'une option ou sous-option à partir de l'adresse du premier menu et du numéro associé au menu à la fonction ou la sous-fonction à autoriser.

Enfin, lorsque l'on n'a plus besoin du menu, on l'élimine de la fenêtre grâce à la fonction :

CleaMenuStrip(fenetre)

"fenetre" étant le pointeur sur la fenêtre à laquelle est lié le menu.

Conclusion

Il ne vous reste plus qu'à étudier le programme fourni comme exemple et qui se trouve bien entendu sur la disquette d'accompagnement de ce numéro. Il a été compilé sans problème avec Lattice 5.10 et Aztec 5.0d.

C
C

Le mois prochain, nous aborderons la gestion des sprites avec comme exemple quelques variations sur la gestion du pointeur de souris.


[Retour en haut] / [Retour aux articles] [Article précédent] / [Article suivant]