Obligement - L'Amiga au maximum

Mardi 03 juin 2025 - 20:28  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

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

Articles in English


Réseaux sociaux

Suivez-nous sur X




Liste des 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,
ALL


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


Galeries

Menu des galeries

BD d'Amiga Spécial
Caricatures Dudai
Caricatures Jet d'ail
Diagrammes de Jay Miner
Images insolites
Fin de jeux (de A à E)
Fin de Jeux (de F à O)
Fin de jeux (de P à Z)
Galerie de Mike Dafunk
Logos d'Obligement
Pubs pour matériels
Systèmes d'exploitation
Trombinoscope Alchimie 7
Vidéos


Téléchargement

Documents
Jeux
Logiciels
Magazines
Divers


Liens

Associations
Jeux
Logiciels
Matériel
Magazines et médias
Pages personnelles
Réparateurs
Revendeurs
Scène démo
Sites de téléchargement
Divers


Partenaires

Annuaire Amiga

Amedia Computer

Relec


A Propos

A propos d'Obligement

A Propos


Contact

David Brunet

Courriel

 


Programmation : Amiga C Manual - Les menus
(Article écrit par Anders Bjerin et extrait d'Amiga C Manual - mars 1990)


Note : traduction par Serge Hammouche.

7. Les menus

7.1 Introduction

Si vous avez utilisé l'Amiga, vous vous êtes probablement beaucoup servis de ses menus. Ce sont des outils flexibles, faciles d'accès et faciles à mettre en place. Dans ce chapitre, nous verrons comment vous pourrez créer vos propres menus et comment vous pourrez utiliser toutes les caractéristiques particulières qu'Intuition met à votre disposition. Nous verrons aussi comment s'effectue la communication entre l'utilisateur et les menus.

7.2 Le concept de menu

Vous pouvez relier une "barre de menu" à chaque fenêtre : lorsque l'utilisateur appuiera sur le bouton droit de la souris, la barre de menu de la fenêtre de travail apparaîtra dans la partie supérieure de l'affichage.

Voici un exemple de barre de menu :

Project  Block  Windows  Search

L'utilisateur pourra maintenant bouger le pointeur sur l'un des en-têtes des menus, tout en appuyant sur le bouton droit de la souris ; ceci provoquera l'affichage du "cadre de rubrique" du menu.

Voici un exemple de cadre de rubrique :

PROJECT  Block  Windows  Search
|----------|
| Open     |
| Save     |
| Save as  |
| Print    |
| Info     |
| Quit     |
|----------|

L'utilisateur pourra maintenant choisir la rubrique de menu qu'il souhaite. Il pourra le faire en bougeant le pointeur sur la rubrique de menu voulue et en relâchant ensuite le bouton droit de la souris. Si l'utilisateur le souhaite, il pourra désigner plusieurs rubriques de menu par une même "action sur le menu", en appuyant comme d'habitude sur le bouton droit de la souris, tout en cliquant avec le bouton gauche sur chaque rubrique de menu qu'il souhaite sélectionner. L'utilisateur pourra aussi "se déplacer" (en appuyant sur les deux boutons de la souris) sur plusieurs rubriques de menu s'il veut les sélectionner toutes.

Si vous le souhaitez, vous pourrez relier à chaque rubrique un menu différent. Habituellement, on appelle ce menu "sous-menu" et il est composé d'une ou de plusieurs "sous-rubriques".

Voici un exemple de sous-rubriques (remarquez que le cadre des sous-rubriques chevauche le cadre des rubriques !) :

Project  Block  Windows  Search
|----------|
| Open     |
| Save     |
| Save a--------------
| PRINT | to printer |
| Info  | to a file  |
| Quit  --------------
|----------|

7.3 Comment avoir accès aux menus à partir du clavier

Si vous le souhaitez, vous pouvez permettre à l'utilisateur de sélectionner certaines rubriques de menu par l'intermédiaire du clavier. C'est bien pratique, s'il s'agit d'une commande que l'utilisateur emploie souvent et si vous voulez lui offrir un raccourci. L'utilisateur pourra avoir accès à la rubrique de menu en appuyant sur la touche "Amiga" et sur une autre touche. Par exemple, si l'utilisateur doit pouvoir avoir accès à la rubrique de menu "Open", à partir du clavier, en appuyant sur la touche "Amiga" et sur la touche "O", Intuition ajoutera automatiquement le signe "[A] O" à la suite du nom de la rubrique :

PROJECT  Block  Windows  Search
|------------|
| Open [A] O |
| Save       |
| Save as    |
| Print      |
| Info       |
| Quit       |
|------------|

Votre programme ne fera aucune différence entre un accès normal au menu et un raccourci.

N'oubliez pas de laisser assez de place dans la partie droite du cadre de la rubrique pour que le caractère Amiga et le signe puissent rentrer dans le cadre. Si le cadre de la rubrique avait une largeur de 100 pixels, vous pourriez mettre la largeur à 100, plus COMMWIDTH, et tout rentrera facilement (COMMWIDTH est une constante déclarée dans le fichier d'en-tête intuition.h). Si la fenêtre était reliée à un écran en basse résolution, employez alors la constante LOWCOMMWIDTH.

7.4 Les rubriques de menu

Il existe deux types différents de rubriques de menu :
  • Les rubriques d'action.
  • Les rubriques d'affectation.
Les rubriques d'action peuvent être sélectionnées à l'infini et à chaque fois qu'on les sélectionnera, elles enverront un message à votre programme.

