Obligement - L'Amiga au maximum

Mardi 17 octobre 2017 - 06:03  

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 : Compléments d'interfaces
(Article écrit par Damien Guichard - décembre 2004)


Dernière étape

Dans l'article précédent, on a survolé la création d'interfaces graphiques pilotées par échange de messages. Dans ce dernier article, on aborde quelques compléments de confort indispensables comme les raccourcis clavier, les AppWindows et les ports ARexx.

Raccourcis clavier

Gadtools gère tout seul les raccourcis clavier pour les menus. Les raccourcis clavier pour les gadgets ne sont pas gérés par Gadtools mais sont plutôt simulés par le programmeur.

Vous ajoutez IDCMP_VANILLAKEY dans les WA_IDCMP de votre fenêtre et vous êtes notifié chaque fois qu'une touche est pressée. Alors imsg.code contient le caractère clavier et à votre charge d'effectuer la fonction qui lui correspond dans votre programme.

Pour aider l'utilisateur à (re)connaître les raccourcis, spécifiez GT_UNDERSCORE,"_" dans la liste d'attributs de CreateGadgetA(). Et placez un "_" dans le libellé de votre gadget, de sorte que "_quitter" incite l'utilisateur à presser "q" pour quitter.

L'exemple du prochain chapitre illustre la programmation des raccourcis clavier.

AppWindows

Pour créer une AppWindow :
  • Vous devez ouvrir/fermer la workbench.library.
  • On transforme une fenêtre déjà ouverte en appwindow via AddAppWindowA().
  • Et alors on peut recevoir des appmessages.
  • appmsg.type=AMTYPE_APPWINDOW signifie un événement appwindow.
  • appmsg.numargs est le nombre d'icônes lachées dans la fenêtre.
  • appmsg.arglist sont les icônes, comme avec un WB Startup message.
  • Avant de fermer la fenêtre appelez RemoveAppWindow().
Cet exemple affiche toutes les icônes lâchées dans la ListView, utilisez le menu ou le raccourci clavier pour quitter, "new" efface la liste, l'action "save" est bidon :

OPT OSVERSION=37

MODULE 'intuition/intuition','intuition/screens','intuition/gadgetclass'
MODULE 'gadtools','libraries/gadtools'
MODULE 'wb','workbench/startup','workbench/workbench'
MODULE 'utility/tagitem','graphics/rastport'
MODULE 'exec/nodes','exec/lists'
MODULE '*gt_window'

CONST ERR_NOWB=ERR_NOWINDOW+1

DEF win:PTR TO window
DEF appwin=NIL
DEF listview=NIL
DEF labels:PTR TO mlh

DEF path[80]:STRING

PROC main() HANDLE
  DEF menu
  workbenchbase:=OpenLibrary('workbench.library',37)
  IF workbenchbase=NIL THEN Raise(ERR_NOWB)
  menu:=[NM_TITLE,0,'Project',0,0,0,0,
         NM_ITEM,0,'New','N',0,0,0,
         NM_ITEM,0,'Load...','L',0,0,0,
         NM_ITEM,0,'Save','S',0,0,0,
         NM_ITEM,0,NM_BARLABEL,0,0,0,0,
         NM_ITEM,0,'Quit','Q',0,0,0,
         0,0,0,0,0,0,0]:newmenu
  gt_openwindow({windef},menu,{winhandler})
EXCEPT DO
  IF workbenchbase THEN CloseLibrary(workbenchbase)
ENDPROC

PROC newlist()
  DEF list:PTR TO mlh
  NEW list
  list.head:=list+4
  list.tailpred:=list
ENDPROC list

PROC insert(list,name)
  AddTail(list,NEW [0,0,0,0,name]:ln)
ENDPROC

