GEM les jeux de mots

Au menu ce moi-ci : la gestion des champs éditables. Vaste et sensible sujet puisque cette partie du GEM n'est vraiment pas à l'aise pour le multitâche et les boîtes de dialogue en fenêtres.
C'est-y quoi un champ éditable ? Ben un objet GEM (donc manipulable avec un éditeur de ressource classique et surtout par les fonctions GEM du GFA). C'est là où vous rentrez vos chaînes de texte ou quelques chiffres au clavier.

Je disais plus haut que cette gestion était difficile avec des dialogues non bloquants. Ça m'a valu quelques déboires et gros bugs pour la programmation de Blaise (l'éditeur de texte pour POV si ça ne vous dit rien) et les remontrances J.J.A dans STMAG. Je vous livre donc mon expérience, que vous étudirez en détails dans le source fourni dans le dossier BONUS. L'article que vous êtes en train de survoler se bornera ici à décrire les fonctions et les deux ou trois avertissements dont :

Attention les bugs !

Bugs vicieux s'il en est puisque la fonction OBJC_EDIT donne 2 zolies bombes si l'objet n'est pas un champ éditable. Faites donc attention aux valeurs que vous donnez à cette fonction car c'est primordial.

Avant on bloquait l'AES avec les WIND_UPDATE, dessinait le formulaire avec FORM_DIAL et on appelait la fonction FORM_DO qui gérait tout : boutons dialogue, boutons radio, et surtout champs éditables. Maintenant que nous sommes grands, il faut manier OBJC_EDIT directement :

`~OBJC_EDIT(ad_tree%,index_objet&,char&,old_pos&,flag&,new_pos&)`

il y a une variable de retour : `0` indique une erreur, mais s'il erreur il y a c'est plutôt un crash très sérieux. Donc pas la peine de s'en occuper, on fait donc un void ou `~` (pour les amateurs du C, les paramètres sont disposés différemment).

`ad_tree%` | adresse de l'arbre, obtenue avec RSRC_GADDR si vous n'avez pas suivi l'épisode précédent. vous verrez dans mon code que j'utilise un tableau.
`index_objet&` | index de l'objet GEM dans l'arbre. Si vous vous plantez et que vous donnez un index qui ne correspond pas à un champ éditable : 2 bombes. Si cela vous ennuie, vous pouvez augmenter la sécurité en testant avec OB_TYPE la nature de l'objet avant de faire l'appel à OBJC_EDIT. Cela vous évite beaucoup de déboires mais cette solution de facilité ne facilite pas les débugages. J'utilise dans l'exemple fourni une VARIABLE. pas une constante déguisée ni de chiffre brut qui correspond à l'objet. C'est là toute la difficulté. si bien sûr vous n'avez qu'un champ éditable, utilisez la constante-index.
`char&` | Ici c'est une valeur du caractère ASCII qui sera inséré dans la chaîne. Cette valeur sera récupérée à partir du EVNT_MULTI général. Les docs m'indiquent même qu'on peut fournir un scan-code, c'est à dire directement la valeur sans bidouillage. On peut employer les valeurs ASCII en dessous de 32, dont 27=Esc qui efface le champ éditable entier ou Del ou Backspace ou les (shift)+flèches... Le GEM c'est bien !
`old_pos&` | C'est l'anciennce position du curseur dans le champ éditable, si vous gérez donc plusieurs champs éditables dans votre formulaire, il faut donc un tableau pour pouvoir avoir les valeurs quelque part à 1 dimension. Si vous gérez plusieurs formulaires avec champs éditables, votre tableau sera à 2 dimensions comme vous verrez dans le source.
`flag&` | type de la manipulation que vous voulez faire à l'objet : `0` : `ED_START`, pas touche, c'est réservé à l'AES. `1` : `ED_INIT`, pose du curseur. `2` : `ED_CHAR`, insertion du caractère. `3` : `ED_END`, le curseur s'efface. `103` : spécifique à MagiC, il s'agit du mode `3` mais le curseur est dessiné en mode XOR, ce qui est plus pratique en mutlitâche. Personnellement, je n'utilise pas, ça dépend de vos goûts.
`new_pos&` | nouvelle position du curseur, ce n'est pas forcément +1, car avec `char&=27` par exemple, ce sera 0.

Les fonctions maison

Car bien sûr, pour faire comme avant, il faut gérer les flèches haut et bas, c'est à dire passer d'un champ à l'autre (et pourquoi pas avec Tab tant qu'on y est).
Et comment déterminer l'objet éditable du formulaire ? hein ? Il faut donc bricoler du code :

- Trouver le premier champ éditable de l'arbre
- Trouver le suivant
- Trouver le précédent
- Effacer et faire apparaître le curseur

Il en existe d'autres, mais qui sont moins spécifiques ou intégrées dans d'autres partie du code.
A noter qu'il n'y a pas besoin de redraw de l'objet (fonction maison `black_white`) car `OBJC_EDIT(flag&=2)` le fait lui-même.

La difficulté

Et quand le GEM fait son redraw, il ne s'occupe pas de la liste des rectangles pour faire son clipping. L'ancienne méthode avec FORM_DO n'utilisant pas de fenêtre, les concepteurs du GEM ne se sont pas forcés à rendre OBJC_EDIT propre au niveau du clipping : il redessine entièrement l'objet.

