Obligement - L'Amiga au maximum

Lundi 25 septembre 2017 - 17:20  

Translate

En De Nl Nl
Es Pt It Nl


Rubriques

 · Accueil
 · A Propos
 · Articles
 · Galeries
 · Glossaire
 · Hit Parade
 · Liens
 · Liste jeux Amiga
 · Quizz
 · Téléchargements
 · Trucs et astuces


Articles

 · Actualité (récente)
 · Actualité (archive)
 · Comparatifs
 · Dossiers
 · Entrevues
 · Matériel (tests)
 · Matériel (bidouilles)
 · Points de vue
 · En pratique
 · Programmation
 · Reportages
 · Tests de jeux
 · Tests de logiciels
 · Tests de compilations
 · Articles divers

 · Articles in english
 · Articles in other languages


Twitter

Suivez-nous sur Twitter




Liens

 · Sites de téléchargements
 · Associations
 · Pages Personnelles
 · Moteurs de recherche
 · Pages de liens
 · Constructeurs matériels
 · Matériel
 · Autres sites de matériel
 · Réparateurs
 · Revendeurs
 · Presse et médias
 · Programmation
 · Développeurs logiciels
 · Logiciels
 · Développeurs de jeux
 · Jeux
 · Autres sites de jeux
 · Scène démo
 · Divers
 · Informatique générale


Jeux Amiga

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Trucs et astuces

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Glossaire

0, A, B, C, D, E, F,
G, H, I, J, K, L, M,
N, O, P, Q, R, S, T,
U, V, W, X, Y, Z


Partenaires

Annuaire Amiga

Amedia Computer

Relec

Hit Parade


Contact

David Brunet

Courriel

 


Programmation : Assembleur - création d'interfaces graphiques GadTools
(Article écrit par Frédéric Delacroix et extrait d'Amiga News - mars 1995)


Voici ce mois-ci un petit algorithme permettant la création d'interfaces graphiques par GadTools. Bien qu'inspiré par le code source généré par GadToolsBox, il a l'avantage sur celui-ci d'être très optimisé, de permettre une certaine compression de données et une grande souplesse.

Présentation

La gadtools.library fait partie de la ROM depuis le Kickstart 2.0. Son rôle est de faciliter la création de gadgets et de menus, ainsi que leur gestion par un programme, tâche possible avec la seule couche Intuition mais hautement non triviale. Nous ne nous intéresserons qu'aux gadgets cette fois-ci.

Pour créer un gadget, on utilise une structure nommée "NewGadget" qui contient les informations importantes comme la position du gadget, sa taille, son étiquette, la position de celle-ci, la police à utiliser... On fournit également au moment de l'appel de "CreateGadget()" des attributs spécifiques supplémentaires (comme une liste d'étiquettes pour un gadget cyclique ou un caractère à souligner dans le label du gadget) sous la forme d'une liste de tags et un identificateur de type. Je vous renvoie à la documentation officielle pour plus de détails sur la marche à suivre ; ce n'est pas le propos de cet article.

Le défaut de cette méthode est qu'il faut, pour chaque gadget, initialiser (dynamiquement à cause du champ "gng_VisualInfo") une structure NewGadget, et appeler tour à tour "CreateGadgetA()" avec la bonne taglist et le bon type pour chaque gadget. Bien entendu, gadtools.library ne gère pas automatiquement les raccourcis clavier, la localisation des étiquettes et surtout l'adaptation automatique à la police de l'écran. C'est le but du modeste fragment de programme que je vous propose ici.

L'algorithme

Le but était ici de n'initialiser que les champs nécessaires : par exemple, on ne stocke qu'une fois la largeur et hauteur de chaque gadget pour une rangée de boutons tous identiques. Concrètement, on utilise une table (une de ces tables très compactes quasiment impossibles à gérer en C) contenant, successivement pour chaque gadget, l'offset de la structure NewGadget à initialiser, le type de données à y placer : mot, mot long, mot + largeur du bord gauche, identificateur de chaîne localisée, valeur à calibrer avec la hauteur de la police... et enfin la donnée elle-même. La fin d'un gadget est repérée par un octet égal à -1. Suivent son type et un pointeur sur la taglist associée.

