Initiation au GEM en GFA (2)
Je n'ai pas tout dit la dernière fois !
Programmer GEM, c'est avant tout être propre donc on emploie les fonctions qui ressemblent au C (~WIND_GET, evnt&=EVNT_MULTI...), et si celles-ci n'existent pas en GFA, on se les bricole très facilement (on verra ça plus loin).
La belle époque du XBIOS(4) est révolue !
On passe donc par :
~WIND_GET(0,4,xscreen&,yscreen&,lscreen&,hscreen&)Cette ligne retourne dans les ?_screen& les coordonnées AES de l'écran, donc l'espace dans lequel vous pourrez travailler. Vous avez remarqué qu'il y a xscreen& et yscreen&, qui ne sont pas forcément nuls : l'écran de travail commence sous une zone que vous connaissez bien : la barre de menu.
Si on est propre : interdiction formelle d'écrire sur cette barre de menu. C'est
propriété réservée du Screen Manager (ap_id&=1 et qui s'occupe de traiter vos
fonctions GEM, alors faut être gentil avec).
Ben comment on la place, notre barre de menu ? suffit de regarder dans la doc-dev : )
~MENU_BAR(adresse_menu%,code&)si code& à 1 : activation, si à 0 : désactivation. Une ligne, donc, suffit pour faire afficher ou enlever un menu. Par contre ce menu ne sera pas construit dans votre programme GFA, mais à l'aide de l'éditeur de ressource.
Gérer ses resources
~RSRC_LOAD(chemin_et_nom_fichier_ressource$)C'est tout ! Le GEM s'occupe de faire la réservation mémoire à votre place et la charge en mémoire. Il faut ici se rappeler d'une chose importante : cette réservation mémoire se fait dans une zone en dehors de la mémoire interne du programme (en compilé, sinon du GFA en interprété). C'est un adr%=GEMDOS(72,L:taille%).
Le GFA (compilé sans options ou interprété) réserve toute la mémoire au lancement de votre programme. Tout le monde fait ça, mais ensuite on calcule ce qu'il nous faut de mémoire pour notre programme, et ensuite on réduit notre zone mémoire pour en laisser au système et à d'autres programmes. Ce n'est pas automatique en GFA et il faut donc faire un RESERVE marge% quelque part, après l'initialisation des variables, des chaînes de texte (remplies) et des tableaux. On peut ensuite faire un RSRC_LOAD. Cette pratique est la plus propre (si on peut parler de propreté en GFA au niveau de la mémoire). De même, cela impose ensuite de faire ses propres réservations mémoires par appel au système (adr%=GEMDOS(72,l:taille%)).
Passé cette légère disgression, on peut étudier :
~RSRC_GADDR(0,0,adr%)Cette fonction se situe après ~RSRC_LOAD et va pêcher l'adresse du premier arbre dans le ressource et la dépose dans adr%. Pour avoir la suite, il faut répéter cette fonction. Pour plus de commodités, j'ai l'habitude de faire :
FOR i%=0 to nombre_arbre%-1 ~RSRC_GADDR(0,0,adr_tree%(i%)) NEXT i%Ça me facilite grandement la vie et la gestion des arbres du ressource. Donc pour déclarer votre menu, si c'est l'arbre en première position dans le ressource : ~MENU_BAR(adr_tree%(0),1). (le 1 est le code pour activer, pas le numéro de l'arbre. On fait comme en C: la première valeur d'un tableau est machin%(0))
Notez que si la zone mémoire interne au GFA est automatiquement libérée
quand on quitte son application GFA, ce n'est pas le cas pour les réservations
mémoire déclarées au système.
Donc :
si adr%=GEMDOS(72,l:taille%) alors ~GEMDOS(73,l:adr%)
si ~RSRC_LOAD(ressource$) alors ~RSRC_FREE()
sinon, c'est le foutoir dans la mémoire de votre Atari, parce qu'il reste des zones
mémoires encombrant tout et qui ne servent plus à rien.
Quand je vous disais d'être propre ;-) En fait, beaucoup de débutants
rebuttent sur de tels problèmes ne sachant pas que quand on déclare quelque
chose, il faut déclarer sa destruction. Pareil dans la vie, quand on va aux toilettes,
on produit son petit kakinou, (on se torche en passant)
et on appuie sur la chasse d'eau. On oublie trop souvent de nettoyer ses cochonneries en GFA,
vu qu'on a une trop grande marge de manoeuvre.
Me demande si j'ai pas pris un bon exemple. Quoi qu'il en soit, votre programme n'est et ne sera jamais de la merde. (mille excuses).
Je voudrais ajouter un problème philosophique : pour ceusses qui seraient réticents à se plier à ces contraintes. Je leur dit que la liberté humaine passe par un certain nombre de règles. Il n'y a pas de liberté sans loi. Qu'elles soient justes ou pas n'est pas la question ici. Pour la programmation en particulier, respecter les appels systèmes et le fonctionnement de l'OS sont contraignants et lourds à digérer, mais une fois l'expérience acquise, vous pourrez faire des merveilles en GEM comme l'auteur de CAB, d'EB Model ou Papyrus. Et on a la chance d'avoir un OS facile à ronger. Sur zin00, c'est (à ce qu'on m'a dit) à se fracasser contre les murs.
On est des Ataristes oui ou non ?
Et on est à l'écoute de tout !
evnt&=EVNT_MULTI(masque_message%,n_clic&,masque_clic&,etat_clic&,... ...etat_1&,x1&,y1&,l1&,h1&,etat_2&,x2&,y2,l2&,h2&,... ...adresse_buffer%,delai&,[mo_x&,mo_y&,mo_k&,... ...etat_clavier%,touche_clavier%,mo_c&])Ce qui se trouve entre crochets sont des variables de retours (facultatives) comme evnt&, les autres sont des paramètres obligatoires.
masque_message% | C'est un masque de bit qui va indiquer à EVNT_MULTI quoi surveiller :
|
evnt& | Variable de retour de la fonction qui indique qu'est-ce qui s'est produit selon
le masque_message%. Si c'est une frappe au clavier, alors evnt&=1 Si c'est un clic souris, alors evnt&=2 Si c'est un message du Screen manager, alors evnt&=16 Si c'est un clic souris + Control appuyé, alors evnt&=1+2=3 Si c'est le temps qui passe avec un message du Screen manager, alors evnt&=32+16=48 Vous avez bien compris qu'ici, il faut tester les bits de evnt& pour la gestion des événements. Donc : IF BTST(evnt&,0) ' gestion clavier ENDIF IF BTST(evnt&,4) ' gestion fenetres, menu, et divers ENDIF IF BTST(evnt&,5) ' je fais ce qui me plait ENDIFRien ne vous empêche d'aiguillonner votre gestion avec BTST(evnt&,0) AND BTST(evnt&,1) |
n_clic& | Nombre de clic souris maximum, en général 2 |
masque_clic& | masque qui sert à scruter les boutons souris (bit 0 : bouton gauche,
bit 1 : bouton droit). malheureusement, il y a un bug qui ne permet pas l'utilisation du
bouton droit. une astuce permet de contourner ce bug, elle est légale mais un peu
compliquée pour le débutant. Donc ici, en général 1. Je mets parfois 0, ce qui m'évite d'employer MU_TIMER pour mes pop-up et c'est plus rapide. |
etat_clic& | C'est l'état clic attendu (bouton enfoncé). Bit 0=1 si gauche
doit être enfoncé, bit 1=1 si droit enfoncé. en général, etat_clic&=1 |
etat_1&,x1&,y1&,l1&,h1& | ces paramètres définissent un état (0=entrée,
1=sortie) et une zone de l'écran. Permet donc de déinir un
événement si la souris entre dans un cadre ou en sort. Vu que pas grand monde l'utilise, c'est 0,0,0,0,0. |
etat_2&,x2&,y2&,l2&,h2& | Idem, pour une deuxième zone. |
adresse_buffer% | Adresse d'une zone tampon de 16 octets (prière de faire un GEMDOS(72)
merci) dans lequel le Screen manager va déposer tout plein de choses. Messages
fenêtres, messages menu, messages provenant d'autres applications, shut down, drag and
drop... Si BTST(evnt&,4)=TRUE, alors il faudra récupérer ce qu'il y a dedans. INT{adresse_buffer%+0}=type& du message, qui est une valeur à connaître car ce qui suit dépend de cette valeur INT{adresse_buffer%+2}=id& identificateur de l'application qui a déposé le message. 1 pour le Screen manager une valeur>1 si c'est une autre application ça peut carrément être votre ap_id& (très utile pour provoquer un rafraichissement de ses propres fenêtres par exemple) INT{adresse_buffer%+4}=0 en général non nul si la longueur du buffer dépasse les 16 octets INT{adresse_buffer%+6} à INT{adresse_buffer%+12}: infos précises selon le type& du message |
delai& | Délai en millisecondes pour MU_TIMER, passé ce délai,
EVNT_MULTI rend la main à votre programme, c'est à dire que BTST(evnt&,5)=TRUE et
que vous pouvez appeler les routines que vous voulez. en général, on done 100 à 1000 ms. on ne va jamais en dessous de 10, parce votre Atari chéri ne sera jamais aussi rapide pour gérer ça. |
Variables de retour | |
mo_x& | Coordonnée en X de la souris |
---|---|
mo_y& | Coordonnée en Y de la souris |
mo_k& | Bouton(s) cliqué(s) 1 pour le gauche, 2 pour le droit, 3 pour les deux ensembles |
etat_clavier% | champ de bits correspondant à une touche spéciale enfoncée (Control, Shifts, Alternate) |
touche_clavier% | valeur sur 32 bits contenant le code
ASCII de la touche enfoncée (non spécifique au langage du pays) et son scan-code
(spécifique au langage du pays). Pour obtenir le code ASCII, on fait code_ascii|=BYTE(touche_clavier%). |
mo_c& | nombre de clic(s) effectués. 1 si clic, 2 si double clic (si vous n'aviez pas compris :). |
Et on manipule les objets comme des dieux ...
OB_STATE (comme OB_FLAGS) est un champ de bit. donc vous pouvez cumuler les états de l'objet. Je vous donne les codes, mais c'est bien parce que c'est vous :
Problème pratique des champs de bits, c'est quoi donc ? En C, tout est facile, mais en
GFA, il faut parfois se fracasser la tête contre son ours en peluche.
Faites OB_STATE(adtree%(1),5)=1. Vous aurez ainsi sélectionné l'objet
5 dans le deuxième arbre. Ya un blème s'il était ombré et
checké, parce que ces états vont disparaître.
Solution :
Dernière précision avant de finir : vous pouvez nommer vos objets dans
l'éditeur de ressource. L'éditeur, lors de la sauvegarde du ressource,
crée alors un fichier *.H ou *.DEF qui fera correspondre le nom d'un objet à son
index (ou code) dans l'arbre.
C'est pratique en C, car avec un #DEFINE coordonnees_souris 5, on se passe de
l'écriture du code 5, et on écrit dans son source C "coordonnees_souris".
C'est et ça reste quoi qu'il arrive un constante.
Malheureuseuement en GFA, on a pas droit au DEFINE, on est donc obligé soit de; :
Il existe une autre solution que m'a suggéré mon gourou d'Emmanuel BARANGER : utiliser ERGO-PRO, un shell pour le GFA qui permet entre-autres de traiter son source GFA et d'y faire pas mal de choses.
Et si nous bidouillons ensemble, là tout de suite ?
Et si vous n'avez toujours pas vos doc-dev à côté de vous la prochaine fois, c'est deux heures de colle ! Vous avez droit au Compendium cédérom, au TOS.HYP, au GFABASIC.HYP, au livre du développeur...
Rajah Lone
nef@mygale.org
écrit le 22 Juin 1998