PROC windef(scr:PTR TO screen,gad,visual,glist)
  DEF offx,offy

  offx:=scr.wborleft
  offy:=scr.wbortop+scr.rastport.txheight+1

  labels:=newlist()

  gad:=listview:=CreateGadgetA(LISTVIEW_KIND,gad,
    [offx+20,offy+14,255,130,NIL,scr.font,0,0,visual,0]:newgadget,
    [GTLV_SCROLLWIDTH,20,GTLV_LABELS,labels,GTLV_SHOWSELECTED,NIL,TAG_DONE])

  gad:=CreateGadgetA(BUTTON_KIND,gad,
    [offx+20,offy+144,70,18,'_New',scr.font,"N",0,visual,0]:newgadget,
    [GT_UNDERSCORE,"_",TAG_DONE])

  gad:=CreateGadgetA(BUTTON_KIND,gad,
    [offx+112,offy+144,70,18,'_Save',scr.font,"S",0,visual,0]:newgadget,
    [GT_UNDERSCORE,"_",TAG_DONE])


  gad:=CreateGadgetA(BUTTON_KIND,gad,
    [offx+205,offy+144,70,18,'_Quit',scr.font,"Q",0,visual,0]:newgadget,
    [GT_UNDERSCORE,"_",TAG_DONE])

  IF gad=NIL THEN Raise(ERR_NOGADGET)

  win:=OpenWindowTagList(NIL,
    [WA_TITLE, 'AppWin Demo',
     WA_FLAGS,  WFLG_DEPTHGADGET+WFLG_CLOSEGADGET+WFLG_DRAGBAR+
                WFLG_SIMPLE_REFRESH+WFLG_ACTIVATE,
     WA_IDCMP,  IDCMP_CLOSEWINDOW+IDCMP_REFRESHWINDOW+IDCMP_VANILLAKEY+
                IDCMP_GADGETDOWN+IDCMP_GADGETUP+IDCMP_MOUSEMOVE+IDCMP_MENUPICK,
     WA_WIDTH,  300,
     WA_HEIGHT, offy+176,
     WA_ZOOM,   [0,offy,130,offy]:INT,
     WA_GADGETS,      glist,
     WA_NEWLOOKMENUS, TRUE,
     WA_AUTOADJUST,   TRUE,
     TAG_DONE])

  IF win
    appwin:=AddAppWindowA(0,0,win,win.userport,NIL)
  ENDIF

  RETURN win

ENDPROC

PROC itemnum(n)
ENDPROC Shr(n,5) AND $3F

PROC winhandler(msg:PTR TO appmessage,class,code,gad:PTR TO gadget) HANDLE
  IF msg.type=AMTYPE_APPWINDOW
    expand_list(msg)
    Gt_ReplyIMsg(msg)
  ELSE
    Gt_ReplyIMsg(msg)
    SELECT class
    CASE IDCMP_CLOSEWINDOW
      Raise(ERR_OK)
    CASE IDCMP_REFRESHWINDOW
      Gt_BeginRefresh(win)
      Gt_EndRefresh(win,TRUE)
    CASE IDCMP_GADGETUP
      IF gad.gadgetid="N"
        clear_list()
      ELSEIF gad.gadgetid="Q"
        Raise(ERR_OK)
      ENDIF
    CASE IDCMP_MENUPICK
      IF itemnum(code)=0 THEN clear_list()
      IF itemnum(code)=4 THEN Raise(ERR_OK)
    CASE IDCMP_VANILLAKEY
      IF code="n"
        clear_list()
      ELSEIF code="q"
        Raise(ERR_OK)
      ENDIF
    ENDSELECT
  ENDIF
EXCEPT
  IF appwin THEN RemoveAppWindow(appwin)
  Raise(ERR_OK)
ENDPROC

PROC clear_list()
  labels.head:=labels+4
  labels.tailpred:=labels
  Gt_SetGadgetAttrsA(listview,win,NIL,[GTLV_LABELS,labels,0])
ENDPROC

PROC expand_list(msg:PTR TO appmessage)
  DEF i,name
  FOR i:=0 TO msg.numargs-1
    NameFromLock(msg.arglist[i].lock,path,80)
    AddPart(path,msg.arglist[i].name,80)
    name:=String(StrLen(path))
    StrCopy(name,path)
    insert(labels,name)
  ENDFOR
  Gt_SetGadgetAttrsA(listview,win,NIL,[GTLV_LABELS,labels,0])
ENDPROC

Les AppIcons fonctionnent de façon très similaire aux AppWindows.

Serveurs ARexx

Un serveur ARexx augmente sensiblement l'interopérabilité de votre programme en exportant toutes ses fonctionnalités, ce qui permet de scripter leur utilisation et de coopérer avec une multitude d'autres programmes serveurs ARexx.