Grâce au second paramètre (type de donnée, ne pas confondre avec le type de gadget), on peut prévoir un traitement spécial pour chaque donnée ; c'est ce qui confère sa grande souplesse à cet algorithme. C'est précisément ceci qui permet de repérer les valeurs qui doivent être adaptées à la taille de la police. Il est, en effet, très désagréable de voir apparaître une fenêtre en Topaz/8 sur un écran entrelacé ou DBLPAL. Pour cela, on dessine l'interface comme si la police de caractères utilisée était de taille 8 par 8 (comme Topaz/8), puis, au moment de la création, une simple règle de trois calcule la taille finale. Ceci doit affecter la position des gadgets et leur taille uniquement, d'où l'apparition de "flags" spéciaux dans le paramètre type (voir code source). Petit inconvénient : cela ne marche qu'avec les polices de caractères non proportionnelles (pour les autres, la meilleure solution est MUI).

De plus, pour chaque gadget, le raccourci clavier est la première lettre de l'étiquette (elle n'est bien sûr pas affichée), elle est stockée dans une table, ce qui permet un test facile par la boucle principale, et une localisation facile. Enfin, chaque gadget a un identificateur différent, incrémenté par rapport au gadget précédent, la fin de la table étant détectée lorsque cet identificateur atteint le nombre de gadgets.

Associé à la routine (Amiga News n°74) d'ouverture d'une fenêtre sur l'écran public frontal, c'est le genre de routine qui rend une interface graphique très conviviale, et ce sans la lourdeur d'un système ultra-puissant comme MUI.

Exemple

L'exemple du mois ne sert à rien, il se contente d'ouvrir une fenêtre sur l'écran public par défaut avec quatre gadgets, le seul réellement utilisé étant celui qui permet de quitter le programme. La police de caractères utilisée est celle de l'écran pourvu qu'elle ne soit pas proportionnelle. J'ai également ajouté un début de gestion du clavier. Bien entendu, cet exemple ne demande qu'à être amélioré...

                        opt          AMIGA
                        include      exec/execbase.i
                        include      exec/alerts.i
                        include      intuition/intuition.i
                        include      graphics/text.i
                        include      libraries/gadtools.i
                        include      libraries/gadtools_lib.i

Start                   move.l       4.w,a6
                        move.l       ThisTask(a6),a4
                        tst.l        pr_CLI(a4)
                        bne.s        FromCLI
                        lea          pr_MsgPort(a4),a0
                        jsr          _LVOWaitPort(a6)
                        lea          pr_MsgPort(a4),a0
                        jsr          _LVOGetMsg(a6)
                        move.l       d0,WB.Startup

FromCLI                 lea          Intuition.Name(pc),a1
                        moveq        #37,d0 ; eh oui
                        jsr          _LVOOpenLibrary(a6)
                        move.l       d0,Intuition.Base
                        bne.s        IntuitionOK
                        move.l       #AT_Recovery!AG_OpenLib!AO_Intuition,d7
                        jsr          _LVOAlert(a6)
                        bra.s        exit
IntuitionOK
                        lea          Graphics.Name(pc),a1
                        moveq        #37,d0
                        jsr          _LVOOpenLibrary(a6)
                        move.l       d0,Graphics.Base
                        beq.s        CloseIntuition
                        lea          GadTools.Name(pc),a1
                        moveq        #37,d0
                        jsr          _LVOOpenLibrary(a6)
                        move.l       d0,GadTools.Base
                        beq.s        CloseGraphics
                        lea          DOS.Name(pc),a1
                        moveq        #37,d0
                        jsr          _LVOOpenLibrary(a6)
                        move.l       d0,DOS.Base
                        beq.s        CloseGadTools

                        bsr.s        OpenMainWindow
                        beq.s        WindowError
                        bsr          ProcessMessages
