Groupe 37 — Gestionnaire de dialogues Trinity
37,1 New Dialog · 37,2 Dispose Dialog · 37,3 Dialog Event · 37,4 Get Dialog Item · 37,5 Draw Dialog · 37,6 Alert
Le gestionnaire de dialogues de la boîte à outils de Trinity construit des dialogues modaux (2 au plus) et des alertes, avec les fenêtres (groupe 34) et les contrôles (groupe 36).
Descripteur d'un dialogue, en RAM du 6502 : le Rect de la fenêtre (coordonnées de l'écran), un octet d'options (bit 0 barre de titre), le titre précédé de sa longueur ; puis jusqu'à 12 éléments terminés par un octet 0, chacun : type (1 bouton, 2 case à cocher, 3 bouton radio, 4 barre de défilement, 5 champ de texte, 6 texte fixe), options (bit 0 inactif, bit 1 par défaut, déclenché par Entrée, bit 2 annulation, déclenché par Échap), Rect relatif au contenu, maximum sur 16 bits (valeur d'une barre ou longueur d'un champ), texte précédé de sa longueur (un champ de texte réserve 1 + maximum octets ; un texte fixe passe à la ligne à chaque caractère 13).
Le dialogue des exemples : « Reglages », avec OK (par défaut), Annuler (annulation), une case « Son », un champ de texte « ab » de 8 caractères au plus et un texte fixe. Les exemples fabriquent les événements qu'ils lui passent et remettent la boîte à outils à zéro avec 32,19 au début et à la fin.
37,1 New Dialog Trinity
Construit un dialogue modal à partir d'un descripteur en RAM du 6502 et le dessine.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | addr | adresse du descripteur (lu sur place) |
| Octets | Type | Rôle |
|---|---|---|
P2 | uint8 | numéro du dialogue (1 ou 2) |
P3 | uint8 | sa fenêtre (groupe 34) |
erreur | uint8 | 1 descripteur invalide, 2 plus de dialogue, de fenêtre ou de contrôle libre |
Le descripteur (voir l'introduction) doit rester intact tant que le dialogue est ouvert : le firmware le relit et écrit dans le tampon des champs de texte. Les éléments 1 à 5 sont des contrôles du groupe 36 (voir 37,4). Les touches vont au premier champ de texte actif (Tab : au suivant). Un type d'élément inconnu est refusé. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Toolbox (Trinity, T-12, ADR-01 of the fork). Builds a modal dialog from the descriptor at Parameters:0,1 in 6502 RAM and returns its number (1-2) in Parameter:2 and its window (group 34) in Parameter:3 (error 1 bad descriptor, 2 no dialog, window or control left). The descriptor is read in place and must stay intact : the screen Rect of the window, a flags byte (bit 0 title bar), the length-prefixed title, then up to 12 items ended by a 0 byte, each : kind (1 button, 2 check box, 3 radio, 4 scroll bar, 5 text field, 6 static text), flags (bit 0 disabled, bit 1 default - fired by Return, drawn with a ring -, bit 2 cancel - fired by Escape), Rect relative to the content, a 16 bit maximum (scroll bar value / text field length) and the length-prefixed title, text or buffer (a text field reserves 1 + maximum bytes ; static text : one line per character 13). Items 1-5 are controls of group 36 (see Get Dialog Item) ; the dialog is drawn at once and again on its update events through Dialog Event. Keys go to the first enabled text field (Tab : next one).
C (llvm-mos)
/* Ouvrir un dialogue (groupe 37, fonction 1, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* Descripteur de dialogue, lu sur place : Rect de la fenêtre (écran), options (bit 0 barre de titre), titre ;
puis chaque élément : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ de texte, 6 texte fixe), options
(bit 0 inactif, bit 1 par défaut : Entrée, bit 2 annulation : Échap), Rect relatif au contenu, maximum,
texte précédé de sa longueur (un champ de texte réserve 1 + maximum octets) ; un 0 termine la liste. */
#define W(v) (v) & 0xFF, (v) >> 8
static uint8_t reglages[] = {
W(40), W(40), W(240), W(160), 1, 8, 'R', 'e', 'g', 'l', 'a', 'g', 'e', 's',
1, 2, W(130), W(90), W(190), W(104), W(0), 2, 'O', 'K', /* 1 : bouton par défaut */
1, 4, W(60), W(90), W(120), W(104), W(0), 7, 'A', 'n', 'n', 'u', 'l', 'e', 'r', /* 2 : annulation */
2, 0, W(10), W(10), W(100), W(22), W(0), 3, 'S', 'o', 'n', /* 3 : case à cocher */
5, 0, W(10), W(30), W(150), W(44), W(8), 2, 'a', 'b', 0, 0, 0, 0, 0, 0, /* 4 : champ de texte, 8 au plus */
6, 0, W(10), W(50), W(150), W(60), W(0), 7, 'B', 'o', 'n', 'j', 'o', 'u', 'r', /* 5 : texte fixe */
0 };
#define CHAMP 81 /* position du tampon de l'élément 4 dans le descripteur */
static void p16(uint8_t i, uint16_t v) { /* paramètre 16 bits en Pi, Pi+1 */
ControlPort.params[i] = v & 0xFF;
ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) { /* 32,19 Toolbox Reset */
libre();
api(32, 19);
}
static uint8_t dialogue, fenetre;
static uint8_t ouvrir(uint8_t *descripteur) { /* 37,1 New Dialog : rend l'indicateur d'erreur */
libre();
p16(0, (uint16_t)descripteur);
api(37, 1);
dialogue = ControlPort.params[2];
fenetre = ControlPort.params[3];
return ControlPort.error;
}
static void fermer(uint8_t d) { /* 37,2 Dispose Dialog */
libre();
ControlPort.params[0] = d;
api(37, 2);
}
int main(void) {
uint8_t d, w, e;
reinit();
ouvrir(reglages); /* fenêtre et contrôles créés, dessinés aussitôt */
d = dialogue; w = fenetre;
fermer(d);
reglages[18] = 9; /* type du premier élément (octet 18) : 9 n'existe pas */
e = ouvrir(reglages);
reglages[18] = 1;
reinit();
printf("Dialogue %u, fenetre %u ; type 9 : erreur %u\n", d, w, e);
return 0;
}Dialogue 1, fenetre 1 ; type 9 : erreur 1Mad Pascal
// Ouvrir un dialogue (groupe 37, fonction 1, Trinity).
program dl1;
uses crt, neo6502;
// Descripteur de dialogue (variable : le firmware écrit dans le champ de texte), lu sur place : Rect de la
// fenêtre (écran), options (bit 0 barre de titre), titre ; puis chaque élément : type (1 bouton, 2 case, 3 radio,
// 4 barre, 5 champ de texte, 6 texte fixe), options (bit 0 inactif, bit 1 par défaut : Entrée, bit 2 annulation :
// Échap), Rect relatif au contenu, maximum, texte précédé de sa longueur (un champ de texte réserve 1 + maximum
// octets) ; un 0 termine la liste.
var reglages: array[0..110] of byte = (
40, 0, 40, 0, 240, 0, 160, 0, 1, 8, ord('R'), ord('e'), ord('g'), ord('l'), ord('a'), ord('g'), ord('e'), ord('s'),
1, 2, 130, 0, 90, 0, 190, 0, 104, 0, 0, 0, 2, ord('O'), ord('K'), // 1 : bouton par défaut
1, 4, 60, 0, 90, 0, 120, 0, 104, 0, 0, 0, 7, ord('A'), ord('n'), ord('n'), ord('u'), ord('l'), ord('e'), ord('r'), // 2 : annulation
2, 0, 10, 0, 10, 0, 100, 0, 22, 0, 0, 0, 3, ord('S'), ord('o'), ord('n'), // 3 : case à cocher
5, 0, 10, 0, 30, 0, 150, 0, 44, 0, 8, 0, 2, ord('a'), ord('b'), 0, 0, 0, 0, 0, 0, // 4 : champ de texte, 8 au plus
6, 0, 10, 0, 50, 0, 150, 0, 60, 0, 0, 0, 7, ord('B'), ord('o'), ord('n'), ord('j'), ord('o'), ord('u'), ord('r'), // 5 : texte fixe
0);
const CHAMP = 81; // position du tampon de l'élément 4 dans le descripteur
var dialogue, fenetre: byte;
procedure appel(g, f: byte); // appel g,f (paramètres déjà posés)
begin
NeoSendMessage(g, f);
NeoWaitMessage;
end;
procedure reinit; // 32,19 Toolbox Reset
begin
NeoWaitMessage;
appel(32, 19);
end;
function ouvrir(descripteur: pointer): byte; // 37,1 New Dialog : rend l'indicateur d'erreur
begin
NeoWaitMessage;
wordParams[0] := word(descripteur);
appel(37, 1);
dialogue := NeoMessage.params[2];
fenetre := NeoMessage.params[3];
result := NeoMessage.error;
end;
procedure fermer(d: byte); // 37,2 Dispose Dialog
begin
NeoWaitMessage;
NeoMessage.params[0] := d;
appel(37, 2);
end;
var d, w, e: byte;
begin
reinit;
ouvrir(@reglages); // fenêtre et contrôles créés, dessinés aussitôt
d := dialogue; w := fenetre;
fermer(d);
reglages[18] := 9; // type du premier élément (octet 18) : 9 n'existe pas
e := ouvrir(@reglages);
reglages[18] := 1;
reinit;
writeln('Dialogue ', d, ', fenetre ', w, ' ; type 9 : erreur ', e);
end.Dialogue 1, fenetre 1 ; type 9 : erreur 1NeoBASIC
10 ' Ouvrir un dialogue (groupe 37, fonction 1, Trinity)
15 gosub 7000
20 gosub 8300
30 q = rg : gosub 8000 : d = dg : w = fw : ' fenetre et controles crees, dessines aussitot
40 gosub 8200
50 poke rg + 18, 9 : ' type du premier element (octet 18) : 9 n'existe pas
60 gosub 8000 : e9 = e
70 poke rg + 18, 1 : gosub 8300
80 print "Dialogue ";d;", fenetre ";w;" ; type 9 : erreur ";e9
90 end
7000 ' descripteur de dialogue, lu sur place : Rect de la fenetre (ecran), options (bit 0 barre de titre), titre ;
7005 ' puis chaque element : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ, 6 texte fixe), options (bit 0 inactif,
7010 ' bit 1 par defaut : Entree, bit 2 annulation : Echap), Rect relatif au contenu, maximum, texte precede de sa
7015 ' longueur (un champ de texte reserve 1 + maximum octets) ; un 0 termine la liste. Adresse dans rg.
7020 rg = alloc(111) : p = rg
7025 for k = 1 to 4 : read v : doke p, v : p = p + 2 : next k : read v : poke p, v : p = p + 1 : read s$ : gosub 7100
7030 for it = 1 to 5 : read ty, op : poke p, ty : poke p + 1, op : p = p + 2
7035 for k = 1 to 5 : read v : doke p, v : p = p + 2 : next k : read s$ : p0 = p : gosub 7100
7040 if ty = 5 then p = p0 + 1 + v : ' le champ reserve 1 + maximum octets
7045 next it : poke p, 0 : ch = rg + 81 : return : ' ch : tampon de l'element 4
7050 data 40, 40, 240, 160, 1, "Reglages"
7055 data 1, 2, 130, 90, 190, 104, 0, "OK" : ' 1 : bouton par defaut
7060 data 1, 4, 60, 90, 120, 104, 0, "Annuler" : ' 2 : annulation
7065 data 2, 0, 10, 10, 100, 22, 0, "Son" : ' 3 : case a cocher
7070 data 5, 0, 10, 30, 150, 44, 8, "ab" : ' 4 : champ de texte, 8 au plus
7075 data 6, 0, 10, 50, 150, 60, 0, "Bonjour" : ' 5 : texte fixe
7100 poke p, len(s$) : for i = 1 to len(s$) : poke p + i, asc(mid$(s$, i, 1)) : next i : p = p + len(s$) + 1 : return
8000 ' 37,1 New Dialog sur le descripteur q : dialogue dans dg, fenetre dans fw, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 dg = peek($ff06) : fw = peek($ff07) : return
8100 ' appel 37,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 37
8120 while peek($ff00) : wend : e = peek($ff02) : return
8200 ' 37,2 Dispose Dialog dg
8210 while peek($ff00) : wend : poke $ff04, dg : f = 2 : goto 8110
8300 ' 32,19 Toolbox Reset
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnDialogue 1, fenetre 1 ; type 9 : erreur 1Assembleur 65C02 (64tass)
; Ouvrir un dialogue (groupe 37, fonction 1, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<b0
ldx #>b0
jsr envoi
jsr ouvrir ; fenêtre et contrôles créés, dessinés aussitôt
lda dlg
sta d
lda fen
sta w
lda dlg
ldx #2 ; 37,2
jsr dial
lda #9 ; type du premier élément : 9 n'existe pas
sta type1
jsr ouvrir
sta e
lda #1
sta type1
lda #<b1
ldx #>b1
jsr envoi
lda #<t2
ldx #>t2
jsr ecrire
lda d
jsr decimal
lda #<t3
ldx #>t3
jsr ecrire
lda w
jsr decimal
lda #<t4
ldx #>t4
jsr ecrire
lda e
jsr decimal
lda #13
jsr WriteCharacter
rts
; Descripteur de dialogue, lu sur place : Rect de la fenêtre (écran), options (bit 0 barre de titre), titre ;
; puis chaque élément : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ de texte, 6 texte fixe), options
; (bit 0 inactif, bit 1 par défaut : Entrée, bit 2 annulation : Échap), Rect relatif au contenu, maximum,
; texte précédé de sa longueur (un champ de texte réserve 1 + maximum octets) ; un 0 termine la liste.
reglages: .word 40, 40, 240, 160
.byte 1, 8
.text "Reglages"
type1: .byte 1, 2 ; 1 : bouton par défaut
.word 130, 90, 190, 104, 0
.byte 2
.text "OK"
.byte 1, 4 ; 2 : annulation
.word 60, 90, 120, 104, 0
.byte 7
.text "Annuler"
.byte 2, 0 ; 3 : case à cocher
.word 10, 10, 100, 22, 0
.byte 3
.text "Son"
.byte 5, 0 ; 4 : champ de texte, 8 au plus
.word 10, 30, 150, 44, 8
champ: .byte 2
.text "ab"
.fill 6
.byte 6, 0 ; 5 : texte fixe
.word 10, 50, 150, 60, 0
.byte 7
.text "Bonjour"
.byte 0
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset
d: .byte 0
w: .byte 0
e: .byte 0
b1: .byte 32, 19, 0 ; 32,19 Toolbox Reset
t2: .text "Dialogue ", 0
t3: .text ", fenetre ", 0
t4: .text " ; type 9 : erreur ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; 37,1 New Dialog sur le descripteur reglages : dialogue dans dlg, fenêtre dans fen ; erreur dans A.
ouvrir: jsr WaitMessage
lda #<reglages
sta ControlPort+4
lda #>reglages
sta ControlPort+5
lda #37
ldx #1
jsr appel
lda ControlPort+6
sta dlg
lda ControlPort+7
sta fen
lda ControlPort+2
rts
; 37,X sur le dialogue A.
dial: pha
phx
jsr WaitMessage
plx
pla
sta ControlPort+4
lda #37
jmp appel
dlg: .byte 0
fen: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Dialogue 1, fenetre 1 ; type 9 : erreur 137,2 Dispose Dialog Trinity
Ferme un dialogue : sa fenêtre et ses contrôles sont supprimés.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | numéro du dialogue |
Sorties : aucune.
Les fenêtres qu'il couvrait reçoivent un événement de mise à jour. Le numéro du dialogue est repris par le suivant. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Closes dialog Parameter:0 : its window and controls are disposed, the windows it covered get an update.
C (llvm-mos)
/* Fermer un dialogue (groupe 37, fonction 2, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* Descripteur de dialogue, lu sur place : Rect de la fenêtre (écran), options (bit 0 barre de titre), titre ;
puis chaque élément : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ de texte, 6 texte fixe), options
(bit 0 inactif, bit 1 par défaut : Entrée, bit 2 annulation : Échap), Rect relatif au contenu, maximum,
texte précédé de sa longueur (un champ de texte réserve 1 + maximum octets) ; un 0 termine la liste. */
#define W(v) (v) & 0xFF, (v) >> 8
static uint8_t reglages[] = {
W(40), W(40), W(240), W(160), 1, 8, 'R', 'e', 'g', 'l', 'a', 'g', 'e', 's',
1, 2, W(130), W(90), W(190), W(104), W(0), 2, 'O', 'K', /* 1 : bouton par défaut */
1, 4, W(60), W(90), W(120), W(104), W(0), 7, 'A', 'n', 'n', 'u', 'l', 'e', 'r', /* 2 : annulation */
2, 0, W(10), W(10), W(100), W(22), W(0), 3, 'S', 'o', 'n', /* 3 : case à cocher */
5, 0, W(10), W(30), W(150), W(44), W(8), 2, 'a', 'b', 0, 0, 0, 0, 0, 0, /* 4 : champ de texte, 8 au plus */
6, 0, W(10), W(50), W(150), W(60), W(0), 7, 'B', 'o', 'n', 'j', 'o', 'u', 'r', /* 5 : texte fixe */
0 };
#define CHAMP 81 /* position du tampon de l'élément 4 dans le descripteur */
static void p16(uint8_t i, uint16_t v) { /* paramètre 16 bits en Pi, Pi+1 */
ControlPort.params[i] = v & 0xFF;
ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) { /* 32,19 Toolbox Reset */
libre();
api(32, 19);
}
static uint8_t dialogue, fenetre;
static uint8_t ouvrir(uint8_t *descripteur) { /* 37,1 New Dialog : rend l'indicateur d'erreur */
libre();
p16(0, (uint16_t)descripteur);
api(37, 1);
dialogue = ControlPort.params[2];
fenetre = ControlPort.params[3];
return ControlPort.error;
}
static void fermer(uint8_t d) { /* 37,2 Dispose Dialog */
libre();
ControlPort.params[0] = d;
api(37, 2);
}
int main(void) {
uint8_t avant, apres, n;
reinit();
ouvrir(reglages);
libre(); api(34, 10); avant = ControlPort.params[0]; /* 34,10 : fenêtre de devant */
fermer(dialogue); /* sa fenêtre et ses contrôles sont supprimés */
libre(); api(34, 10); apres = ControlPort.params[0];
ouvrir(reglages);
n = dialogue;
reinit();
printf("Fenetre devant : %u, puis %u ; nouveau dialogue : %u\n", avant, apres, n);
return 0;
}Fenetre devant : 1, puis 0 ; nouveau dialogue : 1Mad Pascal
// Fermer un dialogue (groupe 37, fonction 2, Trinity).
program dl2;
uses crt, neo6502;
// Descripteur de dialogue (variable : le firmware écrit dans le champ de texte), lu sur place : Rect de la
// fenêtre (écran), options (bit 0 barre de titre), titre ; puis chaque élément : type (1 bouton, 2 case, 3 radio,
// 4 barre, 5 champ de texte, 6 texte fixe), options (bit 0 inactif, bit 1 par défaut : Entrée, bit 2 annulation :
// Échap), Rect relatif au contenu, maximum, texte précédé de sa longueur (un champ de texte réserve 1 + maximum
// octets) ; un 0 termine la liste.
var reglages: array[0..110] of byte = (
40, 0, 40, 0, 240, 0, 160, 0, 1, 8, ord('R'), ord('e'), ord('g'), ord('l'), ord('a'), ord('g'), ord('e'), ord('s'),
1, 2, 130, 0, 90, 0, 190, 0, 104, 0, 0, 0, 2, ord('O'), ord('K'), // 1 : bouton par défaut
1, 4, 60, 0, 90, 0, 120, 0, 104, 0, 0, 0, 7, ord('A'), ord('n'), ord('n'), ord('u'), ord('l'), ord('e'), ord('r'), // 2 : annulation
2, 0, 10, 0, 10, 0, 100, 0, 22, 0, 0, 0, 3, ord('S'), ord('o'), ord('n'), // 3 : case à cocher
5, 0, 10, 0, 30, 0, 150, 0, 44, 0, 8, 0, 2, ord('a'), ord('b'), 0, 0, 0, 0, 0, 0, // 4 : champ de texte, 8 au plus
6, 0, 10, 0, 50, 0, 150, 0, 60, 0, 0, 0, 7, ord('B'), ord('o'), ord('n'), ord('j'), ord('o'), ord('u'), ord('r'), // 5 : texte fixe
0);
const CHAMP = 81; // position du tampon de l'élément 4 dans le descripteur
var dialogue, fenetre: byte;
procedure appel(g, f: byte); // appel g,f (paramètres déjà posés)
begin
NeoSendMessage(g, f);
NeoWaitMessage;
end;
procedure reinit; // 32,19 Toolbox Reset
begin
NeoWaitMessage;
appel(32, 19);
end;
function ouvrir(descripteur: pointer): byte; // 37,1 New Dialog : rend l'indicateur d'erreur
begin
NeoWaitMessage;
wordParams[0] := word(descripteur);
appel(37, 1);
dialogue := NeoMessage.params[2];
fenetre := NeoMessage.params[3];
result := NeoMessage.error;
end;
procedure fermer(d: byte); // 37,2 Dispose Dialog
begin
NeoWaitMessage;
NeoMessage.params[0] := d;
appel(37, 2);
end;
var avant, apres, n: byte;
begin
reinit;
ouvrir(@reglages);
NeoWaitMessage; appel(34, 10); avant := NeoMessage.params[0]; // 34,10 : fenêtre de devant
fermer(dialogue); // sa fenêtre et ses contrôles sont supprimés
appel(34, 10); apres := NeoMessage.params[0];
ouvrir(@reglages);
n := dialogue;
reinit;
writeln('Fenetre devant : ', avant, ', puis ', apres, ' ; nouveau dialogue : ', n);
end.Fenetre devant : 1, puis 0 ; nouveau dialogue : 1NeoBASIC
10 ' Fermer un dialogue (groupe 37, fonction 2, Trinity)
15 gosub 7000
20 gosub 8300
30 q = rg : gosub 8000
40 gosub 2000 : av = dv : ' 34,10 : fenetre de devant
50 gosub 8200 : ' sa fenetre et ses controles sont supprimes
60 gosub 2000 : ap = dv
70 gosub 8000 : n = dg
80 gosub 8300
90 print "Fenetre devant : ";av;", puis ";ap;" ; nouveau dialogue : ";n
100 end
2000 while peek($ff00) : wend : poke $ff01, 10 : poke $ff00, 34
2010 while peek($ff00) : wend : dv = peek($ff04) : return
7000 ' descripteur de dialogue, lu sur place : Rect de la fenetre (ecran), options (bit 0 barre de titre), titre ;
7005 ' puis chaque element : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ, 6 texte fixe), options (bit 0 inactif,
7010 ' bit 1 par defaut : Entree, bit 2 annulation : Echap), Rect relatif au contenu, maximum, texte precede de sa
7015 ' longueur (un champ de texte reserve 1 + maximum octets) ; un 0 termine la liste. Adresse dans rg.
7020 rg = alloc(111) : p = rg
7025 for k = 1 to 4 : read v : doke p, v : p = p + 2 : next k : read v : poke p, v : p = p + 1 : read s$ : gosub 7100
7030 for it = 1 to 5 : read ty, op : poke p, ty : poke p + 1, op : p = p + 2
7035 for k = 1 to 5 : read v : doke p, v : p = p + 2 : next k : read s$ : p0 = p : gosub 7100
7040 if ty = 5 then p = p0 + 1 + v : ' le champ reserve 1 + maximum octets
7045 next it : poke p, 0 : ch = rg + 81 : return : ' ch : tampon de l'element 4
7050 data 40, 40, 240, 160, 1, "Reglages"
7055 data 1, 2, 130, 90, 190, 104, 0, "OK" : ' 1 : bouton par defaut
7060 data 1, 4, 60, 90, 120, 104, 0, "Annuler" : ' 2 : annulation
7065 data 2, 0, 10, 10, 100, 22, 0, "Son" : ' 3 : case a cocher
7070 data 5, 0, 10, 30, 150, 44, 8, "ab" : ' 4 : champ de texte, 8 au plus
7075 data 6, 0, 10, 50, 150, 60, 0, "Bonjour" : ' 5 : texte fixe
7100 poke p, len(s$) : for i = 1 to len(s$) : poke p + i, asc(mid$(s$, i, 1)) : next i : p = p + len(s$) + 1 : return
8000 ' 37,1 New Dialog sur le descripteur q : dialogue dans dg, fenetre dans fw, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 dg = peek($ff06) : fw = peek($ff07) : return
8100 ' appel 37,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 37
8120 while peek($ff00) : wend : e = peek($ff02) : return
8200 ' 37,2 Dispose Dialog dg
8210 while peek($ff00) : wend : poke $ff04, dg : f = 2 : goto 8110
8300 ' 32,19 Toolbox Reset
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnFenetre devant : 1, puis 0 ; nouveau dialogue : 1Assembleur 65C02 (64tass)
; Fermer un dialogue (groupe 37, fonction 2, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<b0
ldx #>b0
jsr envoi
jsr ouvrir
jsr WaitMessage
lda #34
ldx #10 ; 34,10 : fenêtre de devant
jsr appel
lda ControlPort+4
sta av
lda dlg
ldx #2 ; Dispose Dialog : sa fenêtre et ses contrôles sont supprimés
jsr dial
jsr WaitMessage
lda #34
ldx #10 ; 34,10 : fenêtre de devant
jsr appel
lda ControlPort+4
sta ap
jsr ouvrir
lda dlg
sta n
lda #<b1
ldx #>b1
jsr envoi
lda #<t2
ldx #>t2
jsr ecrire
lda av
jsr decimal
lda #<t3
ldx #>t3
jsr ecrire
lda ap
jsr decimal
lda #<t4
ldx #>t4
jsr ecrire
lda n
jsr decimal
lda #13
jsr WriteCharacter
rts
; Descripteur de dialogue, lu sur place : Rect de la fenêtre (écran), options (bit 0 barre de titre), titre ;
; puis chaque élément : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ de texte, 6 texte fixe), options
; (bit 0 inactif, bit 1 par défaut : Entrée, bit 2 annulation : Échap), Rect relatif au contenu, maximum,
; texte précédé de sa longueur (un champ de texte réserve 1 + maximum octets) ; un 0 termine la liste.
reglages: .word 40, 40, 240, 160
.byte 1, 8
.text "Reglages"
type1: .byte 1, 2 ; 1 : bouton par défaut
.word 130, 90, 190, 104, 0
.byte 2
.text "OK"
.byte 1, 4 ; 2 : annulation
.word 60, 90, 120, 104, 0
.byte 7
.text "Annuler"
.byte 2, 0 ; 3 : case à cocher
.word 10, 10, 100, 22, 0
.byte 3
.text "Son"
.byte 5, 0 ; 4 : champ de texte, 8 au plus
.word 10, 30, 150, 44, 8
champ: .byte 2
.text "ab"
.fill 6
.byte 6, 0 ; 5 : texte fixe
.word 10, 50, 150, 60, 0
.byte 7
.text "Bonjour"
.byte 0
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset
av: .byte 0
ap: .byte 0
n: .byte 0
b1: .byte 32, 19, 0 ; 32,19 Toolbox Reset
t2: .text "Fenetre devant : ", 0
t3: .text ", puis ", 0
t4: .text " ; nouveau dialogue : ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; 37,1 New Dialog sur le descripteur reglages : dialogue dans dlg, fenêtre dans fen ; erreur dans A.
ouvrir: jsr WaitMessage
lda #<reglages
sta ControlPort+4
lda #>reglages
sta ControlPort+5
lda #37
ldx #1
jsr appel
lda ControlPort+6
sta dlg
lda ControlPort+7
sta fen
lda ControlPort+2
rts
; 37,X sur le dialogue A.
dial: pha
phx
jsr WaitMessage
plx
pla
sta ControlPort+4
lda #37
jmp appel
dlg: .byte 0
fen: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Fenetre devant : 1, puis 0 ; nouveau dialogue : 137,3 Dialog Event Trinity
Passe un événement (groupe 33) au dialogue et rend l'élément qui a agi.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | numéro du dialogue |
P1-P2 | addr | adresse de l'EventRecord |
| Octets | Type | Rôle |
|---|---|---|
P3 | uint8 | élément qui a agi (1, 2... dans l'ordre du descripteur), 0 si aucun |
P4 | uint8 | 1 si l'événement appartenait au dialogue |
Un élément agit quand : un bouton est relâché dedans, Entrée (élément par défaut), Échap (élément d'annulation), une case bascule, une barre bouge, un champ de texte est cliqué ou modifié. Pendant que le dialogue est ouvert, tous les événements de souris et de clavier lui appartiennent, même un clic hors de sa fenêtre (relevé au banc) ; les mises à jour d'autres fenêtres et les minuteurs restent au programme. L'exemple fabrique ses événements ; un programme passe ceux de 33,2 jusqu'à obtenir l'élément attendu, puis appelle 37,2. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Gives dialog Parameter:0 the EventRecord (group 33) at Parameters:1,2. Returns in Parameter:3 the item that acted (1.. in descriptor order, 0 none) : a button released inside it, the default item on Return, the cancel item on Escape, a box toggled, a scroll bar moved, a text field clicked or edited ; and in Parameter:4 whether the event belonged to the dialog (1 : every mouse and key event while it is up, its own update - redrawn here - and activate events ; 0 : update/activate of other windows, timers, which the program still handles). The program keeps calling this for every event until it gets the item it waits for, then Dispose Dialog.
C (llvm-mos)
/* Passer un événement au dialogue (groupe 37, fonction 3, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* Descripteur de dialogue, lu sur place : Rect de la fenêtre (écran), options (bit 0 barre de titre), titre ;
puis chaque élément : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ de texte, 6 texte fixe), options
(bit 0 inactif, bit 1 par défaut : Entrée, bit 2 annulation : Échap), Rect relatif au contenu, maximum,
texte précédé de sa longueur (un champ de texte réserve 1 + maximum octets) ; un 0 termine la liste. */
#define W(v) (v) & 0xFF, (v) >> 8
static uint8_t reglages[] = {
W(40), W(40), W(240), W(160), 1, 8, 'R', 'e', 'g', 'l', 'a', 'g', 'e', 's',
1, 2, W(130), W(90), W(190), W(104), W(0), 2, 'O', 'K', /* 1 : bouton par défaut */
1, 4, W(60), W(90), W(120), W(104), W(0), 7, 'A', 'n', 'n', 'u', 'l', 'e', 'r', /* 2 : annulation */
2, 0, W(10), W(10), W(100), W(22), W(0), 3, 'S', 'o', 'n', /* 3 : case à cocher */
5, 0, W(10), W(30), W(150), W(44), W(8), 2, 'a', 'b', 0, 0, 0, 0, 0, 0, /* 4 : champ de texte, 8 au plus */
6, 0, W(10), W(50), W(150), W(60), W(0), 7, 'B', 'o', 'n', 'j', 'o', 'u', 'r', /* 5 : texte fixe */
0 };
#define CHAMP 81 /* position du tampon de l'élément 4 dans le descripteur */
static void p16(uint8_t i, uint16_t v) { /* paramètre 16 bits en Pi, Pi+1 */
ControlPort.params[i] = v & 0xFF;
ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) { /* 32,19 Toolbox Reset */
libre();
api(32, 19);
}
static uint8_t dialogue, fenetre;
static uint8_t ouvrir(uint8_t *descripteur) { /* 37,1 New Dialog : rend l'indicateur d'erreur */
libre();
p16(0, (uint16_t)descripteur);
api(37, 1);
dialogue = ControlPort.params[2];
fenetre = ControlPort.params[3];
return ControlPort.error;
}
static void fermer(uint8_t d) { /* 37,2 Dispose Dialog */
libre();
ControlPort.params[0] = d;
api(37, 2);
}
/* Événements fabriqués comme ceux du groupe 33 : type, message, message2, modificateurs, X, Y. */
typedef struct { uint8_t what, message, message2, modifiers; int16_t x, y; } EventRecord;
static EventRecord ev;
static uint8_t a_lui;
static uint8_t evenement(uint8_t d, uint8_t what, uint8_t m, uint8_t m2, int16_t x, int16_t y) { /* 37,3 Dialog Event */
ev.what = what; ev.message = m; ev.message2 = m2; ev.modifiers = 0; ev.x = x; ev.y = y;
libre();
ControlPort.params[0] = d;
p16(1, (uint16_t)&ev);
api(37, 3);
a_lui = ControlPort.params[4]; /* 1 si l'événement appartenait au dialogue */
return ControlPort.params[3]; /* élément qui a agi, 0 si aucun */
}
int main(void) {
uint8_t x, t, ent, ech, son, tim, ta, i;
reinit();
ouvrir(reglages);
x = evenement(dialogue, 1, 'X', 0x1B, 0, 0); /* touche « X » : au champ de texte */
t = reglages[CHAMP];
son = evenement(dialogue, 4, 1, 1, 60, 65); /* clic sur la case « Son », en (51, 61) à l'écran */
son = evenement(dialogue, 5, 0, 1, 60, 65); /* elle agit au relâchement */
ent = evenement(dialogue, 1, 13, 0x28, 0, 0); /* Entrée : le bouton par défaut */
ech = evenement(dialogue, 1, 27, 0x29, 0, 0); /* Échap : le bouton d'annulation */
tim = evenement(dialogue, 8, 0, 0, 0, 0); /* minuteur : pas pour le dialogue */
ta = a_lui;
reinit();
printf("X : element %u, champ : ", x);
for (i = 1; i <= t; i++)
putchar(reglages[CHAMP + i]);
printf("\nSon : %u, Entree : %u, Echap : %u\nMinuteur : %u, au dialogue : %u\n", son, ent, ech, tim, ta);
return 0;
}X : element 4, champ : abX
Son : 3, Entree : 1, Echap : 2
Minuteur : 0, au dialogue : 0Mad Pascal
// Passer un événement au dialogue (groupe 37, fonction 3, Trinity).
program dl3;
uses crt, neo6502;
// Descripteur de dialogue (variable : le firmware écrit dans le champ de texte), lu sur place : Rect de la
// fenêtre (écran), options (bit 0 barre de titre), titre ; puis chaque élément : type (1 bouton, 2 case, 3 radio,
// 4 barre, 5 champ de texte, 6 texte fixe), options (bit 0 inactif, bit 1 par défaut : Entrée, bit 2 annulation :
// Échap), Rect relatif au contenu, maximum, texte précédé de sa longueur (un champ de texte réserve 1 + maximum
// octets) ; un 0 termine la liste.
var reglages: array[0..110] of byte = (
40, 0, 40, 0, 240, 0, 160, 0, 1, 8, ord('R'), ord('e'), ord('g'), ord('l'), ord('a'), ord('g'), ord('e'), ord('s'),
1, 2, 130, 0, 90, 0, 190, 0, 104, 0, 0, 0, 2, ord('O'), ord('K'), // 1 : bouton par défaut
1, 4, 60, 0, 90, 0, 120, 0, 104, 0, 0, 0, 7, ord('A'), ord('n'), ord('n'), ord('u'), ord('l'), ord('e'), ord('r'), // 2 : annulation
2, 0, 10, 0, 10, 0, 100, 0, 22, 0, 0, 0, 3, ord('S'), ord('o'), ord('n'), // 3 : case à cocher
5, 0, 10, 0, 30, 0, 150, 0, 44, 0, 8, 0, 2, ord('a'), ord('b'), 0, 0, 0, 0, 0, 0, // 4 : champ de texte, 8 au plus
6, 0, 10, 0, 50, 0, 150, 0, 60, 0, 0, 0, 7, ord('B'), ord('o'), ord('n'), ord('j'), ord('o'), ord('u'), ord('r'), // 5 : texte fixe
0);
const CHAMP = 81; // position du tampon de l'élément 4 dans le descripteur
var dialogue, fenetre: byte;
procedure appel(g, f: byte); // appel g,f (paramètres déjà posés)
begin
NeoSendMessage(g, f);
NeoWaitMessage;
end;
procedure reinit; // 32,19 Toolbox Reset
begin
NeoWaitMessage;
appel(32, 19);
end;
function ouvrir(descripteur: pointer): byte; // 37,1 New Dialog : rend l'indicateur d'erreur
begin
NeoWaitMessage;
wordParams[0] := word(descripteur);
appel(37, 1);
dialogue := NeoMessage.params[2];
fenetre := NeoMessage.params[3];
result := NeoMessage.error;
end;
procedure fermer(d: byte); // 37,2 Dispose Dialog
begin
NeoWaitMessage;
NeoMessage.params[0] := d;
appel(37, 2);
end;
// Événements fabriqués comme ceux du groupe 33 : type, message, message2, modificateurs, X, Y.
type EventRecord = record what, message, message2, modifiers: byte; x, y: smallint; end;
var ev: EventRecord;
a_lui: byte;
function evenement(d, what, m, m2: byte; x, y: smallint): byte; // 37,3 Dialog Event
begin
ev.what := what; ev.message := m; ev.message2 := m2; ev.modifiers := 0; ev.x := x; ev.y := y;
NeoWaitMessage;
NeoMessage.params[0] := d;
NeoMessage.params[1] := lo(word(@ev));
NeoMessage.params[2] := hi(word(@ev));
appel(37, 3);
a_lui := NeoMessage.params[4]; // 1 si l'événement appartenait au dialogue
result := NeoMessage.params[3]; // élément qui a agi, 0 si aucun
end;
var x, t, ent, ech, son, tim, ta, i: byte;
begin
reinit;
ouvrir(@reglages);
x := evenement(dialogue, 1, ord('X'), $1B, 0, 0); // touche « X » : au champ de texte
t := reglages[CHAMP];
evenement(dialogue, 4, 1, 1, 60, 65); // clic sur la case « Son », en (51, 61) à l'écran
son := evenement(dialogue, 5, 0, 1, 60, 65); // elle agit au relâchement
ent := evenement(dialogue, 1, 13, $28, 0, 0); // Entrée : le bouton par défaut
ech := evenement(dialogue, 1, 27, $29, 0, 0); // Échap : le bouton d'annulation
tim := evenement(dialogue, 8, 0, 0, 0, 0); // minuteur : pas pour le dialogue
ta := a_lui;
reinit;
write('X : element ', x, ', champ : ');
for i := 1 to t do write(chr(reglages[CHAMP + i]));
writeln;
writeln('Son : ', son, ', Entree : ', ent, ', Echap : ', ech);
writeln('Minuteur : ', tim, ', au dialogue : ', ta);
end.X : element 4, champ : abX
Son : 3, Entree : 1, Echap : 2
Minuteur : 0, au dialogue : 0NeoBASIC
10 ' Passer un evenement au dialogue (groupe 37, fonction 3, Trinity)
15 gosub 7000
20 ev = alloc(8) : ' evenements fabriques comme ceux du groupe 33 : type, message, message2, modificateurs, X, Y
30 gosub 8300
40 q = rg : gosub 8000
50 wh = 1 : ms = asc("X") : m2 = $1b : ex = 0 : ey = 0 : gosub 7500 : x = it : ' touche « X » : au champ de texte
60 wh = 4 : ms = 1 : m2 = 1 : ex = 60 : ey = 65 : gosub 7500 : ' clic sur la case « Son », en (51, 61) a l'ecran
70 wh = 5 : ms = 0 : gosub 7500 : so = it : ' elle agit au relachement
80 wh = 1 : ms = 13 : m2 = $28 : ex = 0 : ey = 0 : gosub 7500 : en = it : ' Entree : le bouton par defaut
90 ms = 27 : m2 = $29 : gosub 7500 : ec = it : ' Echap : le bouton d'annulation
100 wh = 8 : ms = 0 : m2 = 0 : gosub 7500 : ti = it : ta = al : ' minuteur : pas pour le dialogue
110 gosub 8300
120 print "X : element ";x;", champ : "; : for i = 1 to peek(ch) : print chr$(peek(ch + i)); : next i : print
130 print "Son : ";so;", Entree : ";en;", Echap : ";ec
140 print "Minuteur : ";ti;", au dialogue : ";ta
150 end
7500 ' 37,3 Dialog Event : evenement fabrique (type wh, message ms, message2 m2, X ex, Y ey) pour le dialogue dg
7510 ' element qui a agi dans it (0 si aucun), al = 1 si l'evenement appartenait au dialogue
7520 poke ev, wh : poke ev + 1, ms : poke ev + 2, m2 : poke ev + 3, 0 : doke ev + 4, ex : doke ev + 6, ey
7530 while peek($ff00) : wend : poke $ff04, dg : doke $ff05, ev : f = 3 : gosub 8110
7540 it = peek($ff07) : al = peek($ff08) : return
7000 ' descripteur de dialogue, lu sur place : Rect de la fenetre (ecran), options (bit 0 barre de titre), titre ;
7005 ' puis chaque element : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ, 6 texte fixe), options (bit 0 inactif,
7010 ' bit 1 par defaut : Entree, bit 2 annulation : Echap), Rect relatif au contenu, maximum, texte precede de sa
7015 ' longueur (un champ de texte reserve 1 + maximum octets) ; un 0 termine la liste. Adresse dans rg.
7020 rg = alloc(111) : p = rg
7025 for k = 1 to 4 : read v : doke p, v : p = p + 2 : next k : read v : poke p, v : p = p + 1 : read s$ : gosub 7100
7030 for it = 1 to 5 : read ty, op : poke p, ty : poke p + 1, op : p = p + 2
7035 for k = 1 to 5 : read v : doke p, v : p = p + 2 : next k : read s$ : p0 = p : gosub 7100
7040 if ty = 5 then p = p0 + 1 + v : ' le champ reserve 1 + maximum octets
7045 next it : poke p, 0 : ch = rg + 81 : return : ' ch : tampon de l'element 4
7050 data 40, 40, 240, 160, 1, "Reglages"
7055 data 1, 2, 130, 90, 190, 104, 0, "OK" : ' 1 : bouton par defaut
7060 data 1, 4, 60, 90, 120, 104, 0, "Annuler" : ' 2 : annulation
7065 data 2, 0, 10, 10, 100, 22, 0, "Son" : ' 3 : case a cocher
7070 data 5, 0, 10, 30, 150, 44, 8, "ab" : ' 4 : champ de texte, 8 au plus
7075 data 6, 0, 10, 50, 150, 60, 0, "Bonjour" : ' 5 : texte fixe
7100 poke p, len(s$) : for i = 1 to len(s$) : poke p + i, asc(mid$(s$, i, 1)) : next i : p = p + len(s$) + 1 : return
8000 ' 37,1 New Dialog sur le descripteur q : dialogue dans dg, fenetre dans fw, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 dg = peek($ff06) : fw = peek($ff07) : return
8100 ' appel 37,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 37
8120 while peek($ff00) : wend : e = peek($ff02) : return
8200 ' 37,2 Dispose Dialog dg
8210 while peek($ff00) : wend : poke $ff04, dg : f = 2 : goto 8110
8300 ' 32,19 Toolbox Reset
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnX : element 4, champ : abX
Son : 3, Entree : 1, Echap : 2
Minuteur : 0, au dialogue : 0Assembleur 65C02 (64tass)
; Passer un événement au dialogue (groupe 37, fonction 3, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<b0
ldx #>b0
jsr envoi
jsr ouvrir
lda #1
sta ev
lda #'X'
sta ev+1
lda #$1B
sta ev+2
lda #0
sta ev+4
lda #0 ; touche « X » : au champ de texte
sta ev+6
lda dlg
jsr evenement
sta x
lda #4
sta ev
lda #1
sta ev+1
lda #1
sta ev+2
lda #60
sta ev+4
lda #65 ; clic sur la case « Son », en (51, 61) à l'écran
sta ev+6
lda dlg
jsr evenement
lda #5
sta ev
lda #0
sta ev+1
lda #1
sta ev+2
lda #60
sta ev+4
lda #65 ; elle agit au relâchement
sta ev+6
lda dlg
jsr evenement
sta so
lda #1
sta ev
lda #13
sta ev+1
lda #$28
sta ev+2
lda #0
sta ev+4
lda #0 ; Entrée : le bouton par défaut
sta ev+6
lda dlg
jsr evenement
sta en
lda #1
sta ev
lda #27
sta ev+1
lda #$29
sta ev+2
lda #0
sta ev+4
lda #0 ; Échap : le bouton d'annulation
sta ev+6
lda dlg
jsr evenement
sta ec
lda #8
sta ev
lda #0
sta ev+1
lda #0
sta ev+2
lda #0
sta ev+4
lda #0 ; minuteur : pas pour le dialogue
sta ev+6
lda dlg
jsr evenement
sta ti
lda #<b1
ldx #>b1
jsr envoi
lda #<t2
ldx #>t2
jsr ecrire
lda x
jsr decimal
lda #<t3
ldx #>t3
jsr ecrire
ldx #0
_ch: cpx champ
beq _hc
lda champ+1,x
jsr WriteCharacter
inx
bra _ch
_hc: lda #13
jsr WriteCharacter
lda #<t4
ldx #>t4
jsr ecrire
lda so
jsr decimal
lda #<t5
ldx #>t5
jsr ecrire
lda en
jsr decimal
lda #<t6
ldx #>t6
jsr ecrire
lda ec
jsr decimal
lda #13
jsr WriteCharacter
lda #<t7
ldx #>t7
jsr ecrire
lda ti
jsr decimal
lda #<t8
ldx #>t8
jsr ecrire
lda alui
jsr decimal
lda #13
jsr WriteCharacter
rts
; Descripteur de dialogue, lu sur place : Rect de la fenêtre (écran), options (bit 0 barre de titre), titre ;
; puis chaque élément : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ de texte, 6 texte fixe), options
; (bit 0 inactif, bit 1 par défaut : Entrée, bit 2 annulation : Échap), Rect relatif au contenu, maximum,
; texte précédé de sa longueur (un champ de texte réserve 1 + maximum octets) ; un 0 termine la liste.
reglages: .word 40, 40, 240, 160
.byte 1, 8
.text "Reglages"
type1: .byte 1, 2 ; 1 : bouton par défaut
.word 130, 90, 190, 104, 0
.byte 2
.text "OK"
.byte 1, 4 ; 2 : annulation
.word 60, 90, 120, 104, 0
.byte 7
.text "Annuler"
.byte 2, 0 ; 3 : case à cocher
.word 10, 10, 100, 22, 0
.byte 3
.text "Son"
.byte 5, 0 ; 4 : champ de texte, 8 au plus
.word 10, 30, 150, 44, 8
champ: .byte 2
.text "ab"
.fill 6
.byte 6, 0 ; 5 : texte fixe
.word 10, 50, 150, 60, 0
.byte 7
.text "Bonjour"
.byte 0
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset
x: .byte 0
so: .byte 0
en: .byte 0
ec: .byte 0
ti: .byte 0
b1: .byte 32, 19, 0 ; 32,19 Toolbox Reset
t2: .text "X : element ", 0
t3: .text ", champ : ", 0
t4: .text "Son : ", 0
t5: .text ", Entree : ", 0
t6: .text ", Echap : ", 0
t7: .text "Minuteur : ", 0
t8: .text ", au dialogue : ", 0
; 37,3 Dialog Event : l'événement ev (fabriqué comme ceux du groupe 33 : type, message, message2,
; modificateurs, X, Y) pour le dialogue A ; élément qui a agi dans A (0 si aucun), appartenance dans alui.
evenement:
pha
jsr WaitMessage
pla
sta ControlPort+4
lda #<ev
sta ControlPort+5
lda #>ev
sta ControlPort+6
lda #37
ldx #3
jsr appel
lda ControlPort+8 ; 1 si l'événement appartenait au dialogue
sta alui
lda ControlPort+7 ; élément qui a agi
rts
ev: .byte 0, 0, 0, 0
.word 0, 0
alui: .byte 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; 37,1 New Dialog sur le descripteur reglages : dialogue dans dlg, fenêtre dans fen ; erreur dans A.
ouvrir: jsr WaitMessage
lda #<reglages
sta ControlPort+4
lda #>reglages
sta ControlPort+5
lda #37
ldx #1
jsr appel
lda ControlPort+6
sta dlg
lda ControlPort+7
sta fen
lda ControlPort+2
rts
; 37,X sur le dialogue A.
dial: pha
phx
jsr WaitMessage
plx
pla
sta ControlPort+4
lda #37
jmp appel
dlg: .byte 0
fen: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0X : element 4, champ : abX
Son : 3, Entree : 1, Echap : 2
Minuteur : 0, au dialogue : 037,4 Get Dialog Item Trinity
Rend le contrôle (groupe 36) et le type d'un élément du dialogue.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | numéro du dialogue |
P1 | uint8 | numéro de l'élément (1, 2...) |
| Octets | Type | Rôle |
|---|---|---|
P2 | uint8 | contrôle du groupe 36 (0 pour un texte fixe) |
P3 | uint8 | type de l'élément |
Le contrôle se pilote ensuite avec le groupe 36 : l'exemple coche la case avec 36,5 et la relit avec 36,6. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Returns in Parameter:2 the control (group 36 : Set/Get Control Value, Set Control Flags) behind item Parameter:1 of dialog Parameter:0 (0 for static text) and its kind in Parameter:3.
C (llvm-mos)
/* Lire le contrôle d'un élément (groupe 37, fonction 4, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* Descripteur de dialogue, lu sur place : Rect de la fenêtre (écran), options (bit 0 barre de titre), titre ;
puis chaque élément : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ de texte, 6 texte fixe), options
(bit 0 inactif, bit 1 par défaut : Entrée, bit 2 annulation : Échap), Rect relatif au contenu, maximum,
texte précédé de sa longueur (un champ de texte réserve 1 + maximum octets) ; un 0 termine la liste. */
#define W(v) (v) & 0xFF, (v) >> 8
static uint8_t reglages[] = {
W(40), W(40), W(240), W(160), 1, 8, 'R', 'e', 'g', 'l', 'a', 'g', 'e', 's',
1, 2, W(130), W(90), W(190), W(104), W(0), 2, 'O', 'K', /* 1 : bouton par défaut */
1, 4, W(60), W(90), W(120), W(104), W(0), 7, 'A', 'n', 'n', 'u', 'l', 'e', 'r', /* 2 : annulation */
2, 0, W(10), W(10), W(100), W(22), W(0), 3, 'S', 'o', 'n', /* 3 : case à cocher */
5, 0, W(10), W(30), W(150), W(44), W(8), 2, 'a', 'b', 0, 0, 0, 0, 0, 0, /* 4 : champ de texte, 8 au plus */
6, 0, W(10), W(50), W(150), W(60), W(0), 7, 'B', 'o', 'n', 'j', 'o', 'u', 'r', /* 5 : texte fixe */
0 };
#define CHAMP 81 /* position du tampon de l'élément 4 dans le descripteur */
static void p16(uint8_t i, uint16_t v) { /* paramètre 16 bits en Pi, Pi+1 */
ControlPort.params[i] = v & 0xFF;
ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) { /* 32,19 Toolbox Reset */
libre();
api(32, 19);
}
static uint8_t dialogue, fenetre;
static uint8_t ouvrir(uint8_t *descripteur) { /* 37,1 New Dialog : rend l'indicateur d'erreur */
libre();
p16(0, (uint16_t)descripteur);
api(37, 1);
dialogue = ControlPort.params[2];
fenetre = ControlPort.params[3];
return ControlPort.error;
}
static void fermer(uint8_t d) { /* 37,2 Dispose Dialog */
libre();
ControlPort.params[0] = d;
api(37, 2);
}
int main(void) {
uint8_t c[5], t[5], i;
uint8_t v;
reinit();
ouvrir(reglages);
for (i = 0; i < 5; i++) {
libre();
ControlPort.params[0] = dialogue;
ControlPort.params[1] = i + 1;
api(37, 4); /* Get Dialog Item */
c[i] = ControlPort.params[2]; /* contrôle du groupe 36, 0 pour un texte fixe */
t[i] = ControlPort.params[3]; /* type */
}
libre(); ControlPort.params[0] = c[2]; p16(1, 1); api(36, 5); /* 36,5 : coche la case */
libre(); ControlPort.params[0] = c[2]; api(36, 6);
v = ControlPort.params[1];
reinit();
printf("Elements :");
for (i = 0; i < 5; i++)
printf(" %u/%u", c[i], t[i]);
printf("\nCase cochee par 36,5 : %u\n", v);
return 0;
}Elements : 1/1 2/1 3/2 4/5 0/6
Case cochee par 36,5 : 1Mad Pascal
// Lire le contrôle d'un élément (groupe 37, fonction 4, Trinity).
program dl4;
uses crt, neo6502;
// Descripteur de dialogue (variable : le firmware écrit dans le champ de texte), lu sur place : Rect de la
// fenêtre (écran), options (bit 0 barre de titre), titre ; puis chaque élément : type (1 bouton, 2 case, 3 radio,
// 4 barre, 5 champ de texte, 6 texte fixe), options (bit 0 inactif, bit 1 par défaut : Entrée, bit 2 annulation :
// Échap), Rect relatif au contenu, maximum, texte précédé de sa longueur (un champ de texte réserve 1 + maximum
// octets) ; un 0 termine la liste.
var reglages: array[0..110] of byte = (
40, 0, 40, 0, 240, 0, 160, 0, 1, 8, ord('R'), ord('e'), ord('g'), ord('l'), ord('a'), ord('g'), ord('e'), ord('s'),
1, 2, 130, 0, 90, 0, 190, 0, 104, 0, 0, 0, 2, ord('O'), ord('K'), // 1 : bouton par défaut
1, 4, 60, 0, 90, 0, 120, 0, 104, 0, 0, 0, 7, ord('A'), ord('n'), ord('n'), ord('u'), ord('l'), ord('e'), ord('r'), // 2 : annulation
2, 0, 10, 0, 10, 0, 100, 0, 22, 0, 0, 0, 3, ord('S'), ord('o'), ord('n'), // 3 : case à cocher
5, 0, 10, 0, 30, 0, 150, 0, 44, 0, 8, 0, 2, ord('a'), ord('b'), 0, 0, 0, 0, 0, 0, // 4 : champ de texte, 8 au plus
6, 0, 10, 0, 50, 0, 150, 0, 60, 0, 0, 0, 7, ord('B'), ord('o'), ord('n'), ord('j'), ord('o'), ord('u'), ord('r'), // 5 : texte fixe
0);
const CHAMP = 81; // position du tampon de l'élément 4 dans le descripteur
var dialogue, fenetre: byte;
procedure appel(g, f: byte); // appel g,f (paramètres déjà posés)
begin
NeoSendMessage(g, f);
NeoWaitMessage;
end;
procedure reinit; // 32,19 Toolbox Reset
begin
NeoWaitMessage;
appel(32, 19);
end;
function ouvrir(descripteur: pointer): byte; // 37,1 New Dialog : rend l'indicateur d'erreur
begin
NeoWaitMessage;
wordParams[0] := word(descripteur);
appel(37, 1);
dialogue := NeoMessage.params[2];
fenetre := NeoMessage.params[3];
result := NeoMessage.error;
end;
procedure fermer(d: byte); // 37,2 Dispose Dialog
begin
NeoWaitMessage;
NeoMessage.params[0] := d;
appel(37, 2);
end;
var c, t: array[0..4] of byte;
i, v: byte;
begin
reinit;
ouvrir(@reglages);
for i := 0 to 4 do begin
NeoWaitMessage;
NeoMessage.params[0] := dialogue;
NeoMessage.params[1] := i + 1;
appel(37, 4); // Get Dialog Item
c[i] := NeoMessage.params[2]; // contrôle du groupe 36, 0 pour un texte fixe
t[i] := NeoMessage.params[3]; // type
end;
NeoWaitMessage;
NeoMessage.params[0] := c[2]; NeoMessage.params[1] := 1; NeoMessage.params[2] := 0;
appel(36, 5); // 36,5 : coche la case
NeoMessage.params[0] := c[2];
appel(36, 6);
v := NeoMessage.params[1];
reinit;
write('Elements :');
for i := 0 to 4 do write(' ', c[i], '/', t[i]);
writeln;
writeln('Case cochee par 36,5 : ', v);
end.Elements : 1/1 2/1 3/2 4/5 0/6
Case cochee par 36,5 : 1NeoBASIC
10 ' Lire le controle d'un element (groupe 37, fonction 4, Trinity)
15 gosub 7000
20 dim c(4), t(4)
30 gosub 8300
40 q = rg : gosub 8000
50 for k = 0 to 4
60 while peek($ff00) : wend : poke $ff04, dg : poke $ff05, k + 1 : f = 4 : gosub 8110 : ' Get Dialog Item
70 c(k) = peek($ff06) : t(k) = peek($ff07) : next k : ' controle du groupe 36 (0 : texte fixe), type
80 while peek($ff00) : wend : poke $ff04, c(2) : doke $ff05, 1 : poke $ff01, 5 : poke $ff00, 36 : ' 36,5 : coche la case
90 while peek($ff00) : wend : poke $ff04, c(2) : poke $ff01, 6 : poke $ff00, 36
100 while peek($ff00) : wend : v = peek($ff05)
110 gosub 8300
120 print "Elements :"; : for k = 0 to 4 : print " ";c(k);"/";t(k); : next k : print
130 print "Case cochee par 36,5 : ";v
140 end
7000 ' descripteur de dialogue, lu sur place : Rect de la fenetre (ecran), options (bit 0 barre de titre), titre ;
7005 ' puis chaque element : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ, 6 texte fixe), options (bit 0 inactif,
7010 ' bit 1 par defaut : Entree, bit 2 annulation : Echap), Rect relatif au contenu, maximum, texte precede de sa
7015 ' longueur (un champ de texte reserve 1 + maximum octets) ; un 0 termine la liste. Adresse dans rg.
7020 rg = alloc(111) : p = rg
7025 for k = 1 to 4 : read v : doke p, v : p = p + 2 : next k : read v : poke p, v : p = p + 1 : read s$ : gosub 7100
7030 for it = 1 to 5 : read ty, op : poke p, ty : poke p + 1, op : p = p + 2
7035 for k = 1 to 5 : read v : doke p, v : p = p + 2 : next k : read s$ : p0 = p : gosub 7100
7040 if ty = 5 then p = p0 + 1 + v : ' le champ reserve 1 + maximum octets
7045 next it : poke p, 0 : ch = rg + 81 : return : ' ch : tampon de l'element 4
7050 data 40, 40, 240, 160, 1, "Reglages"
7055 data 1, 2, 130, 90, 190, 104, 0, "OK" : ' 1 : bouton par defaut
7060 data 1, 4, 60, 90, 120, 104, 0, "Annuler" : ' 2 : annulation
7065 data 2, 0, 10, 10, 100, 22, 0, "Son" : ' 3 : case a cocher
7070 data 5, 0, 10, 30, 150, 44, 8, "ab" : ' 4 : champ de texte, 8 au plus
7075 data 6, 0, 10, 50, 150, 60, 0, "Bonjour" : ' 5 : texte fixe
7100 poke p, len(s$) : for i = 1 to len(s$) : poke p + i, asc(mid$(s$, i, 1)) : next i : p = p + len(s$) + 1 : return
8000 ' 37,1 New Dialog sur le descripteur q : dialogue dans dg, fenetre dans fw, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 dg = peek($ff06) : fw = peek($ff07) : return
8100 ' appel 37,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 37
8120 while peek($ff00) : wend : e = peek($ff02) : return
8200 ' 37,2 Dispose Dialog dg
8210 while peek($ff00) : wend : poke $ff04, dg : f = 2 : goto 8110
8300 ' 32,19 Toolbox Reset
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnElements : 1/1 2/1 3/2 4/5 0/6
Case cochee par 36,5 : 1Assembleur 65C02 (64tass)
; Lire le contrôle d'un élément (groupe 37, fonction 4, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<b0
ldx #>b0
jsr envoi
jsr ouvrir
ldx #1
_el: phx
jsr WaitMessage
plx
stx ControlPort+5 ; P1 : élément
phx
lda dlg
ldx #4 ; Get Dialog Item
jsr dial
plx
lda ControlPort+6 ; contrôle du groupe 36, 0 pour un texte fixe
sta c-1,x
lda ControlPort+7 ; type
sta t-1,x
inx
cpx #6
bne _el
jsr WaitMessage
lda c+2
sta ControlPort+4
lda #1
sta ControlPort+5
stz ControlPort+6
lda #36
ldx #5 ; 36,5 : coche la case
jsr appel
jsr WaitMessage
lda c+2
sta ControlPort+4
lda #36
ldx #6
jsr appel
lda ControlPort+5
sta v
lda #<b1
ldx #>b1
jsr envoi
lda #<t2
ldx #>t2
jsr ecrire
ldx #0
_af: lda #' '
jsr WriteCharacter
lda c,x
jsr decimal
lda #'/'
jsr WriteCharacter
lda t,x
jsr decimal
inx
cpx #5
bne _af
lda #13
jsr WriteCharacter
lda #<t3
ldx #>t3
jsr ecrire
lda v
jsr decimal
lda #13
jsr WriteCharacter
rts
; Descripteur de dialogue, lu sur place : Rect de la fenêtre (écran), options (bit 0 barre de titre), titre ;
; puis chaque élément : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ de texte, 6 texte fixe), options
; (bit 0 inactif, bit 1 par défaut : Entrée, bit 2 annulation : Échap), Rect relatif au contenu, maximum,
; texte précédé de sa longueur (un champ de texte réserve 1 + maximum octets) ; un 0 termine la liste.
reglages: .word 40, 40, 240, 160
.byte 1, 8
.text "Reglages"
type1: .byte 1, 2 ; 1 : bouton par défaut
.word 130, 90, 190, 104, 0
.byte 2
.text "OK"
.byte 1, 4 ; 2 : annulation
.word 60, 90, 120, 104, 0
.byte 7
.text "Annuler"
.byte 2, 0 ; 3 : case à cocher
.word 10, 10, 100, 22, 0
.byte 3
.text "Son"
.byte 5, 0 ; 4 : champ de texte, 8 au plus
.word 10, 30, 150, 44, 8
champ: .byte 2
.text "ab"
.fill 6
.byte 6, 0 ; 5 : texte fixe
.word 10, 50, 150, 60, 0
.byte 7
.text "Bonjour"
.byte 0
c: .fill 5
t: .fill 5
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset
v: .byte 0
b1: .byte 32, 19, 0 ; 32,19 Toolbox Reset
t2: .text "Elements :", 0
t3: .text "Case cochee par 36,5 : ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; 37,1 New Dialog sur le descripteur reglages : dialogue dans dlg, fenêtre dans fen ; erreur dans A.
ouvrir: jsr WaitMessage
lda #<reglages
sta ControlPort+4
lda #>reglages
sta ControlPort+5
lda #37
ldx #1
jsr appel
lda ControlPort+6
sta dlg
lda ControlPort+7
sta fen
lda ControlPort+2
rts
; 37,X sur le dialogue A.
dial: pha
phx
jsr WaitMessage
plx
pla
sta ControlPort+4
lda #37
jmp appel
dlg: .byte 0
fen: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Elements : 1/1 2/1 3/2 4/5 0/6
Case cochee par 36,5 : 137,5 Draw Dialog Trinity
Redessine les contrôles et les textes fixes d'un dialogue.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | numéro du dialogue |
Sorties : aucune.
Par exemple après que le programme a changé un texte dans le descripteur. L'exemple peint le contenu en couleur 4 : le cadre du bouton OK redevient blanc (15). NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Redraws the controls and static texts of dialog Parameter:0 (after the program changed a text in the descriptor, for instance).
C (llvm-mos)
/* Redessiner un dialogue (groupe 37, fonction 5, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* Descripteur de dialogue, lu sur place : Rect de la fenêtre (écran), options (bit 0 barre de titre), titre ;
puis chaque élément : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ de texte, 6 texte fixe), options
(bit 0 inactif, bit 1 par défaut : Entrée, bit 2 annulation : Échap), Rect relatif au contenu, maximum,
texte précédé de sa longueur (un champ de texte réserve 1 + maximum octets) ; un 0 termine la liste. */
#define W(v) (v) & 0xFF, (v) >> 8
static uint8_t reglages[] = {
W(40), W(40), W(240), W(160), 1, 8, 'R', 'e', 'g', 'l', 'a', 'g', 'e', 's',
1, 2, W(130), W(90), W(190), W(104), W(0), 2, 'O', 'K', /* 1 : bouton par défaut */
1, 4, W(60), W(90), W(120), W(104), W(0), 7, 'A', 'n', 'n', 'u', 'l', 'e', 'r', /* 2 : annulation */
2, 0, W(10), W(10), W(100), W(22), W(0), 3, 'S', 'o', 'n', /* 3 : case à cocher */
5, 0, W(10), W(30), W(150), W(44), W(8), 2, 'a', 'b', 0, 0, 0, 0, 0, 0, /* 4 : champ de texte, 8 au plus */
6, 0, W(10), W(50), W(150), W(60), W(0), 7, 'B', 'o', 'n', 'j', 'o', 'u', 'r', /* 5 : texte fixe */
0 };
#define CHAMP 81 /* position du tampon de l'élément 4 dans le descripteur */
static void p16(uint8_t i, uint16_t v) { /* paramètre 16 bits en Pi, Pi+1 */
ControlPort.params[i] = v & 0xFF;
ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) { /* 32,19 Toolbox Reset */
libre();
api(32, 19);
}
static uint8_t dialogue, fenetre;
static uint8_t ouvrir(uint8_t *descripteur) { /* 37,1 New Dialog : rend l'indicateur d'erreur */
libre();
p16(0, (uint16_t)descripteur);
api(37, 1);
dialogue = ControlPort.params[2];
fenetre = ControlPort.params[3];
return ControlPort.error;
}
static void fermer(uint8_t d) { /* 37,2 Dispose Dialog */
libre();
ControlPort.params[0] = d;
api(37, 2);
}
typedef struct { int16_t g, h, d, b; } Rect;
static Rect ecran = {0, 0, 320, 240};
static uint8_t pixel(int16_t x, int16_t y) { /* 5,33 : couleur du fond en (x, y) */
libre(); p16(0, x); p16(2, y); api(5, 33);
return ControlPort.params[0];
}
int main(void) {
uint8_t avant, peint, apres;
putchar(12); /* écran effacé : on relit des pixels */
reinit();
ouvrir(reglages);
avant = pixel(171, 141); /* coin du bouton OK (contenu en (41, 51)) */
libre(); ControlPort.params[0] = fenetre; api(34, 12); /* le programme peint le contenu en couleur 4 */
libre(); ControlPort.params[0] = 4; api(32, 4);
libre(); p16(0, (uint16_t)&ecran); api(32, 8);
peint = pixel(171, 141);
libre(); ControlPort.params[0] = dialogue; api(37, 5); /* Draw Dialog */
apres = pixel(171, 141);
reinit();
printf("Bouton OK : %u, peint : %u, redessine : %u\n", avant, peint, apres);
return 0;
}Bouton OK : 15, peint : 4, redessine : 15Mad Pascal
// Redessiner un dialogue (groupe 37, fonction 5, Trinity).
program dl5;
uses crt, neo6502;
// Descripteur de dialogue (variable : le firmware écrit dans le champ de texte), lu sur place : Rect de la
// fenêtre (écran), options (bit 0 barre de titre), titre ; puis chaque élément : type (1 bouton, 2 case, 3 radio,
// 4 barre, 5 champ de texte, 6 texte fixe), options (bit 0 inactif, bit 1 par défaut : Entrée, bit 2 annulation :
// Échap), Rect relatif au contenu, maximum, texte précédé de sa longueur (un champ de texte réserve 1 + maximum
// octets) ; un 0 termine la liste.
var reglages: array[0..110] of byte = (
40, 0, 40, 0, 240, 0, 160, 0, 1, 8, ord('R'), ord('e'), ord('g'), ord('l'), ord('a'), ord('g'), ord('e'), ord('s'),
1, 2, 130, 0, 90, 0, 190, 0, 104, 0, 0, 0, 2, ord('O'), ord('K'), // 1 : bouton par défaut
1, 4, 60, 0, 90, 0, 120, 0, 104, 0, 0, 0, 7, ord('A'), ord('n'), ord('n'), ord('u'), ord('l'), ord('e'), ord('r'), // 2 : annulation
2, 0, 10, 0, 10, 0, 100, 0, 22, 0, 0, 0, 3, ord('S'), ord('o'), ord('n'), // 3 : case à cocher
5, 0, 10, 0, 30, 0, 150, 0, 44, 0, 8, 0, 2, ord('a'), ord('b'), 0, 0, 0, 0, 0, 0, // 4 : champ de texte, 8 au plus
6, 0, 10, 0, 50, 0, 150, 0, 60, 0, 0, 0, 7, ord('B'), ord('o'), ord('n'), ord('j'), ord('o'), ord('u'), ord('r'), // 5 : texte fixe
0);
const CHAMP = 81; // position du tampon de l'élément 4 dans le descripteur
var dialogue, fenetre: byte;
procedure appel(g, f: byte); // appel g,f (paramètres déjà posés)
begin
NeoSendMessage(g, f);
NeoWaitMessage;
end;
procedure reinit; // 32,19 Toolbox Reset
begin
NeoWaitMessage;
appel(32, 19);
end;
function ouvrir(descripteur: pointer): byte; // 37,1 New Dialog : rend l'indicateur d'erreur
begin
NeoWaitMessage;
wordParams[0] := word(descripteur);
appel(37, 1);
dialogue := NeoMessage.params[2];
fenetre := NeoMessage.params[3];
result := NeoMessage.error;
end;
procedure fermer(d: byte); // 37,2 Dispose Dialog
begin
NeoWaitMessage;
NeoMessage.params[0] := d;
appel(37, 2);
end;
type Rect = record g, h, d, b: smallint; end;
var ecran: Rect;
avant, peint, apres: byte;
begin
write(chr(12)); // écran effacé : on relit des pixels
ecran.g := 0; ecran.h := 0; ecran.d := 320; ecran.b := 240;
reinit;
ouvrir(@reglages);
avant := NeoGetPixel(171, 141); // coin du bouton OK (contenu en (41, 51))
NeoWaitMessage; NeoMessage.params[0] := fenetre; appel(34, 12); // le programme peint le contenu en couleur 4
NeoMessage.params[0] := 4; appel(32, 4);
wordParams[0] := word(@ecran); appel(32, 8);
peint := NeoGetPixel(171, 141);
NeoWaitMessage; NeoMessage.params[0] := dialogue; appel(37, 5); // Draw Dialog
apres := NeoGetPixel(171, 141);
reinit;
writeln('Bouton OK : ', avant, ', peint : ', peint, ', redessine : ', apres);
end.Bouton OK : 15, peint : 4, redessine : 15NeoBASIC
10 ' Redessiner un dialogue (groupe 37, fonction 5, Trinity)
15 gosub 7000
20 cls : ' ecran efface : on relit des pixels
30 ec = alloc(8) : doke ec, 0 : doke ec + 2, 0 : doke ec + 4, 320 : doke ec + 6, 240
40 gosub 8300
50 q = rg : gosub 8000
60 av = point(171, 141) : ' coin du bouton OK (contenu en (41, 51))
70 while peek($ff00) : wend : poke $ff04, fw : poke $ff01, 12 : poke $ff00, 34 : ' le programme peint le contenu en couleur 4
80 while peek($ff00) : wend : poke $ff04, 4 : poke $ff01, 4 : poke $ff00, 32
90 while peek($ff00) : wend : doke $ff04, ec : poke $ff01, 8 : poke $ff00, 32
100 while peek($ff00) : wend : pe = point(171, 141)
110 poke $ff04, dg : f = 5 : gosub 8110 : ' Draw Dialog
120 ap = point(171, 141)
130 gosub 8300
140 print "Bouton OK : ";av;", peint : ";pe;", redessine : ";ap
150 end
7000 ' descripteur de dialogue, lu sur place : Rect de la fenetre (ecran), options (bit 0 barre de titre), titre ;
7005 ' puis chaque element : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ, 6 texte fixe), options (bit 0 inactif,
7010 ' bit 1 par defaut : Entree, bit 2 annulation : Echap), Rect relatif au contenu, maximum, texte precede de sa
7015 ' longueur (un champ de texte reserve 1 + maximum octets) ; un 0 termine la liste. Adresse dans rg.
7020 rg = alloc(111) : p = rg
7025 for k = 1 to 4 : read v : doke p, v : p = p + 2 : next k : read v : poke p, v : p = p + 1 : read s$ : gosub 7100
7030 for it = 1 to 5 : read ty, op : poke p, ty : poke p + 1, op : p = p + 2
7035 for k = 1 to 5 : read v : doke p, v : p = p + 2 : next k : read s$ : p0 = p : gosub 7100
7040 if ty = 5 then p = p0 + 1 + v : ' le champ reserve 1 + maximum octets
7045 next it : poke p, 0 : ch = rg + 81 : return : ' ch : tampon de l'element 4
7050 data 40, 40, 240, 160, 1, "Reglages"
7055 data 1, 2, 130, 90, 190, 104, 0, "OK" : ' 1 : bouton par defaut
7060 data 1, 4, 60, 90, 120, 104, 0, "Annuler" : ' 2 : annulation
7065 data 2, 0, 10, 10, 100, 22, 0, "Son" : ' 3 : case a cocher
7070 data 5, 0, 10, 30, 150, 44, 8, "ab" : ' 4 : champ de texte, 8 au plus
7075 data 6, 0, 10, 50, 150, 60, 0, "Bonjour" : ' 5 : texte fixe
7100 poke p, len(s$) : for i = 1 to len(s$) : poke p + i, asc(mid$(s$, i, 1)) : next i : p = p + len(s$) + 1 : return
8000 ' 37,1 New Dialog sur le descripteur q : dialogue dans dg, fenetre dans fw, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 dg = peek($ff06) : fw = peek($ff07) : return
8100 ' appel 37,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 37
8120 while peek($ff00) : wend : e = peek($ff02) : return
8200 ' 37,2 Dispose Dialog dg
8210 while peek($ff00) : wend : poke $ff04, dg : f = 2 : goto 8110
8300 ' 32,19 Toolbox Reset
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnBouton OK : 15, peint : 4, redessine : 15Assembleur 65C02 (64tass)
; Redessiner un dialogue (groupe 37, fonction 5, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #12 ; écran effacé : on relit des pixels
jsr WriteCharacter
lda #<b0
ldx #>b0
jsr envoi
jsr ouvrir
lda #171 ; coin du bouton OK (contenu en (41, 51))
ldy #141
jsr pixel
sta av
jsr WaitMessage
lda fen
sta ControlPort+4
lda #34
ldx #12 ; le programme peint le contenu en couleur 4
jsr appel
lda #<b1
ldx #>b1
jsr envoi
lda #<b2
ldx #>b2
jsr envoi
lda #171
ldy #141
jsr pixel
sta pe
lda dlg
ldx #5 ; Draw Dialog
jsr dial
lda #171
ldy #141
jsr pixel
sta ap
lda #<b3
ldx #>b3
jsr envoi
lda #<t4
ldx #>t4
jsr ecrire
lda av
jsr decimal
lda #<t5
ldx #>t5
jsr ecrire
lda pe
jsr decimal
lda #<t6
ldx #>t6
jsr ecrire
lda ap
jsr decimal
lda #13
jsr WriteCharacter
rts
; Couleur du fond (5,33) en (A, Y), X et Y inférieurs à 256, rendue dans A.
pixel: pha
jsr WaitMessage
pla
sta ControlPort+4 ; P0-P1 : X
stz ControlPort+5
sty ControlPort+6 ; P2-P3 : Y
stz ControlPort+7
lda #5
ldx #33 ; 5,33 : Read Pixel
jsr appel
lda ControlPort+4
rts
; Descripteur de dialogue, lu sur place : Rect de la fenêtre (écran), options (bit 0 barre de titre), titre ;
; puis chaque élément : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ de texte, 6 texte fixe), options
; (bit 0 inactif, bit 1 par défaut : Entrée, bit 2 annulation : Échap), Rect relatif au contenu, maximum,
; texte précédé de sa longueur (un champ de texte réserve 1 + maximum octets) ; un 0 termine la liste.
reglages: .word 40, 40, 240, 160
.byte 1, 8
.text "Reglages"
type1: .byte 1, 2 ; 1 : bouton par défaut
.word 130, 90, 190, 104, 0
.byte 2
.text "OK"
.byte 1, 4 ; 2 : annulation
.word 60, 90, 120, 104, 0
.byte 7
.text "Annuler"
.byte 2, 0 ; 3 : case à cocher
.word 10, 10, 100, 22, 0
.byte 3
.text "Son"
.byte 5, 0 ; 4 : champ de texte, 8 au plus
.word 10, 30, 150, 44, 8
champ: .byte 2
.text "ab"
.fill 6
.byte 6, 0 ; 5 : texte fixe
.word 10, 50, 150, 60, 0
.byte 7
.text "Bonjour"
.byte 0
ecran: .word 0, 0, 320, 240
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset
av: .byte 0
b1: .byte 32, 4, 1, 4 ; 32,4
b2: .byte 32, 8, 2 ; 32,8
.word ecran
pe: .byte 0
ap: .byte 0
b3: .byte 32, 19, 0 ; 32,19 Toolbox Reset
t4: .text "Bouton OK : ", 0
t5: .text ", peint : ", 0
t6: .text ", redessine : ", 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; 37,1 New Dialog sur le descripteur reglages : dialogue dans dlg, fenêtre dans fen ; erreur dans A.
ouvrir: jsr WaitMessage
lda #<reglages
sta ControlPort+4
lda #>reglages
sta ControlPort+5
lda #37
ldx #1
jsr appel
lda ControlPort+6
sta dlg
lda ControlPort+7
sta fen
lda ControlPort+2
rts
; 37,X sur le dialogue A.
dial: pha
phx
jsr WaitMessage
plx
pla
sta ControlPort+4
lda #37
jmp appel
dlg: .byte 0
fen: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Bouton OK : 15, peint : 4, redessine : 1537,6 Alert Trinity
Ouvre une alerte centrée à l'écran, avec un message et un ou deux boutons.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | addr | adresse du message, précédé de sa longueur (13 : à la ligne) |
P2 | uint8 | boutons : 0 OK, 1 OK et Annuler, 2 Oui et Non |
| Octets | Type | Rôle |
|---|---|---|
P3 | uint8 | numéro du dialogue |
P4 | uint8 | sa fenêtre |
L'élément 1 est le premier bouton (OK ou Oui, par défaut, à droite), l'élément 2 le second (Annuler ou Non, annulation), l'élément 3 le message. Comme pour un dialogue : 37,3 jusqu'à l'élément 1 ou 2, puis 37,2. Le message doit rester intact tant que l'alerte est ouverte. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Opens an alert centred on the screen with the length-prefixed message at Parameters:0,1 (one line per character 13, 6x8 font) and, by Parameter:2, the buttons 0 OK, 1 OK and Cancel, 2 Yes and No ; returns the dialog number in Parameter:3 and its window in Parameter:4. Item 1 is the first button (OK / Yes, default, at the right), item 2 the second (Cancel / No, cancel), item 3 the message : run Dialog Event until item 1 or 2, then Dispose Dialog. The message must stay intact while the alert is up.
C (llvm-mos)
/* Ouvrir une alerte (groupe 37, fonction 6, Trinity). */
#include <stdio.h>
#include <neo6502.h>
#include <neo/api.h>
/* Appel brut de la boîte aux lettres : fonction puis groupe (écrit en dernier, il lance l'appel). */
static void api(uint8_t groupe, uint8_t fonction) {
ControlPort.function = fonction;
ControlPort.command = groupe;
while (ControlPort.command) /* attendre la fin */
;
}
static void libre(void) { /* attendre que la boîte aux lettres soit libre */
while (ControlPort.command)
;
}
/* Descripteur de dialogue, lu sur place : Rect de la fenêtre (écran), options (bit 0 barre de titre), titre ;
puis chaque élément : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ de texte, 6 texte fixe), options
(bit 0 inactif, bit 1 par défaut : Entrée, bit 2 annulation : Échap), Rect relatif au contenu, maximum,
texte précédé de sa longueur (un champ de texte réserve 1 + maximum octets) ; un 0 termine la liste. */
#define W(v) (v) & 0xFF, (v) >> 8
static uint8_t reglages[] = {
W(40), W(40), W(240), W(160), 1, 8, 'R', 'e', 'g', 'l', 'a', 'g', 'e', 's',
1, 2, W(130), W(90), W(190), W(104), W(0), 2, 'O', 'K', /* 1 : bouton par défaut */
1, 4, W(60), W(90), W(120), W(104), W(0), 7, 'A', 'n', 'n', 'u', 'l', 'e', 'r', /* 2 : annulation */
2, 0, W(10), W(10), W(100), W(22), W(0), 3, 'S', 'o', 'n', /* 3 : case à cocher */
5, 0, W(10), W(30), W(150), W(44), W(8), 2, 'a', 'b', 0, 0, 0, 0, 0, 0, /* 4 : champ de texte, 8 au plus */
6, 0, W(10), W(50), W(150), W(60), W(0), 7, 'B', 'o', 'n', 'j', 'o', 'u', 'r', /* 5 : texte fixe */
0 };
#define CHAMP 81 /* position du tampon de l'élément 4 dans le descripteur */
static void p16(uint8_t i, uint16_t v) { /* paramètre 16 bits en Pi, Pi+1 */
ControlPort.params[i] = v & 0xFF;
ControlPort.params[i + 1] = v >> 8;
}
static void reinit(void) { /* 32,19 Toolbox Reset */
libre();
api(32, 19);
}
static uint8_t dialogue, fenetre;
static uint8_t ouvrir(uint8_t *descripteur) { /* 37,1 New Dialog : rend l'indicateur d'erreur */
libre();
p16(0, (uint16_t)descripteur);
api(37, 1);
dialogue = ControlPort.params[2];
fenetre = ControlPort.params[3];
return ControlPort.error;
}
static void fermer(uint8_t d) { /* 37,2 Dispose Dialog */
libre();
ControlPort.params[0] = d;
api(37, 2);
}
/* Événements fabriqués comme ceux du groupe 33 : type, message, message2, modificateurs, X, Y. */
typedef struct { uint8_t what, message, message2, modifiers; int16_t x, y; } EventRecord;
static EventRecord ev;
static uint8_t a_lui;
static uint8_t evenement(uint8_t d, uint8_t what, uint8_t m, uint8_t m2, int16_t x, int16_t y) { /* 37,3 Dialog Event */
ev.what = what; ev.message = m; ev.message2 = m2; ev.modifiers = 0; ev.x = x; ev.y = y;
libre();
ControlPort.params[0] = d;
p16(1, (uint16_t)&ev);
api(37, 3);
a_lui = ControlPort.params[4]; /* 1 si l'événement appartenait au dialogue */
return ControlPort.params[3]; /* élément qui a agi, 0 si aucun */
}
static const char message[] = "\024Tout effacer ?\rSur ?"; /* 13 : à la ligne */
static uint8_t alerte(uint8_t boutons) { /* Alert : 0 OK, 1 OK et Annuler, 2 Oui et Non */
libre();
p16(0, (uint16_t)message);
ControlPort.params[2] = boutons;
api(37, 6);
return ControlPort.params[3]; /* numéro du dialogue */
}
int main(void) {
uint8_t d, t[3], i, ent, ech;
reinit();
d = alerte(2);
for (i = 0; i < 3; i++) {
libre(); ControlPort.params[0] = d; ControlPort.params[1] = i + 1; api(37, 4);
t[i] = ControlPort.params[3]; /* 1 Oui (par défaut), 2 Non (annulation), 3 le message */
}
ent = evenement(d, 1, 13, 0x28, 0, 0);
ech = evenement(d, 1, 27, 0x29, 0, 0);
fermer(d);
reinit();
printf("Alerte : dialogue %u, types %u %u %u\nEntree : %u, Echap : %u\n", d, t[0], t[1], t[2], ent, ech);
return 0;
}Alerte : dialogue 1, types 1 1 6
Entree : 1, Echap : 2Mad Pascal
// Ouvrir une alerte (groupe 37, fonction 6, Trinity).
program dl6;
uses crt, neo6502;
// Descripteur de dialogue (variable : le firmware écrit dans le champ de texte), lu sur place : Rect de la
// fenêtre (écran), options (bit 0 barre de titre), titre ; puis chaque élément : type (1 bouton, 2 case, 3 radio,
// 4 barre, 5 champ de texte, 6 texte fixe), options (bit 0 inactif, bit 1 par défaut : Entrée, bit 2 annulation :
// Échap), Rect relatif au contenu, maximum, texte précédé de sa longueur (un champ de texte réserve 1 + maximum
// octets) ; un 0 termine la liste.
var reglages: array[0..110] of byte = (
40, 0, 40, 0, 240, 0, 160, 0, 1, 8, ord('R'), ord('e'), ord('g'), ord('l'), ord('a'), ord('g'), ord('e'), ord('s'),
1, 2, 130, 0, 90, 0, 190, 0, 104, 0, 0, 0, 2, ord('O'), ord('K'), // 1 : bouton par défaut
1, 4, 60, 0, 90, 0, 120, 0, 104, 0, 0, 0, 7, ord('A'), ord('n'), ord('n'), ord('u'), ord('l'), ord('e'), ord('r'), // 2 : annulation
2, 0, 10, 0, 10, 0, 100, 0, 22, 0, 0, 0, 3, ord('S'), ord('o'), ord('n'), // 3 : case à cocher
5, 0, 10, 0, 30, 0, 150, 0, 44, 0, 8, 0, 2, ord('a'), ord('b'), 0, 0, 0, 0, 0, 0, // 4 : champ de texte, 8 au plus
6, 0, 10, 0, 50, 0, 150, 0, 60, 0, 0, 0, 7, ord('B'), ord('o'), ord('n'), ord('j'), ord('o'), ord('u'), ord('r'), // 5 : texte fixe
0);
const CHAMP = 81; // position du tampon de l'élément 4 dans le descripteur
var dialogue, fenetre: byte;
procedure appel(g, f: byte); // appel g,f (paramètres déjà posés)
begin
NeoSendMessage(g, f);
NeoWaitMessage;
end;
procedure reinit; // 32,19 Toolbox Reset
begin
NeoWaitMessage;
appel(32, 19);
end;
function ouvrir(descripteur: pointer): byte; // 37,1 New Dialog : rend l'indicateur d'erreur
begin
NeoWaitMessage;
wordParams[0] := word(descripteur);
appel(37, 1);
dialogue := NeoMessage.params[2];
fenetre := NeoMessage.params[3];
result := NeoMessage.error;
end;
procedure fermer(d: byte); // 37,2 Dispose Dialog
begin
NeoWaitMessage;
NeoMessage.params[0] := d;
appel(37, 2);
end;
// Événements fabriqués comme ceux du groupe 33 : type, message, message2, modificateurs, X, Y.
type EventRecord = record what, message, message2, modifiers: byte; x, y: smallint; end;
var ev: EventRecord;
a_lui: byte;
function evenement(d, what, m, m2: byte; x, y: smallint): byte; // 37,3 Dialog Event
begin
ev.what := what; ev.message := m; ev.message2 := m2; ev.modifiers := 0; ev.x := x; ev.y := y;
NeoWaitMessage;
NeoMessage.params[0] := d;
NeoMessage.params[1] := lo(word(@ev));
NeoMessage.params[2] := hi(word(@ev));
appel(37, 3);
a_lui := NeoMessage.params[4]; // 1 si l'événement appartenait au dialogue
result := NeoMessage.params[3]; // élément qui a agi, 0 si aucun
end;
const message: array[0..20] of byte = (20, ord('T'), ord('o'), ord('u'), ord('t'), ord(' '), ord('e'), ord('f'), ord('f'),
ord('a'), ord('c'), ord('e'), ord('r'), ord(' '), ord('?'), 13, ord('S'), ord('u'), ord('r'), ord(' '), ord('?')); // 13 : à la ligne
function alerte(boutons: byte): byte; // Alert : 0 OK, 1 OK et Annuler, 2 Oui et Non
begin
NeoWaitMessage;
wordParams[0] := word(@message);
NeoMessage.params[2] := boutons;
appel(37, 6);
result := NeoMessage.params[3]; // numéro du dialogue
end;
var d, i, ent, ech: byte;
t: array[0..2] of byte;
begin
reinit;
d := alerte(2);
for i := 0 to 2 do begin
NeoWaitMessage; NeoMessage.params[0] := d; NeoMessage.params[1] := i + 1; appel(37, 4);
t[i] := NeoMessage.params[3]; // 1 Oui (par défaut), 2 Non (annulation), 3 le message
end;
ent := evenement(d, 1, 13, $28, 0, 0);
ech := evenement(d, 1, 27, $29, 0, 0);
fermer(d);
reinit;
writeln('Alerte : dialogue ', d, ', types ', t[0], ' ', t[1], ' ', t[2]);
writeln('Entree : ', ent, ', Echap : ', ech);
end.Alerte : dialogue 1, types 1 1 6
Entree : 1, Echap : 2NeoBASIC
10 ' Ouvrir une alerte (groupe 37, fonction 6, Trinity)
15 gosub 7000
20 ev = alloc(8)
30 m$ = "Tout effacer ?" + chr$(13) + "Sur ?" : ' 13 : a la ligne
40 mg = alloc(len(m$) + 1) : poke mg, len(m$) : for i = 1 to len(m$) : poke mg + i, asc(mid$(m$, i, 1)) : next i
50 gosub 8300
60 while peek($ff00) : wend : doke $ff04, mg : poke $ff06, 2 : f = 6 : gosub 8110 : ' Alert : 2 = Oui et Non
70 dg = peek($ff07)
80 dim t(2) : for k = 0 to 2
90 while peek($ff00) : wend : poke $ff04, dg : poke $ff05, k + 1 : f = 4 : gosub 8110 : t(k) = peek($ff07) : next k
100 wh = 1 : ms = 13 : m2 = $28 : ex = 0 : ey = 0 : gosub 7500 : en = it
110 ms = 27 : m2 = $29 : gosub 7500 : ec = it
120 gosub 8200 : gosub 8300
130 print "Alerte : dialogue ";dg;", types ";t(0);" ";t(1);" ";t(2)
140 print "Entree : ";en;", Echap : ";ec
150 end
7500 ' 37,3 Dialog Event : evenement fabrique (type wh, message ms, message2 m2, X ex, Y ey) pour le dialogue dg
7510 ' element qui a agi dans it (0 si aucun), al = 1 si l'evenement appartenait au dialogue
7520 poke ev, wh : poke ev + 1, ms : poke ev + 2, m2 : poke ev + 3, 0 : doke ev + 4, ex : doke ev + 6, ey
7530 while peek($ff00) : wend : poke $ff04, dg : doke $ff05, ev : f = 3 : gosub 8110
7540 it = peek($ff07) : al = peek($ff08) : return
7000 ' descripteur de dialogue, lu sur place : Rect de la fenetre (ecran), options (bit 0 barre de titre), titre ;
7005 ' puis chaque element : type (1 bouton, 2 case, 3 radio, 4 barre, 5 champ, 6 texte fixe), options (bit 0 inactif,
7010 ' bit 1 par defaut : Entree, bit 2 annulation : Echap), Rect relatif au contenu, maximum, texte precede de sa
7015 ' longueur (un champ de texte reserve 1 + maximum octets) ; un 0 termine la liste. Adresse dans rg.
7020 rg = alloc(111) : p = rg
7025 for k = 1 to 4 : read v : doke p, v : p = p + 2 : next k : read v : poke p, v : p = p + 1 : read s$ : gosub 7100
7030 for it = 1 to 5 : read ty, op : poke p, ty : poke p + 1, op : p = p + 2
7035 for k = 1 to 5 : read v : doke p, v : p = p + 2 : next k : read s$ : p0 = p : gosub 7100
7040 if ty = 5 then p = p0 + 1 + v : ' le champ reserve 1 + maximum octets
7045 next it : poke p, 0 : ch = rg + 81 : return : ' ch : tampon de l'element 4
7050 data 40, 40, 240, 160, 1, "Reglages"
7055 data 1, 2, 130, 90, 190, 104, 0, "OK" : ' 1 : bouton par defaut
7060 data 1, 4, 60, 90, 120, 104, 0, "Annuler" : ' 2 : annulation
7065 data 2, 0, 10, 10, 100, 22, 0, "Son" : ' 3 : case a cocher
7070 data 5, 0, 10, 30, 150, 44, 8, "ab" : ' 4 : champ de texte, 8 au plus
7075 data 6, 0, 10, 50, 150, 60, 0, "Bonjour" : ' 5 : texte fixe
7100 poke p, len(s$) : for i = 1 to len(s$) : poke p + i, asc(mid$(s$, i, 1)) : next i : p = p + len(s$) + 1 : return
8000 ' 37,1 New Dialog sur le descripteur q : dialogue dans dg, fenetre dans fw, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 dg = peek($ff06) : fw = peek($ff07) : return
8100 ' appel 37,f, parametres deja poses ; erreur dans e
8110 poke $ff01, f : poke $ff00, 37
8120 while peek($ff00) : wend : e = peek($ff02) : return
8200 ' 37,2 Dispose Dialog dg
8210 while peek($ff00) : wend : poke $ff04, dg : f = 2 : goto 8110
8300 ' 32,19 Toolbox Reset
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnAlerte : dialogue 1, types 1 1 6
Entree : 1, Echap : 2Assembleur 65C02 (64tass)
; Ouvrir une alerte (groupe 37, fonction 6, Trinity).
.cpu "65c02"
* = $0800
ControlPort = $FF00 ; +0 groupe, +1 fonction, +2 erreur, +4.. paramètres
WaitMessage = $FFF4 ; attend que la boîte aux lettres soit libre
WriteCharacter = $FFF1 ; affiche le caractère de A
start: lda #<b0
ldx #>b0
jsr envoi
lda #<b1
ldx #>b1
jsr envoi
lda ControlPort+7 ; numéro du dialogue
sta d
ldx #1
_el: phx
jsr WaitMessage
plx
stx ControlPort+5
phx
lda d
ldx #4 ; 37,4 : 1 Oui (par défaut), 2 Non (annulation), 3 le message
jsr dial
plx
lda ControlPort+7
sta t-1,x
inx
cpx #4
bne _el
lda #1
sta ev
lda #13
sta ev+1
lda #$28
sta ev+2
lda #0
sta ev+4
lda #0
sta ev+6
lda d
jsr evenement
sta en
lda #1
sta ev
lda #27
sta ev+1
lda #$29
sta ev+2
lda #0
sta ev+4
lda #0
sta ev+6
lda d
jsr evenement
sta ec
lda d
ldx #2 ; 37,2
jsr dial
lda #<b2
ldx #>b2
jsr envoi
lda #<t3
ldx #>t3
jsr ecrire
lda d
jsr decimal
lda #<t4
ldx #>t4
jsr ecrire
lda t
jsr decimal
lda #<t5
ldx #>t5
jsr ecrire
lda t+1
jsr decimal
lda #<t6
ldx #>t6
jsr ecrire
lda t+2
jsr decimal
lda #13
jsr WriteCharacter
lda #<t7
ldx #>t7
jsr ecrire
lda en
jsr decimal
lda #<t8
ldx #>t8
jsr ecrire
lda ec
jsr decimal
lda #13
jsr WriteCharacter
rts
message: .byte 20
.text "Tout effacer ?", 13, "Sur ?" ; 13 : à la ligne
t: .fill 3
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset
b1: .byte 37, 6, 3 ; Alert : 2 = Oui et Non
.word message
.byte 2
d: .byte 0
en: .byte 0
ec: .byte 0
b2: .byte 32, 19, 0 ; 32,19 Toolbox Reset
t3: .text "Alerte : dialogue ", 0
t4: .text ", types ", 0
t5: .text " ", 0
t6: .text " ", 0
t7: .text "Entree : ", 0
t8: .text ", Echap : ", 0
; 37,3 Dialog Event : l'événement ev (fabriqué comme ceux du groupe 33 : type, message, message2,
; modificateurs, X, Y) pour le dialogue A ; élément qui a agi dans A (0 si aucun), appartenance dans alui.
evenement:
pha
jsr WaitMessage
pla
sta ControlPort+4
lda #<ev
sta ControlPort+5
lda #>ev
sta ControlPort+6
lda #37
ldx #3
jsr appel
lda ControlPort+8 ; 1 si l'événement appartenait au dialogue
sta alui
lda ControlPort+7 ; élément qui a agi
rts
ev: .byte 0, 0, 0, 0
.word 0, 0
alui: .byte 0
; Appel décrit par un bloc dont l'adresse est dans A (poids faible) et X (poids fort) :
; groupe, fonction, nombre de paramètres, puis les paramètres (P0, P1...).
envoi: sta blk
stx blk+1
jsr WaitMessage
ldy #2
lda (blk),y ; nombre de paramètres
clc
adc #3
sta fin
ldy #3
_copie: cpy fin
beq _lance
lda (blk),y
sta ControlPort+1,y ; octet 3 du bloc -> P0 ($FF04)...
iny
bra _copie
_lance: ldy #1
lda (blk),y
tax
lda (blk)
jmp appel
; Affiche la chaîne terminée par 0 dont l'adresse est dans A (poids faible) et X (poids fort).
ecrire: sta ptr
stx ptr+1
ldy #0
_e: lda (ptr),y
beq _f
jsr WriteCharacter
iny
bne _e
_f: rts
; Affiche A (0-255) en décimal, sans zéros de tête.
decimal:
phx
phy
ldx #0
ldy #100
jsr _chiffre
ldy #10
jsr _chiffre
ora #'0'
jsr WriteCharacter
ply
plx
rts
_chiffre:
sty diviseur
ldy #0
_div: cmp diviseur
bcc _fini
sbc diviseur
iny
bne _div
_fini: pha
tya
bne _ecrit
cpx #0
beq _saute
_ecrit: ora #'0'
jsr WriteCharacter
ldx #1
_saute: pla
rts
; Affiche le mot de 16 bits A (poids faible), X (poids fort) en décimal, sans zéros de tête.
dec16: sta n16
stx n16+1
stz vu
ldy #0 ; puissance de 10 en cours : 10000, 1000, 100, 10
_p: ldx #0 ; chiffre
_s: lda n16
sec
sbc p10l,y
pha
lda n16+1
sbc p10h,y
bcc _neg ; plus petit : chiffre trouvé
sta n16+1
pla
sta n16
inx
bra _s
_neg: pla
txa
ora vu
beq _suiv ; pas de zéro de tête
txa
ora #'0'
phy
jsr WriteCharacter
ply
lda #1
sta vu
_suiv: iny
cpy #4
bne _p
lda n16 ; les unités, toujours
ora #'0'
jmp WriteCharacter
p10l: .byte <10000, <1000, <100, <10
p10h: .byte >10000, >1000, >100, >10
n16: .word 0
vu: .byte 0
; 37,X sur le dialogue A.
dial: pha
phx
jsr WaitMessage
plx
pla
sta ControlPort+4
lda #37
jmp appel
dlg: .byte 0
fen: .byte 0
; Appel : A = groupe, X = fonction (les paramètres sont déjà en place).
appel: stx ControlPort+1
sta ControlPort ; écrit en dernier : lance l'appel
jmp WaitMessage
ptr = $80
blk = $82
diviseur: .byte 0
fin: .byte 0Alerte : dialogue 1, types 1 1 6
Entree : 1, Echap : 2