Les rubriques d'affectation, de leur côté, peuvent être sélectionnées une fois seulement et une fois qu'elles ont été sélectionnées, on devra invalider leur sélection pour pouvoir les sélectionner à nouveau. La seule manière d'invalider la sélection d'une rubrique d'affectation est de prévoir l'exclusion mutuelle (expliquée un peu plus loin dans ce chapitre).

Lorsqu'on sélectionne une rubrique d'affectation, Intuition met une petite marque de contrôle, [v], devant le nom de la rubrique. Si vous voulez employer une marque de contrôle personnalisée, à la place de la marque par défaut vous devrez fixer le pointeur CheckMark de votre structure NewWindow pour qu'il pointe sur une structure Image que vous aurez déclarée et initialisée à votre guise.

Si vous vous servez d'une rubrique d'affectation dans votre menu, vous devrez laisser assez de place pour la marque de vérification dans la partie gauche du cadre de menu. Si vous employez la marque par défaut, vous pourrez déplacer le texte du menu sur la droite d'un nombre de pixels égal à CHECKWIDTH (CHECKWIDTH est une constante déclarée dans le fichier d'en-tête intuition.h). Si la fenêtre est reliée à un écran en basse résolution (largeur égale à 320 pixels), employez alors la constante LOWCHECKWIDTH à la place de CHECKWIDTH.

7.5 L'exclusion mutuelle

Cette fonction particulière et très utile s'applique seulement aux rubriques d'affectation. L'idée qui est à la base de l'exclusion mutuelle est la suivante : lorsque l'utilisateur sélectionne une certaine rubrique, les autres rubriques d'affectation seront automatiquement invalidées. Par exemple, vous êtes en train de programmer un traitement de texte et l'utilisateur devra pouvoir imprimer son texte soit d'une manière normale (ordinaire), soit en utilisant un style particulier (gras, souligné, italique). On offrira donc à l'utilisateur la possibilité de sélectionner Ordinaire ou l'un des autres styles ou plusieurs autres (gras et souligné, par exemple). Si l'utilisateur sélectionne "ordinaire", tous les autres styles devront être invalidés (exclusion mutuelle). D'autre part, si l'utilisateur sélectionne "gras", "souligné" ou "italique", il faudra que la rubrique "ordinaire" soit invalidée.

Voici comment fonctionne l'exclusion mutuelle :
  • Si le drapeau CHECKIT n'est pas mis (Cf. la structure MenuItem), la rubrique n'est pas une rubrique d'affectation ; il s'agit d'une rubrique d'action : l'exclusion mutuelle ne produira aucun effet sur la rubrique elle-même.
  • Si le drapeau CHECKIT est mis, la rubrique est une rubrique d'affectation et Intuition s'assurera que le drapeau n'est pas mis. S'il l'est, Intuition l'enlèvera automatiquement et la rubrique sera invalidée.
Chaque rubrique a un champ MutualExclude où vous pouvez indiquer quelles rubriques devront être invalidées lorsque cette rubrique est activée. Le premier bit de ce champ se réfère à la première rubrique, le deuxième à la deuxième rubrique et ainsi de suite.

