• Aucun résultat trouvé

4.3 Exemples

4.3.1 Le d´eplacement

Nous pr´esentons la technique d’interaction ´el´ementaire de d´eplacement d’un objet dont le comportement r´ealise le protocole translate. Ce protocole, outre les m´ethodesbeginetend, propose une unique m´ethode,translate, qui d´eplace l’objet concern´e d’un vecteur pass´e en argument.

Principe

La technique d’interaction que nous utilisons est la plus simple de l’in-teraction graphique : grˆace au curseur, li´e `a la position de la souris, on peut “attraper” les objets d´eplac¸ables en enfonc¸ant le bouton gauche de la souris lorsque le curseur les d´esigne. Les d´eplacements du curseur translatent alors l’objet concern´e tant que le bouton n’est pas relˆach´e.

80 CHAPITRE 4. LES MACHINES `A ´ETATS HI ´ERARCHIQUES 01 hsm Translater { 02 [*button/hsm::Button::cast] : Translating 03 04 hsm Idle { 05 - button > Translating 06 } 07 08 hsm Translating { 09 - button > Idle 10 11 hsm Op{

12 var hsm::SVGLWindow *window; 13 in point;

14

15 var hsm::Translate *op = 0; 16 var hsm::Point origin(2); 17

18 require

19 ((op = window->pick< hsm::Translate >(*point/hsm::Point::cast))

20 != 0)

21 else

22 Nop

23

24 require (op->begin()) else Nop 25

26 enter { origin = *point/hsm::Point::cast; }

27 leave { op->end(); } 28 29 - point { 30 hsm::Point delta(2); 31 delta = *point/hsm::Point::cast; 32 delta -= origin; 33 op->translate(delta); 34 origin += delta; 35 } 36 } 37 38 hsm Nop {} 39 } 40 }

FIG. 4.11 – HSM traduisant les actions de la souris en d´eplacement d’un objet

R´ealisation

La Figure 4.11 montre le code qui r´ealise la technique d’interaction. Il consiste en une quarantaine de lignes. La premi`ere ligne d´eclare la HSM de haut niveauTranslater. La ligne 2 permet de synchroniser la machine avec ses entr´ees lors de son initialisation en modifiant son ´etat initial en fonction de l’´etat de ses entr´ees. En effet, la machineTranslatercomporte deux ´etats : IdleetTranslatingqui sont actifs respectivement quand le bouton de la souris est relˆach´e et quand il est enfonc´e. Si, lors de l’initialisation de la ma-chine, le bouton est enfonc´e, l’´etat initial devient alorsTranslating.

Les lignes suivantes (4 `a 6) d´efinissent l’´etat Idle. Dans cet ´etat, il ne se passe rien tant qu’aucun ´ev´enement provenant du bouton n’est rec¸u. La ligne 5 attend un tel ´ev´enement et sp´ecifie que la machine passe dans l’´etat Translatinglors de sa r´eception. L’´etatTranslatingest d´efini `a partir de la ligne 8. Il commence par d´efinir une transition semblable `a la pr´ec´edente, mais ayant pour cible l’´etatIdle. Ainsi, les ´ev´enements venant du bouton font basculer alternativement de l’´etatIdle`a l’´etatTranslating. Ces deux transitions, associ´ees `a la condition de synchronisation vue ci-dessus, nous assurent ainsi de la coh´erence de ces ´etats avec l’´etat du bouton de la souris.

4.3. EXEMPLES 81

01 hsm::SVGLWindow *window = new hsm::SVGLWindow("test"); 02 window->setDocument("test.svg");

03

04 hsm::Device *pointer = hsm::repository::getDevice("Pointer"); 05

06 Translater::Hsm translater(window,

07 *pointer/"buttons"/hsm::ButtonPad::L, 08 *pointer/"position");

FIG. 4.12 – Initialisation de la machine `a ´etats

Le sous-´etat initial deTranslating,Op(ligne 11), r´ealise l’op´eration de translation proprement dite. Il commence par d´efinir les variables et l’entr´ee dont il a besoin (lignes 12 `a 16). Il d´efinit ensuite deux pr´econditions qui doivent ˆetre v´erifi´ees pr´ealablement `a l’entr´ee dans cet ´etat :

– pour les lignes 18 `a 22, il faut qu’un objet dont le comportement r´ealise le protocoleTranslatablesoit pr´esent dans la fenˆetre sous le point initial de l’interaction ; et

– pour la ligne 24, il faut que cet objet accepte l’interaction dont le d´ebut lui est signifi´e `a l’aide du protocole ´el´ementaire begin/end.

Si l’une de ces conditions n’est pas remplie, la machine passe dans l’´etatNop (ligne 38) dans lequel il ne se passe plus rien. Les ´etatsOpetNoppermettent donc de rester dans l’´etatTranslatingen accord avec le bouton de la sou-ris, mais en effectuant ou non l’interaction de translation suivant qu’un objet r´eceptif `a l’interaction est trouv´e ou non sous le curseur.