WindowError
                        bsr          CloseMainWindow

CloseDOS
                        move.l       DOS.Base(pc),a1
                        move.l       4.w,a6
                        jsr          _LVOCloseLibrary(a6)
CloseGadTools
                        move.l       GadTools.Base(pc),a1
                        jsr          _LVOCloseLibrary(a6)
CloseGraphics
                        move.l       Graphics.Base(pc),a1
                        jsr          _LVOCloseLibrary(a6)
CloseIntuition
                        move.l       Intuition.Base(pc),a1
                        jsr          _LVOCloseLibrary(a6)
exit                    move.l       WB.Startup(pc),d1
                        beq.s        ToCLI
                        move.l       d1,a1
                        jsr          _LVOForbid(a6)
                        jsr          _LVOReplyMsg(a6)
ToCLI                   moveq        #0,d0
                        rts

OpenMainWindow          ; (Z)Succès=OpenMainWindow()
                        suba.l       a0,a0 ; écran par défaut
                        move.l       Intuition.Base(pc),a6
                        jsr          _LVOLockPubScreen(a6)
                        move.l       d0,Window.Screen
                        beq          .Failure
                        move.l       d0,a0

                        move.l       sc_Font(a0),a0
                        btst         #FPB_PROPORTIONAL,ta_Flags(a0)
                        beq.s        .GoodFont
                        lea          Topaz8.TextAttr(pc),a0
.GoodFont
                        move.l       a0,NewGadget.Struct+gng_TextAttr
                        move.l       Graphics.Base(pc),a6
                        jsr          _LVOOpenFont(a6)
                        move.l       d0,a1
                        move.l       a1,d0
                        beq         .Failure
                        move.w       tf_YSize(a1),Font.YSize
                        move.w       tf_XSize(a1),Font.XSize
                        jsr          _LVOCloseFont(a6)

                        move.l       Window.Screen(pc),a0
                        suba.l       a1,a1
                        move.l       GadTools.Base(pc),a6
                        jsr          _LVOGetVisualInfoA(a6)
                        move.l       d0,Screen.VisualInfo
                        beq          .Failure

                        move.l       Window.Screen(pc),a0
                        moveq        #0,d3           ;taille du bord gauche de la
                        move.l       d3,d2           ;fenêtre
                        move.b       sc_WBorLeft(a0),d2
                        move.l       sc_Font(a0),a1  ;taille du bord haut
                        move.w       ta_YSize(a1),d3
                        addq.w       #1,d3
                        add.b        sc_WBorTop(a0),d3
                        lea          Window.GadgetList(pc),a0
                        jsr          _LVOCreateContext(a6)
                        move.l       d0,a3
                        move.l       a3,d0
                        beq          .Failure
                        lea          NewGadget.Values(pc),a5
                        lea          Window.Gadgets(pc),a4
                        moveq        #0,d4           ;identificateur de gadget
.FillNextGadget
                        lea          NewGadget.Struct(pc),a1
                        move.w       d4,gng_GadgetID(a1)
.FillNewGadget
                        moveq        #0,d0
                        move.l       d0,d1
                        move.b       (a5)+,d0
                        move.b       (a5)+,d5
                        move.b       d5,d1
                        and.b        #~$C0,d1         ;masque bits de scale
                        beq.s        .TransferLong    ;0=Long,
                                                      ;1=Word,
                                                      ;2=Word+D2
                                                      ;3=Word+D3
                        cmp.l        #4,d1
                        beq.s        .LocalizedString ;4=Localized string
                        move.w       (a5)+,0(a1,d0.w)

                        bclr         #7,d5
                        beq.s        .NoScaleHeight
                        move.w       0(a1,d0.w),d5
                        ext.l        d5
                        mulu         Font.YSize(pc),d5
                        lsr.l        #3,d5
                        move.w       d5,0(a1,d0.w)
                        bra.s       .ScaleDone