L'interaction avec ARexx se fait par la rexxsyslib.library, pour cela vous créez et nommez un port de message, ce port de message deviendra votre adresse de serveur ARexx. Pour créer ce port de message vous utilisez les fonctions CreateMsgPort() et DeleteMsgPort() de la exec.library, mais vous pouvez tout aussi bien réutiliser votre port de fenêtre. Ensuite, il suffit de définir la priorité du port de message, puis de le rendre public à l'aide de la fonction AddPort(), à la fin il faudra le retirer à l'aide de la fonction RemPort().

Si vous réutilisez votre port de fenêtre, la fonction IsRexxMsg() vous permettra de distinguer un message ARexx d'un simple message intuition.

Une fois le message rxmsg identifié comme étant un message ARexx :
  • rxmsg.args[0] est la ligne de commande.
  • Interprétez cette commande.
  • Définissez le code d'erreur rxmsg.result1 (comme une commande DOS).
  • Pour retourner une valeur placez la chaîne dans rxmsg.result2.
  • Finalement répondez avec ReplyMsg(rxmsg).
Ces quelques commandes s'inspirent de la graphics.library pour offrir un outil de dessin scriptable par ARexx :

QUIT
MOVE x y
DRAW x y
RECTFILL xmin ymin xmax ymax
ELLIPSE cx cy a b
SETPEN pen
TEXT string

Ce petite source implémente le serveur ARexx pour ces commandes :

OPT OSVERSION=37

MODULE 'exec/ports','exec/nodes','intuition/intuition'
MODULE 'rexxsyslib','rexx/storage'

ENUM ERR_OK,ERR_NOREXXSYSLIB,ERR_NOWINDOW

CONST SIGNAL_BREAK=$1000

DEF win:PTR TO window
DEF rastport
DEF xa,ya,xb,yb:LONG

PROC main() HANDLE
  rexxsysbase:=OpenLibrary('rexxsyslib.library',36)
  IF rexxsysbase=NIL THEN Raise(ERR_NOREXXSYSLIB)
  win:=OpenWindowTagList(NIL,
     [WA_TITLE,  'AREXX Paint Demo',
      WA_FLAGS,  WFLG_DEPTHGADGET+WFLG_CLOSEGADGET+WFLG_DRAGBAR+
                 WFLG_NOCAREREFRESH+WFLG_ACTIVATE,
      WA_IDCMP,  IDCMP_CLOSEWINDOW,
      WA_WIDTH,  320,
      WA_HEIGHT, 256,
      WA_AUTOADJUST, TRUE,
      NIL])
  IF win=NIL THEN Raise(ERR_NOWINDOW)
  win.userport::ln.name:='APaint.1'
  win.userport::ln.pri:=5
  AddPort(win.userport)
  rastport:=win.rport
  SetAPen(rastport,1)
  handle()
EXCEPT DO
  SELECT exception
  CASE ERR_NOREXXSYSLIB
    PrintF('Could not open rexxsyslib.library v36+ !\n')
  CASE ERR_NOWINDOW
    PrintF('Could not open window!\n')
  ENDSELECT
  IF win THEN CloseWindow(win)
  IF rexxsysbase THEN CloseLibrary(rexxsysbase)
ENDPROC

