Suivez-nous sur X

|
|
|
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
|
|
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
|
|
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
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
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 :
- 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".
- 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).
- 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.
|