.NoScaleHeight
                        bclr         #6,d5             ;scale to font width ?
                        beq.s        .NoScaleWidth
                        move.w       0(a1,d0.w),d5
                        ext.l        d5
                        mulu         Font.XSize(pc),d5
                        lsr.l        #3,d5
                        move.w       d5,0(a1,d0.w)
.NoScaleWidth
.ScaleDone

                        cmp.b        #2,d1
                        bne.s        .NoD2
                        add.w        d2,0(a1,d0.w)
.NoD2                   cmp.b        #3,d1
                        bne.s        .NoD3
                        add.w        d3,0(a1,d0.w)
.NoD3
                        bra.s        .TransferDone
.TransferLong
                        move.l       (a5)+,0(a1,d0.w)
                        bra.s        .TransferDone
.LocalizedString
                                                           ;inutilisé ici

.TransferDone
                        cmp.b        #-1,(a5)
                        bne          .FillNewGadget
                        addq.l       #1,a5
                        move.l       gng_GadgetText(a1),a0 ;raccourci 
                                                           ;clavier
                        move.b       (a0)+,d0
                        move.l       a0,gng_GadgetText(a1)
                        lea          Gadget.Shortcuts(pc),a0
                        move.b       d0,0(a0,d4)

                        moveq        #0,d0
                        move.b       (a5)+,d0
                        move.l       (a5)+,a2
                        move.l       a3,a0
                        jsr          _LVOCreateGadgetA(a6)
                        move.l       d0,a3
                        move.l       d0,(a4)+
                        beq.s        .Failure
                        addq.w       #1,d4
                        cmp.l        #Window.GadgetCount,d4
                        bne          .FillNextGadget

                        move.l       #WINDOWWIDTH,d0
                        mulu         Font.XSize(pc),d0
                        lsr.l        #3,d0
                        move.l       d0,Window.Width
                        move.l       #WINDOWHEIGHT,d0
                        mulu         Font.YSize(pc),d0
                        lsr.l        #3,d0
                        move.l       d0,Window.Height

                        lea          Window.NewWindow(pc),a0
                        lea          Window.Tags(pc),a1
                        move.l       Intuition.Base(pc),a6
                        jsr          _LVOOpenWindowTagList(a6)
                        move.l       d0,Window.Window
                        beq.s        .Failure
                        move.l       d0,a0
                        suba.l       a1,a1
                        move.l       GadTools.Base(pc),a6
                        jsr          _LVOGT_RefreshWindow(a6)
                        moveq        #-1,d0
                        rts

.Failure
                        moveq        #0,d0
                        rts

CloseMainWindow
                        move.l       Window.Window(pc),d0
                        beq.s        .NoWindow
                        move.l       d0,a0
                        move.l       Intuition.Base(pc),a6
                        jsr          _LVOCloseWindow(a6)
.NoWindow
                        move.l       Window.GadgetList(pc),d0
                        beq.s        .NoGadgets
                        move.l       d0,a0
                        move.l       GadTools.Base(pc),a6
                        jsr          _LVOFreeGadgets(a6)
                        clr.l        Window.GadgetList
.NoGadgets
                        move.l       Screen.VisualInfo(pc),d0
                        beq.s        .NoVI
                        move.l       d0,a0
                        move.l       GadTools.Base(pc),a6
                        jsr          _LVOFreeVisualInfo(a6)
                        clr.l        Screen.VisualInfo
.NoVI                   move.l       Window.Screen(pc),d0
                        beq.s        .NoScreen
                        move.l       d0,a1
                        suba.l       a0,a0
                        move.l       Intuition.Base(pc),a6
                        jsr          _LVOUnlockPubScreen(a6)
                        clr.l        Window.Screen
.NoScreen
                        rts

ProcessMessages
                        move.l       sp,QuitStack
.Wait                   move.l       Window.Window(pc),a2
                        move.l       wd_UserPort(a2),a0
                        move.l       4.w,a6
                        jsr          _LVOWaitPort(a6)