L'objet édité doit donc être en premier plan. Forcément, quand on tape au clavier, c'est pour le programme qui a fenêtre au premier plan. Sauf...

Avant vous étiez prévenu de tout. Vous l'êtes encore, mais il existe de nouveaux messages AES. Dans l'offset 2 du buffer recevant les messages AES, vous étiez prévenu avec WM_TOPPED (code 21) qu'il fallait activer votre fenêtre pour la mettre au premier plan. Remarque : WM_NEWTOP (code 29), bien que documenté est inutilisé.

Avec la gestion du multitâche et l'arrivée des fenêtres "non activables" (pas besoin de cliquer une première fois si elle est en arrière plan pour accéder à son contenu), de nouveaux messages sont apparus :

- WM_UNTOPPED (code 30) : la fenêtre passe en arrière plan. Pratique pour restaurer une palette de couleurs.
- WM_ONTOP (code 31) : notez l'absence du "ED" à la fin. Vous n'avez rien à faire, le GEM active pour vous la fenêtre ! Vous n'avez même pas à faire WIND_SET avec WF_TOP (code 10) pour l'activer...

Activation du GEM de votre fenêtre ? Ben, si vous n'avez pas tenu compte de ce message, vous pouvez alors faire un OBJC_EDIT en arrière plan, et là c'est pas bô.
Pire : vous pouvez avoir la bonne fenêtre en avant plan (car par prudence vous interrogez WIND_GET toujours avec WF_TOP (code 10)) et garder l'ancien index de l'objet dans l'ancienne fenêtre. Résultat : 2 bombes si vous ne tombez pas sur un objet éditable.

Donc, on prend la peine d'interroger les fonctions maison (1er object éditable) quand ces messages AES arrivent.

Dur, dur d'être apprenti !

Au début c'est dur, mais une fois qu'on a le coup de main : c'est génial.
Exemples :

- Intercepter la valeur ASCII avant l'insertion avec OBJC_EDIT(`flag&=2`), vous récupérer cette valeur et insérez à la place "*". But ? faire un champ éditable spécial mot de passe.
- Modifier le champ éditable qui gère une valeur, avec d'autres événements et objets GEM. Vous cliquez sur l'objet "plus haut", la valeur augmente, vous cliquez sur "plus bas", la valeur diminue, et vous pouvez également la modifier au clavier.

Si j'ai encore la force avant le bouclage : ça doit se trouver dans l'exemple.

Les champs éditables...

Car le GEM peut filtrer ce que vous insérer dans le champ éditable. Il peut aussi gérer une sorte de masque (regardez certains formulaires avec des dates par exemple). Ces préférences sont à régler dans l'éditeur de ressource quand vous créez l'objet.
C'est dans la doc de l'éditeur de ressource, donc vous possédez déjà ces informations. Pour ceusses qui l'ont pas :

- Text : correspond à la chaîne que vous éditez avec OBJC_EDIT. C'est celle-ci que vous récupérez. Pendant la création, remplissez le texte avec n'importe quoi (mais avec la longueur voulue, sinon problèmes de mémoire si ça dépasse). Je remplie personnellement avec `01234567890123...`, ça a l'avantage d'indiquer le nombre de caractères.

  Lors de l'initialisation de votre programme, videz cette chaîne ou déposez un chaîne de texte par défaut avec `CHAR{{OB_SPEC(..)}}=machin$`, comme on l'a vu auparavant (pointeur sur pointeur, souvenez-vous !).

- Template : il s'agit d'une sorte de masque, remplissez avec les "~" (même longueur que Text) et insérez du vrai texte, par exemple "~~/~~/~~" pour une date.
  Dans Text, ce sera donc "012345" (6 caractères).

- Validation : ici très important, ce doit être une copie du texte éditable (Text) mais remplacé par des caractères spéciaux. Ces caractères spéciaux indiquent au GEM le type de filtrage. Exemples :
  - "X" permet l'insertion de n'importe quel caractère avec OBJC_EDIT.
  - "9" ne permet qu'insérer que des chiffres.
  - etc... A vous de connaître si besoin ces valeurs magiques.

Donc, pour résumer cela donnera dans l'éditeur de ressource (NB : WERCS, car je viens de m'apercevoir que c'est différent avec RSC3 par exemple) :

      Text:       012345     (01~23~45 avec RSC3)
      Template:   ~~/~~/~~
      Validation: 999999     (99~99~99 avec RSC3)

C'est joli tout plein, car vous ne pourrez insérez que des chiffres et sans taper le slash ! Cool, non ? La seule contrainte est de manipuler vos chaînes sous la forme "010398" pour le 1er Mars 1998 lorsque vous voulez écrire ou récupérer avec CHAR{{OB_SPEC()}} la chaîne éditée.

Au revoir !

Etudiez bien le LST fourni dans EXEMPLE2.ZIP . Gérer les champs éditables n'est pas une mince affaire et il faut penser à chaque éventualités qui peuvent se poser.
N'hésitez pas à me mailer en cas de besoin, ou si vous désirez que je traite un sujet particulier...

nef@mygale.org

Rajah Lone
écrit à la bourre le 19 Septembre 1998