Pour charger un ressource, l'AES offre une fonction : rsrc_load(). Sachez que l'AES utilise la variable d'environnement 'PATH' pour chercher le ressource. Ainsi, on peut placer tout les fichiers ressources dans un seul répertoire, par exemple: 'PATH=C:\bin;C:\GEMSYS\RSC'. Notez que certain programme utilise leur propre routine de chargement de ressource et n'utilise pas la variable PATH ce qui est une erreur.
Les versions de l'AES les plus récentes (depuis la version 3.4) (TOS Falcon)utilise un nouveau format de fichier ressource dit ressource étendu. Les nouveautés sont:
Comme nous l'avons dit précédemment, les ressources étendus n'intègre pas de nouveaux objets. Toutefois, l'AES permet de coder ses propres objets et cela quelquesoit la version des AES sur les machines Atari. C'est pourquoi, il existe plusieurs bibliothèque GEM proposant des nouveaux objets. Citons par exemple MyDials ou BiG et la liste est assez longue! En général, ces librairies offrent des boutons rond, ou carré avec une croix dedans, des cadres titre, du texte avec des attributs tel que gras, souligné etc ...
Nous exposons ici les techniques pour programmer des objets :Les objets GEM sont constitués d'une arborescence de structure OBJECT. Cette arboresence donne le contenu et la hiérarchie d'un formulaire. Les deux champs qui nous intéresse ici sont le type de l'objet 'ob_type' et le champ 'ob_spec' qui pointe vers des données spécifique à chaque type d'objet.
typedef struct { int ob_next; int ob_head; int ob_tail; unsigned int ob_type; unsigned int ob_flags; unsigned int ob_state; long ob_spec; int ob_x; int ob_y; int ob_width; int ob_height; } OBJECT;
Les objets utilisateurs possède le type G_USERDEF (24). Ces objets ont leur champs 'ob_type' qui pointe vers une structure 'USERBLK' dont voici la déclaration C:
typedef struct { int cdecl (*ub_code)(struct __parmblk *parmblock); long ub_parm; } USERBLK;
Certains compilateurs définissent cette structure sous le nom APPBLK (dont il semble que ce soit le nom officiel donné par Atari). Cette structure possède deux champs. Le premier, 'ub_code', est l'adresse de la routine qui est appelé par l'AES pour dessiner l'objet.
Disgression : Les dessins des objets se font par l'intermédaire des fonctions objc_draw() et objc_change() à deux exceptions toutefois : les formulaires de fond de bureau et les toolbars (depuis l'AES 4.1) sont directement dessinés par l'AES.
La routine reçoit en paramètre un pointeur sur la structure:
typedef struct __parmblk { OBJECT *pb_tree; int pb_obj; int pb_prevstate; int pb_currstate; int pb_x, pb_y, pb_w, pb_h; int pb_xc, pb_yc, pb_wc, pb_hc; long pb_parm; } PARMBLK;
Cette structure est mise à jour par l'AES et nous servira à dessiner notre objet. La valeur de retour a aussi une importance que nous soulignerons dans le paragraphe suivant.
Le second paramètre, 'ub_parm', est un paramètre laissé libre à l'utilisateur. Il sera recopié dans la variable 'parmblock' passé à la routine de dessin dans le champs 'pb_parm'.
Pour obtenir plus d'information sur notre objet, il suffit de faire référence à 'parmblk->pb_tree[parmblk->pb_index]'.
Les champs pb_prevstate et pb_currstate permettent de savoir si l'on doit rédessiner complètement un objet (cas où pb_prevstate == pb_currstate) ou bien si l'on doit changer seulement un ou plusieur état.
La routine doit retourner un entier. Cette entier indique à l'AES que sont les états qu'il doit redessiné par dessus notre objet! Si on retourne 0, l'AES ne fera rien. Les états DISABLED, OUTLINED, CROSSED, CHECKED sont pris en compte par L'AES mais pas SHADOWED et SELECTED.
Voici un exemple de routine d'objet, un simple bouton. Ce code amenera quelques commentaires.
exemple pour PureC/Gccextern int handle; /* id de la station de travail virtuelle */ int cdecl bouton( PARMBLK *pblk) { int xy[4]; char *txt = (char *)pblk->ub_parm; /* Masquons notre objet */ xy[0] = pblk -> pb_xc; xy[1] = pblk -> pb_yc; xy[2] = pblk -> pb_wc + xy[0] - 1; xy[3] = pblk -> pb_hc + xy[1] - 1; vs_clip( handle, 1, xy); if( pblk -> pb_oldstate == pblk -> pb_currstate) { /* Dessinons le cadre */ vswr_mode( app.handle, MD_REPLACE); vsf_interior( handle, WHITE); vsf_perimeter( handle, 1); xy[0] = pblk -> pb_x; xy[1] = pblk -> pb_y; xy[2] = pblk -> pb_w + xy[0] - 1; xy[3] = pblk -> pb_h + xy[1] - 1; v_bar( handle, xy); /* Dessinons le texte (centré) */ vqt_extend(handle, str, xy); /* taille du texte */ v_gtext( handle, pblk -> pb_x + (pblk -> pb_w - xy[2] + xy[0])/2, pblk -> pb_y + (pblk -> pb_h + hcar), str); res = 0; } else { res = pblk->currstate & (DISABLED|OUTLINED|CROSSED|CHECKED|SELECTED); } vs_clip( handle, 0, tab); /* pour que l'aes redessine les autres états */ return res; }
La variable handle est l'identificateur VDI d'une station de travail virtuelle. Vous pouvez utiliser celui ouvert par l'AES (donné par la fonction graf_handle()) mais il est recommandé d'utiliser sa propre station (fonction v_opnvwrk()).
L'opération de masquage est hautement recommandé en particulier. On trouve ce masquage avec les fonctions objc_draw() et objc_change() qui demande une zone de masque en paramètre. Le masquage sera tres important lors d'intégration des formulaires dans des fenêtres.
Par contre, on ne pas utiliser les fonctions objc_draw() ou objc_change() dans une routine USERBLK sous peine de plantage. De plus, les variables locales utilisé dans les routine userblk doivent être réduit au minimun, il faut utilisez plutot des variables globales.
Après codages des nouvelles routines, il faut ensuite les installer dans les objets. La plupart des librairies GEM utilise le type étendu des objets. Il s'agit de l'octet de poid fort du champs ob_type de la structure OBJECT. En effet le GEM ne regarde que l'octet de poid faible, ce qui laisse donc cet octet libre. Il suffit maintenant d'attribuer un type étendu qui caractérisera la routine à un objet.
Pour notre routine de bouton, on pourra prendre un objet de type bouton et lui attribué le type etendue 18 par exemple. Il faudra également récupérer le texte du bouton et le passer à la routine d'où l'utilité du champ ub_parm de USERBLK.
#define G_BOUTON 18 /* cette routine utilise le type etendus des objets pour installer la routine correspondante dans un formulaire */ void InstallUserblk( OBJECT *tree) { int dum=-1; int xtype; int type; int bouton( PARMBLK *); /* definier les autres routines */ USERBLK *pblk; do { dum ++; xtype = (tree[dum].ob_type & 0xFF00)>>8; type = tree[dum].ob_type & 0x00FF; switch( xtype) { case G_BOUTON: pblk = (USERBLK*)malloc(sizeof(USERBLK)); tree[dum].ob_type = xtype | USERDEF; pblk -> ub_code = bouton; pblk -> ub_code = (long)tree[dum].ob_spec; tree[dum].ob_spec = (long) pblk; break; /* gerer les autres routines */ } } while( !(tree[dum].ob_flags & LASTOB)); }Bien sur, il faudra coder une autre routine pour librérer la mémoire alloué (les malloc) avant de terminer le programme.