.MsgL                   move.l       Window.Window(pc),a2
                        move.l       wd_UserPort(a2),a0
                        move.l       GadTools.Base(pc),a6
                        jsr          _LVOGT_GetIMsg(a6)
                        move.l       d0,a1
                        move.l       a1,d0
                        beq.s        .Wait
                        move.l       im_Class(a1),d7
                        move.w       im_Code(a1),d6
                        move.l       im_IAddress(a1),a4
                        jsr          _LVOGT_ReplyIMsg(a6)
                        cmp.l        #IDCMP_REFRESHWINDOW,d7
                        bne.s        .NoRefresh
                        move.l       a2,a0
                        jsr          _LVOGT_BeginRefresh(a6)
                        move.l       a2,a0
                        moveq        #-1,d0
                        jsr          _LVOGT_EndRefresh(a6)
                        bra.s        .MsgL
.NoRefresh
                        cmp.l        #IDCMP_GADGETUP,d7
                        bne.s        .NoGad
                        move.l       gg_UserData(a4),d0
                        beq.s        .MsgL
                        move.l       d0,a0
                        jsr          (a0)
                        bra.s        .MsgL
.NoGad                  cmp.l        #IDCMP_VANILLAKEY,d7
                        bne.s        .MsgL
                        lea          Gadget.Shortcuts(pc),a0
                        lea          Shortcuts.Funcs(pc),a1
.NextK                  move.l       (a1)+,a2
                        move.b       (a0)+,d1
                        beq.s        .MsgL
                        cmp.b        d6,d1
                        bne.s        .NextK
                        jsr          (a2)
                        bra          .MsgL

QuitK                   moveq        #ID_QUIT_BUTTON,d0
                        bsr.s        ActivateButton
QuitClicked
                        move.l       QuitStack,sp
                        rts
But1K                   moveq        #ID_BUTTON1_BUTTON,d0
                        bra.s        ActivateButton
But2K                   moveq        #ID_BUTTON2_BUTTON,d0
ActivateButton          ;ActivateButton(GadgetID)(D0)
                        movem.l      d0-d1/a0-a3/a6,-(sp)
                        lsl.l        #2,d0
                        lea          Window.Gadgets(pc),a0
                        move.l       0(a0,d0.w),a0
                        move.l       a0,a3
                        or.w         #GFLG_SELECTED,gg_Flags(a0)
                        moveq        #1,d0
                        move.l       Window.Window(pc),a1
                        suba.l       a2,a2
                        move.l       Intuition.Base(pc),a6
                        jsr          _LVORefreshGList(a6)
                        moveq        #10,d1
                        move.l       DOS.Base(pc),a6
                        jsr          _LVODelay(a6)
                        move.l       a3,a0
                        and.w        #~GFLG_SELECTED,gg_Flags(a0)
                        moveq        #1,d0
                        move.l       Window.Window(pc),a1
                        move.l       Intuition.Base(pc),a6
                        jsr          _LVORefreshGList(a6)
                        movem.l      (sp)+,d0-d1/a0-a3/a6
                        rts

