GFA
Vous souhaitez réagir à ce message ? Créez un compte en quelques clics ou connectez-vous pour continuer.
Le deal à ne pas rater :
Cartes Pokémon : la prochaine extension Pokémon sera EV6.5 Fable ...
Voir le deal

Stimulus 04 On passe aux choses sérieuses !

Aller en bas

Stimulus 04  On passe aux choses sérieuses ! Empty Stimulus 04 On passe aux choses sérieuses !

Message par Shadow272 Lun 16 Nov - 15:08

On passe aux choses sérieuses !
Initiation au GEM en GFA (2)




Je n'ai pas tout dit la dernière fois !

Si l'on a bien vu qu'en GEM, il fallait appeler les fonctions AES et VDI existantes, il fallait aussi se passer de certaines fonctions que le GFA nous livre d'office :
toutes les fonctions OPENW, CLOSEW...
toutes les fonctions utilisant ON MENU xxx GOSUB...
(et celles utilisant le Ligne A, tant qu'à faire...)
Ces fonctions sont adaptées au bons vieux ST(E), mais sont si dépendantes du système, que sous MagiC (par exemple), ça donne des résultats catastrophiques.
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 !

Si dans le temps, on testait rez%=XBIOS(4) pour connaître la hauteur et la largeur de l'écran. Cela est maintenant déconseillé, qu'autant qu'il y a une foule de résolutions possibles (je vous écris cet article en 832*592*256c).
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

Votre fichier ressource est un fichier externe. Il faut donc le charger en mémoire et récupérer les adresses des différents arbres qui le composent. On fait donc :
~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%).
Il faut donc libérer assez de votre mémoire pour pourvoir charger le ressource. Ce qui suit n'est pas du GEM mais un peu de bibouille GFA.
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 !

Si en GEM il y a une fonction à maîtriser à la perfection, c'est bien EVNT_MULTI(...). Elle constitue le coeur de programme GEM, va récupérer tous les messages que le Screen manager (ou un autre programme en multitâche) va fournir. Il peut s'agir d'un clic souris, d'une frappe au clavier... On va la regarder en détails :
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 :
bit 0 : le clavier MU_KEYBD
bit 1 : la souris MU_BUTTON
bit 2 : l'événement 1 MU_M1 (presque jamais employé)
bit 3 : l'événement 2 MU_M2 (idem)
bit 4 : les messages MU_MESAG (TRES important, permet la gestion des fenêtres, du menu, les échanges inter-applications, etc...)
bit 5 : le temps MU_TIMER (ceci permet de quitter EVNT_MULTI tous les delai& pour faire autre chose. exemples : le text-scrolling dans la fenêtre "Informations" de mon Joe, le nettoyage régulier da la mémoire interne avec ~FRE() et ~FRE(0), ou l'affichage de l'heure dans une horloge Smile )
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
ENDIF
Rien 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 Smile.


Et on manipule les objets comme des dieux ...

J'ai été trop rébartabif la dernière fois. Après relecture, ça devait bien être compliqué à piger. Vous avez compris qu'il y avait des fonctions pour manipuler les objets : OB_STATE pour les différents états comme la sélection, l'ombrage, l'outline... OB_FLAGS pour leur aspect 3D, leur comportement ou si on le veux caché...
OB_SPEC est un peu plus complexe et dépend du type de l'objet (OB_TYPE).
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 :

bit 0 : sélecté (1) ou non (0)
bit 1 : il y a une croix
bit 2 : checké (comme dans les menus)
bit 3 : inactivé (comme dans les menus)
bit 4 : outliné
bit 5 : ombré
Tout ça, vous le retrouvez mille et une fois dans les doc-devs.
Je vous donne quand même les champs de bit pour OB_FLAGS, mais cela ne vous dispense pas d'obtenir par tous les moyens cette doc-dev :
bit 0 : sélectionnable
bit 1 : par défaut (lorsqu'on tape Return au clavier)
bit 2 : exit (indispensable pour la fonction FORM_DO)
bit 3 : éditable (attention, ça ne marche que pour certains objets : les FTEXT et FBOXTEXT, sinon c'est deux bombes)
bit 4 : bouton radio (vous cliquer sur un bouton, les autres se déselectionnent tous seuls, il faut que ceux-ci soient dans le même objet-parent)
bit 5 : lastob (je sais pas à quoi ça sert)
bit 6 : exit (on peut l'employer aussi comme le bit 2, mais il n'y a pas encadrement supplémentaire de l'objet)
bit 7 : caché (très utile si on veut faire plusieurs formulaires en un façon zin00, ou cacher certaines options)
bit 8 : indirect. pas utilisé en GFA, ça sert à appeler une fonction qui va faire plein de choses. lors de l'affichage de cet objet, il y aura par exemple une routine de dessin appelée pour tracer un rond ombré au lieu du carré qu'on avait dessiné sous l'éditeur de ressource)
bit 9 et 10 : 3D (le fonctionnement n'est pas facile à expliquer et je m'y perds moi-même dans cette gestion)
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 :

On prend l'état de l'objet (OB_STATE(adtree%(1),5))
On efface ou on allume le bit qu'on veut (BSET(OB_STATE(adtree%(1),5),0))
Et on réinjecte tout ça dans ce qu'on avait au départ. (OB_STATE(adtree%(1),5)=BSET(OB_STATE(adtree%(1),5),0))
A vous le choix des armes. Si votre objet n'a qu'un état : 1ère méthode, mais s'il en a plusieurs : 2ème méthode.

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; :

écrire coordonnees_souris&=5, c'est donc une variable, qui consommera plus de mémoire qu'une constante
se passer du nom et écrire 5, quitte à s'emméler les pinceaux plus tard.
En GFA, ces deux solutions sont possibles. Pour les gros ressources, la première méthode est souhaitable et ressemble au C. Pour les petits, j'aurai tendance à préférer la seconde option. (j'imprime toujours ce *.H ou *.DEF pour vérifier l'exactidude des index).
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 ?

Allez voir le source GFA dans le dossier Bonus.
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
Shadow272
Shadow272
Admin

Messages : 329
Date d'inscription : 28/12/2017
Age : 65
Localisation : Hainaut Belgique

http://toutatari.blog4ever.xyz/

Revenir en haut Aller en bas

Revenir en haut

- Sujets similaires

 
Permission de ce forum:
Vous ne pouvez pas répondre aux sujets dans ce forum