Dans notre exemple précédent, nous avons mis le champ MutualExclude de la rubrique "ordinaire" à 0xFFFFFFFE (0xFFFFFFFE est égal à 11111111111111111111111111111110). Ce faisant, nous exclurons toutes les rubriques, sauf la première ("ordinaire" est la première rubrique de la liste et, naturellement, on ne devra pas l'exclure).

Le champ des autres rubriques (gras, souligné et italique) devra être mis à 0x00000001 (0x00000001 est égal à 00000000000000000000000000000001). Ce faisant, nous exclurons seulement la première rubrique (la rubrique "ordinaire").

7.6 L'ouverture d'un menu

Si vous voulez relier une barre de menu à une fenêtre, vous devrez :
  1. Déclarer et initialiser une ou plusieurs structures Menu. Vous devrez relier ces structures les unes aux autres et chacune d'elle aura sa propre liste de rubriques. Chaque structure Menu représente une "en-tête de menu".
  2. Déclarer et initialiser une ou plusieurs structures MenuItem, qui seront reliées aux structures Menu. Chaque structure MenuItem représente une rubrique. Si vous le souhaitez, vous pourrez connecter une liste de sous-rubriques à une structure Item (les sous-rubriques utilisent les mêmes structures de données que les rubriques normales).
  3. Appeler la fonction SetMenuStrip(). Important : avant de fermer la fenêtre ou de changer la barre de menu, vous devrez déconnecter le menu de la fenêtre. Vous pourrez le faire en appelant la fonction ClearMenuStrip().
7.6.1 L'initialisation d'une structure Menu

Voici à quoi ressemble une structure Menu :

struct Menu
{
  struct Menu *NextMenu;
  SHORT LeftEdge, TopEdge, Width, Height;
  USHORT Flags;
  BYTE *MenuName;
  struct MenuItem *FirstItem;
  SHORT JazzX, JazzY, BeatX, BeatY;
};
  • NextMenu : pointeur sur la structure Menu suivante dans la liste de la barre de menu. On mettra à NULL le champ NextMenu de la dernière structure Menu de la liste.
  • LeftEdge : position X du titre du menu.
  • TopEdge : position Y du titre du menu. Pour l'instant, ce champ est inutilisé car tous les menus sont positionnés dans la partie supérieure de l'affichage. Mettez ce champ à 0.
  • Width : largeur du titre du menu.
  • Height : hauteur du titre du menu. Pour l'instant, ce champ est inutilisé car la hauteur de tous les menus est égale à celle de la barre de titre de l'écran. Mettez ce champ à 0.
  • Flags : pour l'instant, il n'y a que deux drapeaux différents :
    • MENUENABLED : si ce drapeau est mis à 1, le menu est activé et l'utilisateur pourra en sélectionner les rubriques. S'il n'est pas mis à 1, le menu apparaît "grisé" et l'utilisateur ne pourra sélectionner aucune de ses rubriques.
      Si vous voulez que le menu soit activé lorsque vous en passerez le contrôle à Intuition, vous devrez mettre ce drapeau à 1. Par la suite, vous pourrez en changer l'état en appelant les fonctions OnMenu() et OffMenu().
    • MIDRAWN : ce drapeau est mis à 1 par Intuition lorsque le menu s'affiche aux yeux de l'utilisateur.
  • MenuName : pointeur sur une chaîne de caractères qui se termine par NULL. Le texte apparaîtra dans le cadre du menu dans la partie supérieure de l'écran.
  • FirstItem : pointeur sur le premier MenuItem de la liste des rubriques.
Les variables suivantes - si joliment nommées - sont seulement à usage interne :
  • JazzX, JazzY, BeatX, BeatY : utilisées par Intuition. Mettez-les à 0.
Voici un exemple de comment on déclare et on initialise une structure Menu :

struct Menu my_menu=
{
  NULL,        /* NextMenu, il n'y a pas d'autres      */
               /* structures de menu.                  */
  0,           /* LeftEdge, position X à 0 pixels.     */
  0,           /* TopEdge, pour l'instant ignoré par   */
               /* Intuition. Mettez-le à 0.            */
  60,          /* Width, largeur 60 pixels.            */
  0,           /* Height, pour l'instant ignoré par    */
               /* Intuition. Mettez-le à 0.            */
  MENUENABLED, /* Flags, on doit pouvoir activer       */
               /* ce menu.                             */
  "Project",   /* MenuName, titre du menu.             */
  &first_item, /* FirstItem, pointeur sur la première  */
               /* rubrique de la liste.                */
  0, 0, 0, 0   /* JazzX, JazzY, BeatX, BeatY           */
};

7.6.2 L'initialisation d'une structure de rubriques de menu

Voici à quoi ressemble une structure MenuItem :

struct MenuItem
{
  struct MenuItem *NextItem;
  SHORT LeftEdge, TopEdge, Width, Height;
  USHORT Flags;
  LONG MutualExclude;
  APTR ItemFill;
  APTR SelectFill;
  BYTE Command;
  struct MenuItem *SubItem;
  USHORT NextSelect;
};
  • NextItem : pointeur sur la prochaine structure MenuItem de la liste de rubriques. Le champ NextItem de la dernière structure de rubrique de la liste sera fixé à NULL.
  • LeftEdge : position X du cadre de sélection de la rubrique, relative au coin supérieur gauche de la structure Menu.
  • TopEdge : position Y du cadre de sélection de la rubrique, relative à la position extrême qu'autorise Intuition. Cette position extrême est calculée automatiquement par Intuition, qui examine la taille de la police, combien de rubriques il y a déjà, etc. Mettez TopEdge à 0 pour sélectionner la position extrême.
  • Width : la largeur du cadre de sélection de la rubrique.
  • Height : la hauteur du cadre de sélection de la rubrique.
  • Flags : voici les drapeaux pouvant être utilisés par vous et par Intuition :
    • CHECKIT : mettez ce drapeau si vous souhaitez que votre rubrique soit une rubrique d'affectation, autrement vous aurez une rubrique d'action. Si vous mettez ce drapeau, Intuition affichera la petite marque de contrôle avant le texte de la rubrique, lorsqu'on la sélectionnera. Faites donc bien attention à laisser assez de place.
    • CHECKED : s'il s'agit d'une rubrique d'affectation (le drapeau CHECKIT est mis), ce drapeau sera mis par Intuition, lorsque l'utilisateur sélectionnera cette rubrique. Intuition se chargera aussi de mettre ce drapeau à 0 automatiquement, lorsqu'il s'agira d'une rubrique à exclusion mutuelle.
      Vous pouvez fixer vous-même ce drapeau, avant de passer le contrôle de la barre de menu à Intuition si vous souhaitez que la rubrique soit déjà sélectionnée au démarrage.
    • HIGHITEM : la rubrique s'affichera en surbrillance et ce drapeau sera mis à 1 lorsque l'utilisateur bougera le pointeur sur le cadre de la rubrique choisie.
      Vous devrez mettre à 1 l'un des quatre drapeaux suivants pour informer Intuition du type de de surbrillance que vous voulez : HIGHCOMP (complémente les couleurs de tous les pixels qui se trouvent dans le cadre de la rubrique choisie), HIGHBOX (trace un cadre autour du cadre de la rubrique choisie), HIGHIMAGE (affiche une image ou un texte de rechange) et HIGHNONE (pas de surbrillance).
    • ITEMENABLED : si ce drapeau est mis à 1, la rubrique est en service et l'utilisateur pourra la sélectionner. Si ce drapeau n'est pas mis, la rubrique est grisée et l'utilisateur ne pourra pas la sélectionner.
      Si vous souhaitez que la rubrique soit mise en service lorsqu'elle passe sous le contrôle d'Intuition, vous devrez mettre ce drapeau à 1. Par la suite, vous pourrez changer l'état de ce bit en appelant les fonctions OnMenu() et OffMenu().
    • ITEMTEXT : si l'on veut que cette rubrique soit représentée par un texte, vous devrez mettre ce drapeau à 1. Intuition attendra alors ItemFill et SelectFill pour pointer sur les structures IntuiText. Si ce drapeau n'est pas mis à 1, la rubrique sera représentée par un dessin et Intuition attendra ItemFill et SelectFill pour pointer sur les structures Image.
    • COMMSEQ : vous devrez mettre ce drapeau à 1 si la rubrique doit être accessible par l'intermédiaire du clavier. Souvenez-vous que vous devez informer Intuition de la touche sur laquelle il faut appuyer, en même temps qu'on appuie sur la touche "Amiga", pour pouvoir sélectionner la rubrique. Vous pourrez le faire en confiant le caractère voulu à la variable Command.
    • ISDRAWN : ce drapeau est mis à 1 par Intuition lorsque sont affichées les sous-rubriques d'une rubrique ; ce même drapeau est remis à 0 lorsque les sous-rubriques ne sont plus affichées.
  • MutualExclude : cette variable informera Intuition sur les rubriques d'affectation qui devront s'exclure réciproquement (elles seront invalidées lorsque cette rubrique sera sélectionnée). Le premier bit se réfère à la première rubrique de la liste active (liste de rubriques ou de sous-rubriques), le deuxième se réfère à la deuxième rubrique et ainsi de suite. Par exemple, le nombre 0x0000000B en hexadécimal est égal à 00000000000000000000000000001011 en binaire, par conséquent Intuition essaiera d'exclure réciproquement la première, la seconde et la quatrième rubrique.
  • ItemFill : pointeur sur une structure Image (si le drapeau ITEMTEXT n'est pas mis à 1) ou sur une structure IntuiText (si le drapeau ITEMTEXT est mis à 1), utilisée par Intuition pour représenter cette rubrique.
  • SelectFill : pointeur sur une structure Image (si le drapeau ITEMTEXT n'est pas mis à 1) ou sur une structure IntuiText (si le drapeau ITEMTEXT est mis à 1), pour représenter cette rubrique lorsqu'elle est en surbrillance (on peut utiliser ce champ seulement si on a mis à 1 le drapeau HIGHIMAGE).
  • Command : si l'utilisateur doit pouvoir avoir accès à cette rubrique par l'intermédiaire du clavier, vous devrez informer Intuition de la touche que vous emploierez. Par conséquent, ce champ devra contenir le caractère voulu (n'oubliez pas de mettre à 1 le drapeau COMMSEQ dans le champ Flags).
  • SubItem : pointeur sur une liste de sous-rubriques, s'il y en a une, autrement NULL. Si cette rubrique est déjà une sous-rubrique, Intuition ignorera ce champ (n'oubliez pas que la liste de sous-rubriques est constituée d'une liste chaînée de structures MenuItem).
  • NextSelect : ce champ est géré par Intuition et contiendra un numéro spécial si, après avoir sélectionné une première rubrique, plusieurs autres rubriques sont sélectionnées en même temps dans un même menu, autrement il contiendra MENUNULL (nous approfondirons ceci plus avant dans ce chapitre). Donnez à ce champ la valeur MENUNULL.
Voici un exemple de déclaration et d'initialisation d'une structure MenuItem :

struct MenuItem my_first_item=                                
{                                                             
  &my_second_item,   /* NextItem, pointeur sur la prochaine   */
                     /* rubrique de la liste.                 */
  0,                 /* LeftEdge, position X à 0 pixels.      */
  0,                 /* TopEdge, position supérieure maxi.    */
  150,               /* Width, largeur de 150 pixels.         */
  10,                /* Height, hauteur de 10 lignes.         */
  CHECKIT|           /* Flags, une rubrique d'affectation.    */
  CHECKED|           /*        Devra être déjà sélectionnée   */
  COMMSEQ|           /*        et accessible via le clavier.  */
  HIGHCOMP|          /*        Complémente les couleurs si    */
  ITEMENABLED,       /*        en surbrillance. La rubrique   */
                     /*        doit être activée. Ne pas      */
                     /*        être grisée.                 */
  0x00000037,        /* MutualExclude, invalide si possible   */
                     /* les rubriques 1, 2, 3, 5 et 6.        */
  &my_image          /* ItemFill, pointeur sur une structure  */
                     /* Image employée pour le rendu de la    */
                     /* rubrique. Du moment que le drapeau    */
                     /* ITEMTEXT n'a pas été mis, Intuition   */
                     /* considérera que celui-ci est un       */
                     /* pointeur sur une structure Image et   */
                     /* non un pointeur sur une structure     */
                     /* IntuiText.                            */
  NULL,              /* SelectFill, NULL étant donné que nous */
                     /* complémentons les couleurs au lieu    */
                     /* d'afficher une image alternative.     */
  'O',               /* Command, le caractère sur lequel il   */
                     /* faudra appuyer en même temps qu'on    */
                     /* appuiera sur la touche "Amiga" pour   */
                     /* employer un raccourci-clavier.        */
  NULL,              /* SubItem, aucune sous-rubrique n'est   */
                     /* reliée à cette rubrique.              */
  MENUNULL           /* NextSelect, valeur qu'Intuition       */
                     /* fixera par la suite.                  */
};

7.6.3 Coment relier ou enlever une barre de menu a une/d'une fenêtre

Dès que vous aurez déclaré et initialisé les structures Menu et MenuItem appropriées et que vous les aurez reliées l'une à l'autre, vous n'aurez plus qu'à appeler la fonction SetMenuStrip() et la barre de menu sera reliée à votre fenêtre. Souvenez-vous que vous devez d'abord ouvrir la fenêtre, avant de lui relier une barre de menu.

Si vous avez un pointeur sur une fenêtre ouverte auparavant, my_window, et un pointeur sur la structure du premier Menu de votre liste, my_first_menu, vous pourrez relier la barre de menu à la fenêtre de la manière suivante :

SetMenuStrip( my_window, my_first_menu );

Si vous voulez changer une barre de menu qui est déjà reliée à une fenêtre, vous devrez d'abord supprimer la barre. Vous le ferez en appelant la fonction ClearMenuStrip(). Vous pourrez alors changer ce que vous souhaitez et relier à nouveau la barre à la fenêtre.

Pour supprimer la barre de menu d'une fenêtre, vous aurez seulement besoin du pointeur sur cette fenêtre, par exemple my_window, puis de faire appel à la fonction ClearMenuStrip() de la manière suivante :

ClearMenuStrip( my_window );

Si une barre de menu est reliée à une fenêtre et que vous souhaitez fermer cette fenêtre, vous devrez d'abord supprimer le menu. Si votre programme ne supprime pas la barre de menu avant de fermer la fenêtre, il y a le risque que l'utilisateur ait activé le menu et que le programme entraîne un beau plantage du système. Par conséquent, pour ne pas prendre de risques, appelez toujours la fonction ClearMenuStrip() avant de fermer une fenêtre à laquelle est rattachée une barre de menu.

7.7 Les drapeaux IDCMP particuliers

Il existe deux drapeaux IDCMP qui sont en étroite relation avec les menus. Il s'agit de MENUPICK et de MENUVERIFY. Le drapeau IDCMP MENUPICK informe votre programme que l'utilisateur a choisi plusieurs rubriques d'un menu ou qu'il n'en a choisi aucune. MENUVERIFY permet à votre programme d'en terminer avec une opération en cours avant que le menu s'affiche ; vous pourrez même - si vous le souhaitez - mettre fine à toute opération sur un menu.

7.7.1 Le drapeau MENUPICK

Si vous souhaitez que votre programme reçoive un message à chaque fois qu'un utilisateur ne choisit aucune rubrique/sous-rubrique du menu ou qu'il en choisit plusieurs, vous devrez mettre à 1 le drapeau MENUPICK du champ IDCMPFlags de votre structure NewWindow. Vous pourrez ensuite manipuler ce message comme tous les autres messages IDCMP (Cf. le chapitre 8 - IDCMP pour plus de renseignements sur les messages IDCMP).

Dès que vous aurez reçu un message MENUPICK, vous devrez vérifier si des rubriques ont été sélectionnées. Le champ Code de la structure IntuiMessage contiendra un numéro spécial de code ("Menu Number") que nous pourrons examiner pour voir quelle rubrique a été sélectionnée. Ce numéro de menu est égal à MENUNULL si l'on n'a pas sélectionné de rubrique. Servez-vous de la fonction ItemAddress() qui attend comme paramètres un pointeur sur la barre de menu et le numéro de menu ; elle vous retournera l'adresse de la rubrique qui a été sélectionnée.

Voici un problème qui pourrait se poser : lors d'une seule opération sur un menu, l'utilisateur peut sélectionner plusieurs rubriques et votre programmes devra les tester toutes. Il y a cependant une solution à ce problème. Si une rubrique a été sélectionnée, nous pourrons examiner le champ NextSelect de la structure de cette rubrique : nous y trouverons soit MENUNULL (aucune autre rubrique n'a été sélectionnée) soit un numéro spécial de menu (si ce numéro n'est pas égal à MENUNULL, vous devrez appeler une fois de plus la fonction ItemAddress() pour obtenir un pointeur sur la structure de la deuxième rubrique et ainsi de suite...).

Voici un fragment de programme qui manipule un événement MENUPICK :

if( class == MENUPICK )
{
  /* L'utilisateur a relâché le bouton droit de la souris.  */
  
  /* La variable menu_number est initialisée avec la valeur */
  /* du code:                                               */
  menu_number = code;
  
  /* Tant que menu_number n'est pas égal à MENUNULL nous    */
  /* resterons dans la boucle "while" :   */
  while( menu_number != MENUNULL )
  {
    /* Prendre l'adresse de la rubrique:  */
    item_address = ItemAddress( &first_menu, menu_number );
  
    /* Traiter cette rubrique... */
    
    /* Prendre le numéro de menu de la rubrique suivante : */
    menu_number = item_address->NextSelect;
  }
  
  /* Toutes les rubriques sélectionnées ont été traitées ! */
}

Si vous obtenez un numéro de menu, vous pourrez utiliser trois macros d'Intuition pour savoir quel(le) menu/rubrique/sous-rubrique a (ont) été sélectionné(es). Vous aurez un 0 en retour si vous avez à faire avec le (la) premier(-ère) menu/rubrique/sous-rubrique de la liste ou un 1 si vous avez à faire avec le (la) second(e), et ainsi de suite.
  • MENUNUM( menu_number ); égal à 0 si la rubrique a été sélectionnée dans le premier menu, égal à 1 si la rubrique a été sélectionnée dans le second et ainsi de suite. Il est égal à NOMENU si l'utilisateur n'a pas sélectionné de rubrique dans les menus.
  • ITEMNUM( menu_number ); égal à 0 si on a sélectionné la première rubrique de la liste de cette rubrique, égal à 1 si on a sélectionné la deuxième et ainsi de suite. Il est égal à NOITEM si l'utilisateur n'a sélectionné aucune rubrique.
  • SUBNUM( menu_number ); égal à 0 si on a sélectionné la première sous-rubrique de la liste de cette sous-rubrique, égal à 1 si on a sélectionné la deuxième et ainsi de suite. Il est égal à NOSUB si l'utilisateur n'a sélectionné aucune sous-rubrique.
7.7.2 Le drapeau MENUVERIFY

Le message MENUVERIFY informe votre programme que l'utilisateur a appuyé sur le bouton droit de la souris : un menu sera donc activé. Cependant, lorsque votre programme aura répondu, la barre de menu sera activée en premier et vous pourrez, par conséquent, grâce à cet avertissement, rester en attente d'un événement de menu pendant un certain temps ou même - si nécessaire - l'interrompre définitivement.

Si vous souhaitez que votre programme reçoive un message à chaque fois qu'un menu est activé, vous devrez mettre à 1 le drapeau MENUVERIFY du champ IDCMPFlags de la structure NewWindow. Le drapeau MENUVERIFY se comporte comme le drapeau REQVERIFY des requêtes.

Voici un exemple pour montrer comment votre programme devra traiter ce message de contrôle et comment vous pourrez annuler une opération sur un menu :

/* Attendre jusqu'à réception d'un ou plusieurs messages: */
Wait( 1 << my_window->UserPort->mp_SigBit );

/* Tant qu'il y aura des messages à récupérer, */
/* nous resterons dans cette boucle "while" :  */
while(my_message = GetMsg( my_window->UserPort ));
{
  /* Après avoir récupéré le message, nous pourrons le lire, */
  /* et sauvegarder certaines valeurs importantes que nous   */
  /* voudrons peut-être tester par la suite :                */
  class = my_message->Class;
  code = my_message->Code;

  /* Avant de répondre, nous devrons vérifier si l'on a reçu */
  /* un message MENUVERIFY:                                  */
  
  if( class == MENUVERIFY )
  {
    /* Oui, nous avons reçu un message MENUVERIFY !         */
    /* L'utilisateur veut activer un menu, mais le problème */
    /* est de savoir si on va activer le menu de notre      */
    /* fenêtre ou celui d'une autre fenêtre. Nous pouvons   */
    /* cependant le savoir en examinant le champ Code du    */
    /* message. Si celui-ci est égal à MENUWAITING, cela    */
    /* voudra dire qu'on ne va pas activer le menu de       */
    /* votre fenêtre, par contre si Code est égal à MENUHOT,*/
    /* cela voudra dire qu'on va activer le menu de votre   */
    /* fenêtre !                                            */
    
    if( code == MENUWAITING )
    {
      /* Ce n'est pas le menu de votre fenêtre qu'on va activer !*/
      
      /* Si nécessaire, votre programme pourra faire une pause.  */
      /* Vous voulez peut-être terminer des dessins, donc votre  */
      /* programme ne doit pas se débarrasser des menus. Ceci est*/
      /* particulièrement important si vous êtes en train de     */
      /* vous servir des routines graphiques de bas niveau car   */
      /* celles-ci ne se gêneront pas pour les menus, etc. et    */
      /* dessineront par-dessus et détruiront tout ce qui se     */
      /* trouvera sur leur passage.                              */
      
      /* Dès que le programme est prêt, il devra     */
      /* répondre au message et le menu sera activé. */
    }
    else
      if( code == MENUHOT )
      {
        /* C'est le menu de votre fenêtre qu'on va activer !  */
        
        /* Vous pouvez maintenant faire une pause et terminer        */
        /* quelque chose avant de permettre à Intuition d'activer le */
        /* menu ou même, si nécessaire, interrompre toute opération  */
        /* sur le menu. Si vous êtes en train d'écrire un programme  */
        /* de dessin, peut-être vous voudrez seulement que           */
        /* l'utilisateur soit en mesure d'activer le menu si le      */
        /* pointeur se trouve dans la partie supérieure de           */
        /* l'affichage. Ceci voudrait dire que l'utilisateur pourra  */
        /* dessiner avec le bouton droit de la souris et que quand   */
        /* il/elle voudra faire un choix dans le menu, il/elle devra */
        /* simplement bouger le pointeur dans la partie supérieure   */
        /* de l'affichage et appuyer ensuite sur le bouton droit de  */
        /* la souris.                                                */
        
        /* Maintenant, nous allons vérifier si le pointeur se trouve */
        /* quelque part dans la partie supérieure de l'affichage :   */
        if( my_window->MouseY < 10)
        {
          /* La coordonnée Y du pointeur se trouve au minimum */
          /* à moins de dix lignes au-dessous du TopEdge de   */
          /* fenêtre.                                         */
        
          /* L'opération sur le menu continuera dès que */
          /* possible !                                 */
        }
        else
        {
          /* Le pointeur se trouve au-dessous de la barre de titre   */
          /* de la fenêtre ! Annuler toute l'opération sur le menu ! */
          
          /* Pour annuler une opération sur un menu, vous devrez   */
          /* mettre MENUCANCEL dans le champ Code. Important !     */
          /* Ne pas changer la variable de code car celle-ci n'est */
          /* qu'une copie de la vraie variable de Code. Ce que     */
          /* nous devons faire, c'est de changer la vraie valeur   */
          /* et celle-ci est encore intacte tant que nous n'aurons */
          /* pas répondu.                                          */

          my_message->Code=MENUCANCEL;
        }
      }
  }

  /* Après avoir lu le message nous répondons aussi vite que   */
  /* possible. Rappel : ne jamais essayer de lire ou de changer*/
  /* un message après avoir répondu ! Un autre processus est   */
  /* peut-être en train de l'utiliser.                         */
  ReplyMsg( my_message );

Si vous mettez à 1 le drapeau RMBTRAP du champ Flags de votre structure NewWindow, vous informez Intuition que vous ne voulez utiliser aucun menu dans cette fenêtre. Votre programme pourrait alors utiliser le bouton droit de la souris pour quelque chose d'autre (voir le chapitre 8 - IDCMP pour plus d'informations sur RMBTRAP).

7.8 Les numéros de menu

Voici une description de la manière dont fonctionnent réellement les numéros de menus (par la suite, il se pourrait qu'on en modifie le fonctionnement, par conséquent ne calculez rien vous-même et laissez les macros d'Intuition tout faire à votre place).

Le numéro de menu est une variable à 16 bits dont les cinq premiers bits sont employés pour les menus, les six bits suivants pour les rubriques et les cinq derniers bits pour les sous-rubriques :

c c c c c b b b b b b a a a a a
|         |           |
|         |           > Menu                                     [menu]
|         > Item                                             [rubrique]
> SubItem                                               [sous-rubrique]

Ceci signifie qu'Intuition peut manipuler "seulement" un maximum de 31 menus, chacun avec un maximum de 63 rubriques et chaque rubrique avec un maximum de 31 sous-rubriques. Je ne pense pas que ceci puisse entraîner des limitations dans vos programmes.

Si un champ est égal à 0, cela indique qu'on a à faire au (à la) premier (première) menu/rubrique/sous-rubrique ; si un champ est égal à 1, ceci indique qu'on a à faire au(à la) second(e) et ainsi de suite. Si tous les bits sont mis à 1, cela veut dire qu'aucun(e) menu/rubrique/sous-rubrique n'a été sélectionné(e). Voyez l'exemple suivant :

Le chiffre de menu 0xF803 signifie aucune sous-rubrique, la première rubrique, dans le quatrième menu.

0xF803 (h) = 1111 1000 0000 0011 (b)

Menu number  11111 000000 00011  (b)
             |     |      |
             |     |      >  00011 =  3 = fourth Menu
             |     >        000000 =  0 = first Item
             >               11111 = 31 = NOSUB

Pour calculer ceci, vous devrez employer les macros d'Intuition suivantes :
  • MENUNUM( 0xF803 ) == 3 le quatrième menu
  • ITEMNUM( 0xF803 ) == 0 la première rubrique
  • SUBNUM( 0xF803 ) == 31 (NOSUB)
Il vous arrivera parfois de vouloir vous y prendre autrement et de vouloir calculer votre propre numéro de menu. Vous devrez alors vous servir des macros SHIFTMENU, SHIFTITEM et SHIFTSUB qui fonctionnent à l'inverse de MENUNUM, etc. Si vous avez l'intention d'employer les fonctions OnMenu() et OffMenu() (que nous expliquons plus loin), il vous faudra envoyer un numéro de menu en tant que premier paramètre. Par exemple, si vous voulez afficher en grisé la deuxième rubrique du troisième menu, vous devrez calculer le numéro de menu de la manière suivante :

menu_number = SHIFTMENU(2) + SHIFTITEM(1) + SHIFTSUB(NOSUB);
              [3e menu]      [2e rubique]   [pas de sous-rubrique]

7.9 Les fonctions

Voici quelques fonctions couramment employées qui affectent les menus :

SetMenuStrip()

Cette fonction relie une barre de menu à une fenêtre. Rappelez-vous qu'il vous faudra ouvrir une fenêtre avant d'y rattacher une barre de menu.
  • Synopsis : SetMenuStrip( my_window, my_menu );
  • my_window : (struct Window *). Pointeur sur la fenêtre à laquelle on doit rattacher la barre de menu.
  • my_menu : (struct Menu *). Pointeur sur la première structure Menu de la barre de menu.
ClearMenuStrip()

Cette fonction supprime une barre de menu dans une fenêtre. N'oubliez jamais de supprimer la barre de menu avant toute modification ou avant de fermer la fenêtre.
  • Synopsis : ClearMenuStrip( my_window );
  • my_window : (struct Window *). Pointeur sur la fenêtre dont on doit supprimer la barre de menu.
ItemAddress()

Cette fonction retourne un pointeur sur la structure Menu ou de rubrique spécifié(e) par numéro de menu.
  • Synopsis : ItemAddress( my_menu, menu_number );
  • my_menu : (struct Menu *). Pointeur sur la première structure Menu dans la barre de menu.
  • menu_number : (USHORT). Ce numéro de menu spécifie une sous-rubrique, une rubrique, un menu.
OffMenu()

Cette fonction peut désactiver une sous-rubrique, une rubrique ou même un menu entier. L'image ou le texte des rubriques, etc. désactivés s'affichera en grisé et l'utilisateur ne pourra pas les sélectionner.
  • Synopsis : OffMenu( my_window, menu_number );
  • my_window : (struct Window *). Pointeur sur la fenêtre à laquelle est reliée la barre de menu.
  • menu_number : (USHORT). Ce numéro de menu indique ce qu'on devra désactiver. Utilisez les macros SHIFTMENU, SHIFTITEM et SHIFTSUB pour calculer le bon numéro de menu. Si vous ne n'indiquez qu'un menu, toutes les rubriques de ce menu seront désactivés. Si vous indiquez un menu et une rubrique, la rubrique sera désactivée ainsi que, le cas échéant, toutes les sous-rubriques qui sont lui reliées.
OnMenu()

Cette fonction peut activer une sous-rubrique, une rubrique ou même un menu entier. L'image ou le texte des rubriques, etc. activé(e)s seront normalement affiché(e)s (ne seront pas grisé(e)s) et l'utilisateur pourra alors les sélectionner.
  • Synopsis : OnMenu( my_window, menu_number );
  • my_window : (struct Window *). Pointeur sur la fenêtre à laquelle est reliée la barre de menu.
  • menu_number : (USHORT). Ce numéro de menu indique ce qu'on devra activer. Utilisez les macros SHIFTMENU, SHIFTITEM et SHIFTSUB pour calculer correctement le numéro de menu. Si vous n'indiquez qu'un menu, toutes les rubriques de ce menu seront activées. Si vous indiquez un menu et une rubrique, la rubrique sera activée ainsi que, le cas échéant, toutes les sous-rubriques qui sont lui reliées.
7.10 Les macros

Voici quelques macros couramment employées.

Ces trois macros prennent un numéro de menu comme seul paramètre et l'analysent. Elles sont très pratiques si vous avez reçu un numéro de menu et que vous souhaitez tester quel menu et quelle rubrique ont été sélectionnés, etc. :

MENUNUM( menu_number ); est égal à 0, si le numéro de menu indique le premier menu, égal à 1 si ce chiffre indique le deuxième menu et ainsi de suite. Il est égal à "NOMENU" s'il n'indique aucun menu.

MENITEM( menu_number ); est égal à 0 si le chiffre de menu indique la première rubrique, égal à 1 si ce chiffre indique la deuxième rubrique et ainsi de suite. Il est égal à NOITEM s'il n'indique aucune rubrique.

SUBNUM( menu_number ); est égal à 0 si le chiffre de menu indique la première sous-rubrique, égal à 1 si ce chiffre indique la deuxième sous- rubrique et ainsi de suite. Il est égal à NOSUB s'il n'indique aucune sous-rubrique.

Les trois macros qui suivent font le travail inverse des trois macros précédentes. A l'aide de ces macros, vous pourrez écrire votre propre numéro de menu, en indiquant seulement le menu, la rubrique et la sous-rubrique souhaité(e)s :

SHIFTMENU( menu ); est égal au numéro de menu qui indiquera ce menu ("menu" est une valeur entre 0 et 30 ; vous mettrez "NOMENU" si vous n'indiquez aucun menu).

SHIFTITEM( item ); est égal au chiffre de menu qui indiquera cette rubrique ("item" est une valeur entre 0 et 62 ; vous mettrez NOITEM, si vous n'indiquez aucune rubrique).

SHIFTSUB( sub ); est égal au chiffre de menu qui indiquera cette sous-rubrique ("sub" est une valeur entre 0 et 30 ; vous mettrez NOSUB, si vous n'indiquez aucune sous-rubrique).

7.11 Exemples

Voici des exemples (dans le répertoire "Amiga_C_Manual/7.Menus") avec des menus :

Exemple 1

Ce programme ouvre une fenêtre normale à laquelle nous relions une barre de menu. Le menu se compose de quatre rubriques : Plain, Bold, Underlined et Italic. L'utilisateur pourra sélectionner soit Plain, soit une combinaison des autres styles (si l'utilisateur sélectionne Plain, tous les autres modes s'excluront réciproquement, mais d'un autre côté, si l'utilisateur sélectionne Bold, Underlined ou Italic, seule l'option Plain sera exclue).

Cet exemple montre aussi comment un programme doit manipuler les drapeaux IDCMP et comment on peut obtenir plusieurs messages en partant d'un événement de menu unique.

Exemple 2

Cet exemple est assez semblable à l'exemple 1 mais cette fois-ci nous avons mis les styles d'édition dans un cadre de sous-rubriques qui est relié à un seul et unique cadre de rubrique de nom "Style".

Exemple 3

Cet exemple ressemble assez à l'exemple 2 mais cette fois-ci l'utilisateur pourra aussi avoir accès aux sous-rubriques par l'intermédiaire du clavier. Par exemple, pour sélectionner Bold, l'utilisateur n'aura qu'à appuyer sur la touche "Amiga Droite" en même temps qu'il appuie sur la touche "B".

Exemple 4

Ce programme ouvre une fenêtre normale à laquelle nous relions une barre de menu. Le menu se compose de deux rubriques : ReadMode et EditMode. La rubrique ReadMode est sélectionnée et s'affichera en grisé : lorsque l'utilisateur sélectionne la rubrique EditMode, celle-ci sera invalidée (s'affichera en grisé) tandis que la rubrique ReadMode est validée (ne s'affichera plus en grisé). Ceci veut dire que l'utilisateur ne pourra choisir que le mode "EditMode" si le programme est en mode "ReadMode" et réciproquement. Le but de ce programme est de vous montrer comment utiliser les fonctions OnMenu et OffMenu pour créer une interface utilisateur "conviviale".

Exemple 5

Exactement comme l'exemple 1, si l'on excepte que nous avons changé la marque de contrôle d'Intuition en une marque personnalisée, une "flèche" de notre création.

Exemple 6

Ce programme ouvre une fenêtre normale à laquelle nous relions une barre de menu. Le menu est composé de six petits dés qui sont autant de rubriques d'action. Cet exemple vous montre comment utiliser des images à l'intérieur d'un menu.

Exemple 7

Ce programme ouvre une fenêtre normale à laquelle nous relions une barre de menu. Le menu est composé d'une seule petite rubrique d'action avec deux images.

Exemple 8

Comme l'exemple 1 mais cette fois-ci, nous allons tester toutes les opérations sur un menu. Si l'utilisateur essaie d'activer le menu de ce programme, nous essayons de savoir si la position du pointeur se trouve quelque part dans la partie supérieure de la fenêtre (moins de dix lignes en dessous). Dans ce cas, l'opération sur le menu s'effectuera normalement, autrement nous annulons l'opération en cours sur le menu.


[Retour en haut] / [Retour aux articles] [Chapitre précédent : les alertes] / [Chapitre suivant : IDCMP]