Dans le cas o `u un tel objet est trouv´e, l’´etatOpdevient effectivement actif. La ligne 26 permet alors de m´emoriser l’origine du d´eplacement. La ligne 27 permettra de terminer l’interaction lorsque l’´etat sera quitt´e. La transition d´efinie ensuite, lignes 29 `a 35, est invoqu´ee `a chaque modification de la posi-tion du curseur. Elle d´eplace l’objet d’un vecteur correspondant `a la diff´erence entre la position actuelle du curseur et sa position `a l’´etape pr´ec´edente. Cette transition ne modifie pas l’´etat courant, puisqu’elle n’a pas d’´etat cible ; les actionsenteretleavene sont donc pas activ´ees lors de son franchissement. On peut remarquer qu’aucune transition ne permet de sortir de l’´etatOp. C’est en fait la transition deTranslating(ligne 9) qui provoquera la sor-tie de cet ´etat (ou celle de son fr`ereNop) lorsque le bouton sera relˆach´e. Le code de l’actionleaveappartenant `a l’´etatOp(ligne 27) sera alors invoqu´e et terminera l’interaction avec l’objet actuel.

Utilisation

La machine `a ´etats hi´erarchique, une fois d´efinie, peut-ˆetre utilis´ee en donnant explicitement ses entr´ees. La Figure 4.12 comporte le code minimal qui utilise cette machine `a ´etats pour interagir avec le contenu d’une fenˆetre charg´e `a partir d’un fichier SVG. Les lignes 1 `a 3 cr´eent cette fenˆetre et y chargent un document SVG `a partir d’un fichier. La ligne 5 r´ecup`ere le com-posant du pointeur syst`eme (la souris par d´efaut). Enfin, les lignes 7 `a 9 tialisent la machine `a ´etats en lui passant ses variables et ses entr´ees non ini-tialis´ees. Ces derni`eres, lignes 8 et 9, sp´ecifient que l’on va utiliser le bouton gauche de la souris et sa position pour activer et contr ˆoler le d´eplacement.

82 CHAPITRE 4. LES MACHINES `A ´ETATS HI ´ERARCHIQUES 01 hsm ConstrainedTranslater { 02 [*shift/hsm::Button::cast] : Constrained 03 04 in point; 05 in p = point; 06 07 hsm Normal { 08 hsm Translater; 09 - shift > Constrained 10 } 11 12 hsm Constrained {

13 var hsm::Point constr(2); 14 in point = &constr; 15 var hsm::Point origin(2); 16

17 enter { constr = origin = *p/hsm::Point::cast;}

18

19 local void constrain(hsm::Point &c, 20 const hsm::Point &o,

21 const hsm::Point &p) { /* d´etails omis */ }

22

23 - p { constrain(constr, origin, *p/hsm::Point::cast); }

24

25 hsm Translater; 26 - shift > Normal 27 }

28 }

FIG. 4.13 – Sp´ecialisation du d´eplacement en d´eplacement contraint

R´eutilisation

La technique pr´ec´edente est simple. Elle peut cependant servir de base pour r´ealiser des variantes plus complexes. Il est par exemple possible de la r´eutiliser telle quelle en l’englobant au sein d’une autre machine pour alt´erer son comportement. Ici, le d´eplacement deviendra contraint selon les axes ho-rizontaux et verticaux d`es que la touche shift sera enfonc´ee, reproduisant ainsi une contrainte classiquement propos´ee dans les ´editeurs graphiques.

La Figure 4.13 montre cette extension de la technique pr´ec´edente. La machine principale ConstrainedTranslater comporte deux sous-´etats, NormaletConstrained. L’appui de la touche shift permet de passer de l’un `a l’autre, comme le permettait le bouton dans l’exemple pr´ec´edent. Chacun des ´etats inclut la machineTranslatertelle quelle (lignes 8 et 25), sans la red´efinir. L’´etatNormal(lignes 7 `a 10) se limite `a cette inclusion puisqu’il ne modifie pas son comportement.

L’´etat Constrained (lignes 12 `a 27) est un peu plus compliqu´e puis-qu’il doit adapter la position qui sert d’entr´ee `a sa version de la machine Translaterpour la contraindre. L’identification des entr´ees d’une machine reposant sur leur nom, la position contrainteconstr(d´efinie ligne 13) doit ˆetre identifi´ee `a l’entr´ee point pour ˆetre prise en compte par la machine Translater. Cette identification est faite ligne 14. Cette position contrainte est alors mise `a jour d`es que la position d’entr´ee de la machinepest modifi´ee grˆace `a la transition de la ligne 23, ce qui alimente la machineTranslater en ´ev´enements. La contrainte est exprim´ee grˆace `a une m´ethode locale `a l’´etat qui n’est pas d´etaill´ee ici mais dont le prototype est donn´e ligne 19.

Ainsi, `a l’int´erieur de la machineConstrainedTranslater, et de l’´etat Normal, l’entr´ee pointfait r´ef´erence `a la position du curseur, et p est un

4.3. EXEMPLES 83

FIG. 4.14 – D´eplacement (haut) et redimensionnement (bas) multiplex´es `a l’aide d’un control menu

simple alias de cette entr´ee d´efini ligne 5. Dans l’´etat Constrained, cet alias reste visible, ce qui permet de connaˆıtre les d´eplacements r´eels du cur-seur, mais l’entr´eepointest volontairement masqu´ee par le point contraint. Grˆace `a ce masquage, c’est ce point contraint qui est utilis´e comme entr´ee pour le sous-´etatTranslater. L’objet est alors manipul´e en respectant un d´eplacement strictement horizontal ou strictement vertical suivant la direc-tion dans laquelle l’amplitude du mouvement du curseur depuis l’origine est la plus importante.