PROC handle() HANDLE
  DEF signals,winsig,iclass,imsg:PTR TO intuimessage
  DEF cmdline,rxmsg:PTR TO rexxmsg
  winsig:=Shl(1,win.userport.sigbit)
  LOOP
    signals:=Wait(winsig+SIGNAL_BREAK)
    IF signals AND winsig
      WHILE rxmsg:=imsg:=GetMsg(win.userport)
        IF IsRexxMsg(imsg)
          cmdline:=TrimStr(rxmsg.args[0])
          IF StrCmp(cmdline,'QUIT')
            rxmsg.result1:=0
            ReplyMsg(rxmsg)
            Raise(0)
          ELSEIF StrCmp(cmdline,'MOVE ',STRLEN)
            IF read_args(rxmsg,2)
              Move(rastport,xa,ya)
            ENDIF
          ELSEIF StrCmp(cmdline,'DRAW ',STRLEN)
            IF read_args(rxmsg,2)
              Draw(rastport,xa,ya)
            ENDIF
          ELSEIF StrCmp(cmdline,'RECTFILL ',STRLEN)
            IF read_args(rxmsg,4)
              IF (xb>=xa) AND (yb>=ya)
                RectFill(rastport,xa,ya,xb,yb)
              ELSE
                rxmsg.result1:=10
              ENDIF
            ENDIF
          ELSEIF StrCmp(cmdline,'ELLIPSE ',STRLEN)
            IF read_args(rxmsg,4)
              DrawEllipse(rastport,xa,ya,xb,yb)
            ENDIF
          ELSEIF StrCmp(cmdline,'SETPEN ',STRLEN)
            IF read_args(rxmsg,1)
              SetAPen(rastport,xa)
            ENDIF
          ELSEIF StrCmp(cmdline,'TEXT ',STRLEN)
            cmdline:=TrimStr(cmdline+STRLEN)
            Text(rastport,cmdline,StrLen(cmdline))
            rxmsg.result1:=0
          ENDIF
          ReplyMsg(rxmsg)
        ELSE
          iclass:=imsg.class
          ReplyMsg(imsg)
          SELECT iclass
          CASE IDCMP_CLOSEWINDOW
            Raise(0)
          ENDSELECT
        ENDIF
      ENDWHILE
    ENDIF
    IF signals AND SIGNAL_BREAK
      Raise(0)
    ENDIF
  ENDLOOP
EXCEPT
  WHILE imsg:=GetMsg(win.userport)
    ReplyMsg(imsg)
  ENDWHILE
ENDPROC

PROC read_args(rxmsg:PTR TO rexxmsg,num)
  DEF str,ch
  str:=TrimStr(rxmsg.args[0])
  WHILE str[]<>" " DO INC str
  xa,ch:=Val(str); IF ch THEN DEC num; str:=str+ch
  ya,ch:=Val(str); IF ch THEN DEC num; str:=str+ch
  xb,ch:=Val(str); IF ch THEN DEC num; str:=str+ch
  yb,ch:=Val(str); IF ch THEN DEC num; str:=str+ch
  IF num THEN rxmsg.result1:=10 ELSE rxmsg.result1:=0
ENDPROC num=0

Le Shell permet d'utiliser ces commandes de façon interactive :

 RUN >NIL: APaint
 RX "ADDRESS 'APaint.1' ELLIPSE 160 128 100 60"
 RX "ADDRESS 'APaint.1' QUIT"

Une chose que ce petit programme ne gère pas ce sont les exécutions multiples d'un même programme serveur. Dans ce cas vous voulez soit partager un même serveur soit avoir de multiples serveurs, un pour chaque tâche. Pour avoir de multiples serveurs il suffirait de les nommer Apaint.1, APaint.2, APaint.3 et ainsi de suite.

Voyez la rexxsyslib.library ainsi que rexx/storage.h pour plus d'informations sur les serveurs ARexx.

Les Gadget-Toolkits

Ce tutoriel ne couvre pas les gadget-toolkits. Cependant, voici où trouver quelques ressources et documentations pour le programmeur Amiga-E :

MUI :

de.aminet.net/aminet/dev/mui/mui38dev.lha.
de.aminet.net/aminet/dev/mui/mui38dev-E.lha.

Feelin :

www.feelin.fr.

Pour aller plus loin

Un tutoriel n'est ni exhaustif ni une référence. Un programme AmigaOS réaliste est fait de mille autres choses, non abordées ici, comme les écrans, les datatypes, les memory-pools, les processus, les devices, les fichiers IFF et bien d'autres encore. Savoir programmer c'est donc aussi savoir trouver de la documentation, et des exemples, le plus souvent en anglais. Voici quelques liens pour démarrer.

La documentation indispensable c'est les Autodocs de Commodore, et c'est encore mieux dans le format AmigaGuide : de.aminet.net/pub/aminet/dev/misc/AmigaOS_guides.lha.

Les non moins indispensables AmigaOS Includes : obligement.free.fr/files/ndk_amigaos39.lzx.

Le compilateur EC v3.3a de Wouter van Oortmerssen (version complète) : www.aminet.net/dev/e/amigae33a.lha et home.swipnet.se/blubbe/ECX.

La liste de diffusion Amiga-E : www.freelists.org/list/positron.


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