NewGadget.Values
                        ENUM
                        EITEM        ID_QUIT_BUTTON
                        dc.b         gng_LeftEdge,2+64
                        dc.w         4
                        dc.b         gng_TopEdge,3+128
                        dc.w         4
                        dc.b         gng_Width,1+64
                        dc.w         40
                        dc.b         gng_Height,1+128
                        dc.w         12
                        dc.b         gng_GadgetText,0
                        dc.l         Quit.Label
                        dc.b         gng_Flags,0
                        dc.l         PLACETEXT_IN
                        dc.b         gng_UserData,0
                        dc.l         QuitClicked
                        dc.b         -1,BUTTON_KIND
                        dc.l         Quit.Button.Tags

                        EITEM        ID_NAME_STRING
                        dc.b         gng_TopEdge,3+128
                        dc.w         20
                        dc.b         gng_Width,1+64
                        dc.w         200
                        dc.b         gng_GadgetText,0
                        dc.l         Name.Label
                        dc.b         gng_Flags,0
                        dc.l         PLACETEXT_BELOW
                        dc.b         gng_UserData,0
                        dc.l         0
                        dc.b         -1,STRING_KIND
                        dc.l         Name.String.Tags
                        EITEM        ID_BUTTON1_BUTTON
                        dc.b         gng_TopEdge,3+128
                        dc.w         60
                        dc.b         gng_Width,1+64
                        dc.w         64
                        dc.b         gng_GadgetText,0
                        dc.l         Button1.Label
                        dc.b         gng_Flags,0
                        dc.l         PLACETEXT_IN
                        dc.b         -1,BUTTON_KIND
                        dc.l         Button1.Button.Tags

                        EITEM        ID_BUTTON2_BUTTON
                        dc.b         gng_LeftEdge,2+64
                        dc.w         140
                        dc.b         gng_GadgetText,0
                        dc.l         Button2.Label
                        dc.b         -1,BUTTON_KIND
                        dc.l         Button2.Button.Tags
                        EITEM        Window.GadgetCount      ;fini

Name.String.Tags
                        dc.l         GTST_MaxChars,30
                        dc.l         GTST_String,Name.Default
Quit.Button.Tags
Button1.Button.Tags
Button2.Button.Tags
                        dc.l         GT_Underscore,'_'
                        dc.l         TAG_DONE

Window.Gadgets          dcb.l        Window.GadgetCount,0

Window.NewWindow
                        dc.w         0,12,208,80
                        dc.b         -1,-1
                        dc.l         IDCMP_GADGETUP!IDCMP_VANILLAKEY!
                                                  IDCMP_REFRESHWINDOW
                        dc.l         WFLG_DRAGBAR!WFLG_DEPTHGADGET!
                                               WFLG_SIMPLE_REFRESH!
                                               WFLG_ACTIVATE
Window.GadgetList       dc.l         0,0,Window.Title
Window.Screen           dc.l         0,0
                        dc.w         208,80,208,80
                        dc.w         PUBLICSCREEN

WINDOWWIDTH             EQU          208
WINDOWHEIGHT            EQU          80

Window.Tags
                        dc.l         WA_InnerWidth
Window.Width            dc.l         208
                        dc.l         WA_InnerHeight
Window.Height           dc.l         80
                        dc.l         TAG_DONE

NewGadget.Struct        dcb.b        gng_SIZEOF,0
Screen.VisualInfo=NewGadget.Struct+gng_VisualInfo

Topaz8.TextAttr
                        dc.l         Topaz.Name
                        dc.w         8
                        dc.b         FS_NORMAL,0

Font.YSize              dc.w         0
Font.XSize              dc.w         0

Intuition.Base          dc.l         0
Graphics.Base           dc.l         0
GadTools.Base           dc.l         0
DOS.Base                dc.l         0
WB.Startup              dc.l         0
Window.Window           dc.l         0
QuitStack               dc.l         0

Shortcuts.Funcs         dc.l         QuitK,0,But1K,But2K

Gadget.Shortcuts        dcb.b        Window.GadgetCount+1,0

Intuition.Name          dc.b         'intuition.library',0
Graphics.Name           dc.b         'graphics.library',0
GadTools.Name           dc.b         'gadtools.library',0
DOS.Name                dc.b         'dos.library',0
Topaz.Name              dc.b         'topaz.font',0
Quit.Label              dc.b         'q_Quit',0
Name.Label              dc.b         1,'Nom',0
Button1.Label           dc.b         '1Bouton_1',0
Button2.Label           dc.b         '2Bouton_2',0
Name.Default            dc.b         'Entrez votre nom',0
Window.Title            dc.b         'Inutilitaire',0


[Retour en haut] / [Retour aux articles] [Article précédent] / [Article suivant]