Suivez-nous sur X

|
|
|
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,
ALL
|
|
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
|
|
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
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
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 liste de balises 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, le décalage 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 liste de balises 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
|
|