Groupe 35 — Gestionnaire de menus Trinity
35,1 New Menu · 35,2 Draw Menu Bar · 35,3 Menu Select · 35,4 Menu Track · 35,5 Menu Track End · 35,6 Set Item Flags · 35,7 Dispose Menu · 35,8 Get Item Flags · 35,9 Set Menu Bar Bounds · 35,10 Menu Key
Le gestionnaire de menus de la boîte à outils de Trinity tient une barre de menus en haut de l'écran (12 lignes) et jusqu'à 6 menus déroulants, décrits par des descripteurs en RAM du 6502.
À la souris : 35,3 sur un clic, 35,4 à chaque mouvement, 35,5 au relâchement. Au clavier : 35,10 avec le code de chaque touche. Les exemples appellent ces fonctions avec des coordonnées et des codes de touches fixes, sans souris ni clavier réels, et remettent la boîte à outils à zéro avec 32,19 au début et à la fin.
Les deux menus des exemples : « Fichier » (Ouvrir, Fermer inactif, un séparateur, Quitter) et « Edition » (Copier coché, Coller).
35,1 New Menu Trinity
Ajoute un menu à la barre des menus, à partir d'un descripteur en RAM du 6502, et rend son numéro.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | addr | adresse du descripteur (lu sur place) |
| Octets | Type | Rôle |
|---|---|---|
P2 | uint8 | numéro du menu (1 à 6) |
erreur | uint8 | 2 s'il ne reste plus de menu libre |
Descripteur : titre précédé de sa longueur, puis jusqu'à 16 articles, chacun un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) suivi de son texte précédé de sa longueur (31 caractères au plus), enfin l'octet $FF. Il doit rester intact : le firmware le relit et y écrit (35,6). La barre occupe les 12 premières lignes de l'écran (fond blanc, titres noirs en police 6 × 8) ; les fenêtres doivent rester dessous. Au banc, le septième menu 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). Adds a menu to the menu bar from the descriptor at Parameters:0,1 in 6502 RAM and returns its number (1-6) in Parameter:2 (error 2 if none left). The descriptor is read in place and must stay intact : a length-prefixed title, then up to 16 items, each a flags byte (bit 0 disabled, bit 1 checked, bit 7 separator) followed by a length-prefixed text (31 characters at most), ended by a $FF byte. The menu bar (12 lines at the top of the screen, titles in the 6x8 font) is redrawn ; keep windows below it.
C (llvm-mos)
/* Ajouter un menu à la barre (groupe 35, 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)
;
}
/* Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF. */
static uint8_t fichier[] = { 7, 'F', 'i', 'c', 'h', 'i', 'e', 'r',
0, 6, 'O', 'u', 'v', 'r', 'i', 'r', /* article 1 */
1, 6, 'F', 'e', 'r', 'm', 'e', 'r', /* article 2, inactif */
0x80, 0, /* article 3 : séparateur */
0, 7, 'Q', 'u', 'i', 't', 't', 'e', 'r', 0xFF }; /* article 4 */
static uint8_t edition[] = { 7, 'E', 'd', 'i', 't', 'i', 'o', 'n',
2, 6, 'C', 'o', 'p', 'i', 'e', 'r', /* coché */
0, 6, 'C', 'o', 'l', 'l', 'e', 'r', 0xFF };
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 uint8_t nouveau(uint8_t *menu) { /* 35,1 New Menu : rend le numéro */
libre();
p16(0, (uint16_t)menu);
api(35, 1);
return ControlPort.params[2];
}
static uint8_t point(uint8_t f, int16_t x, int16_t y) { /* 35,3 Menu Select ou 35,4 Menu Track en (x, y) */
libre();
p16(0, x);
p16(2, y);
api(35, f);
return ControlPort.params[4]; /* 35,3 : menu déroulé, 0 si aucun titre touché */
}
static uint8_t choix_menu, choix_article;
static void fin(void) { /* 35,5 Menu Track End : menu et article choisis */
libre();
api(35, 5);
choix_menu = ControlPort.params[0];
choix_article = ControlPort.params[1];
}
static void reinit(void) { /* 32,19 Toolbox Reset : plus aucun menu */
libre();
api(32, 19);
}
int main(void) {
uint8_t a, b, i, e;
reinit();
a = nouveau(fichier);
b = nouveau(edition);
for (i = 0; i < 5; i++) /* menus 3 à 6, puis un septième */
nouveau(edition);
e = ControlPort.error;
reinit();
printf("Menus : %u et %u ; septieme : erreur %u\n", a, b, e);
return 0;
}Menus : 1 et 2 ; septieme : erreur 2Mad Pascal
// Ajouter un menu à la barre (groupe 35, fonction 1, Trinity).
program mn1;
uses crt, neo6502;
// Descripteurs de menus (variables : le firmware y écrit), lus sur place : titre précédé de sa longueur, puis pour chaque article un octet
// d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
var fichier: array[0..35] of byte = (7, ord('F'), ord('i'), ord('c'), ord('h'), ord('i'), ord('e'), ord('r'),
0, 6, ord('O'), ord('u'), ord('v'), ord('r'), ord('i'), ord('r'), // article 1
1, 6, ord('F'), ord('e'), ord('r'), ord('m'), ord('e'), ord('r'), // article 2, inactif
$80, 0, // article 3 : séparateur
0, 7, ord('Q'), ord('u'), ord('i'), ord('t'), ord('t'), ord('e'), ord('r'), $FF); // article 4
edition: array[0..24] of byte = (7, ord('E'), ord('d'), ord('i'), ord('t'), ord('i'), ord('o'), ord('n'),
2, 6, ord('C'), ord('o'), ord('p'), ord('i'), ord('e'), ord('r'), // coché
0, 6, ord('C'), ord('o'), ord('l'), ord('l'), ord('e'), ord('r'), $FF);
procedure appel(f: byte); // appel 35,f (paramètres déjà posés)
begin
NeoSendMessage(35, f);
NeoWaitMessage;
end;
function nouveau(menu: pointer): byte; // 35,1 New Menu : rend le numéro
begin
NeoWaitMessage;
wordParams[0] := word(menu);
appel(1);
result := NeoMessage.params[2];
end;
function point(f: byte; x, y: smallint): byte; // 35,3 Menu Select ou 35,4 Menu Track en (x, y)
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
appel(f);
result := NeoMessage.params[4]; // 35,3 : menu déroulé, 0 si aucun titre touché
end;
var choix_menu, choix_article: byte;
procedure fin; // 35,5 Menu Track End : menu et article choisis
begin
NeoWaitMessage;
appel(5);
choix_menu := NeoMessage.params[0];
choix_article := NeoMessage.params[1];
end;
procedure reinit; // 32,19 Toolbox Reset : plus aucun menu
begin
NeoWaitMessage;
NeoSendMessage(32, 19);
NeoWaitMessage;
end;
var a, b, i, e: byte;
begin
reinit;
a := nouveau(@fichier);
b := nouveau(@edition);
for i := 1 to 5 do nouveau(@edition); // menus 3 à 6, puis un septième
e := NeoMessage.error;
reinit;
writeln('Menus : ', a, ' et ', b, ' ; septieme : erreur ', e);
end.Menus : 1 et 2 ; septieme : erreur 2NeoBASIC
10 ' Ajouter un menu a la barre (groupe 35, fonction 1, Trinity)
15 gosub 7000
20 gosub 8300
30 q = fi : gosub 8000 : a = mn
40 q = ed : gosub 8000 : b = mn
50 for k = 1 to 5 : gosub 8000 : next k : ' menus 3 a 6, puis un septieme
60 e7 = e : gosub 8300
70 print "Menus : ";a;" et ";b;" ; septieme : erreur ";e7
80 end
7000 ' descripteurs de menus, lus sur place : titre precede de sa longueur, puis pour chaque article
7010 ' un octet d'options (bit 0 inactif, bit 1 coche, bit 7 separateur) et son texte, enfin $FF
7020 fi = alloc(36) : p = fi : s$ = "Fichier" : gosub 7100
7030 poke p, 0 : p = p + 1 : s$ = "Ouvrir" : gosub 7100 : ' article 1
7040 poke p, 1 : p = p + 1 : s$ = "Fermer" : gosub 7100 : ' article 2, inactif
7050 poke p, $80 : poke p + 1, 0 : p = p + 2 : ' article 3 : separateur
7060 poke p, 0 : p = p + 1 : s$ = "Quitter" : gosub 7100 : poke p, $ff : ' article 4
7070 ed = alloc(25) : p = ed : s$ = "Edition" : gosub 7100
7080 poke p, 2 : p = p + 1 : s$ = "Copier" : gosub 7100 : ' coche
7090 poke p, 0 : p = p + 1 : s$ = "Coller" : gosub 7100 : poke p, $ff : return
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 ' 35,1 New Menu, descripteur en q : numero dans mn, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 mn = peek($ff06) : return
8100 ' 35,3 Menu Select ou 35,4 Menu Track en (x, y) : menu deroule dans r (35,3)
8105 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y
8110 poke $ff01, f : poke $ff00, 35
8120 while peek($ff00) : wend : r = peek($ff08) : e = peek($ff02) : return
8200 ' 35,5 Menu Track End : menu dans cm, article dans ca
8210 while peek($ff00) : wend : f = 5 : gosub 8110
8220 cm = peek($ff04) : ca = peek($ff05) : return
8300 ' 32,19 Toolbox Reset : plus aucun menu
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnMenus : 1 et 2 ; septieme : erreur 2Assembleur 65C02 (64tass)
; Ajouter un menu à la barre (groupe 35, 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
lda #<b1
ldx #>b1
jsr envoi
lda ControlPort+6 ; P2 : numéro du menu
sta a
lda #<b2
ldx #>b2
jsr envoi
lda ControlPort+6 ; P2 : numéro du menu
sta b
ldx #5 ; menus 3 à 6, puis un septième
_n: phx
lda #<b2
ldx #>b2
jsr envoi
plx
dex
bne _n
lda ControlPort+2
sta e
lda #<b3
ldx #>b3
jsr envoi
lda #<t4
ldx #>t4
jsr ecrire
lda a
jsr decimal
lda #<t5
ldx #>t5
jsr ecrire
lda b
jsr decimal
lda #<t6
ldx #>t6
jsr ecrire
lda e
jsr decimal
lda #13
jsr WriteCharacter
rts
; Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
; un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
fichier: .byte 7
.text "Fichier"
.byte 0, 6
.text "Ouvrir" ; article 1
fermer: .byte 1, 6
.text "Fermer" ; article 2, inactif
.byte $80, 0 ; article 3 : séparateur
.byte 0, 7
.text "Quitter" ; article 4
.byte $FF
edition: .byte 7
.text "Edition"
.byte 2, 6
.text "Copier" ; coché
.byte 0, 6
.text "Coller"
.byte $FF
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus aucun menu
b1: .byte 35, 1, 2 ; 35,1 : New Menu
.word fichier
a: .byte 0
b2: .byte 35, 1, 2 ; 35,1 : New Menu
.word edition
b: .byte 0
e: .byte 0
b3: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus aucun menu
t4: .text "Menus : ", 0
t5: .text " et ", 0
t6: .text " ; septieme : 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
; 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 0Menus : 1 et 2 ; septieme : erreur 235,2 Draw Menu Bar Trinity
Redessine la barre des menus, par exemple après que le programme a dessiné dessus.
Entrées : aucune.
Sorties : aucune.
L'exemple peint la barre en couleur 4 avec 32,8, puis la fait redessiner : le fond redevient blanc (15). NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Redraws the menu bar (after the program drew over it, for instance).
C (llvm-mos)
/* Redessiner la barre des menus (groupe 35, 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)
;
}
/* Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF. */
static uint8_t fichier[] = { 7, 'F', 'i', 'c', 'h', 'i', 'e', 'r',
0, 6, 'O', 'u', 'v', 'r', 'i', 'r', /* article 1 */
1, 6, 'F', 'e', 'r', 'm', 'e', 'r', /* article 2, inactif */
0x80, 0, /* article 3 : séparateur */
0, 7, 'Q', 'u', 'i', 't', 't', 'e', 'r', 0xFF }; /* article 4 */
static uint8_t edition[] = { 7, 'E', 'd', 'i', 't', 'i', 'o', 'n',
2, 6, 'C', 'o', 'p', 'i', 'e', 'r', /* coché */
0, 6, 'C', 'o', 'l', 'l', 'e', 'r', 0xFF };
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 uint8_t nouveau(uint8_t *menu) { /* 35,1 New Menu : rend le numéro */
libre();
p16(0, (uint16_t)menu);
api(35, 1);
return ControlPort.params[2];
}
static uint8_t point(uint8_t f, int16_t x, int16_t y) { /* 35,3 Menu Select ou 35,4 Menu Track en (x, y) */
libre();
p16(0, x);
p16(2, y);
api(35, f);
return ControlPort.params[4]; /* 35,3 : menu déroulé, 0 si aucun titre touché */
}
static uint8_t choix_menu, choix_article;
static void fin(void) { /* 35,5 Menu Track End : menu et article choisis */
libre();
api(35, 5);
choix_menu = ControlPort.params[0];
choix_article = ControlPort.params[1];
}
static void reinit(void) { /* 32,19 Toolbox Reset : plus aucun menu */
libre();
api(32, 19);
}
typedef struct { int16_t g, h, d, b; } Rect;
static Rect barre = {0, 0, 320, 12};
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 p1, p2, p3, t;
reinit();
nouveau(fichier);
p1 = pixel(1, 2); /* fond de la barre */
t = pixel(5, 2); /* texte du titre */
libre(); ControlPort.params[0] = 4; api(32, 4);
libre(); p16(0, (uint16_t)&barre); api(32, 8); /* le programme peint par-dessus la barre */
p2 = pixel(1, 2);
libre(); api(35, 2); /* Draw Menu Bar */
p3 = pixel(1, 2);
reinit();
printf("Barre : %u (titre %u), peinte : %u, redessinee : %u\n", p1, t, p2, p3);
return 0;
}Barre : 15 (titre 0), peinte : 4, redessinee : 15Mad Pascal
// Redessiner la barre des menus (groupe 35, fonction 2, Trinity).
program mn2;
uses crt, neo6502;
// Descripteurs de menus (variables : le firmware y écrit), lus sur place : titre précédé de sa longueur, puis pour chaque article un octet
// d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
var fichier: array[0..35] of byte = (7, ord('F'), ord('i'), ord('c'), ord('h'), ord('i'), ord('e'), ord('r'),
0, 6, ord('O'), ord('u'), ord('v'), ord('r'), ord('i'), ord('r'), // article 1
1, 6, ord('F'), ord('e'), ord('r'), ord('m'), ord('e'), ord('r'), // article 2, inactif
$80, 0, // article 3 : séparateur
0, 7, ord('Q'), ord('u'), ord('i'), ord('t'), ord('t'), ord('e'), ord('r'), $FF); // article 4
edition: array[0..24] of byte = (7, ord('E'), ord('d'), ord('i'), ord('t'), ord('i'), ord('o'), ord('n'),
2, 6, ord('C'), ord('o'), ord('p'), ord('i'), ord('e'), ord('r'), // coché
0, 6, ord('C'), ord('o'), ord('l'), ord('l'), ord('e'), ord('r'), $FF);
procedure appel(f: byte); // appel 35,f (paramètres déjà posés)
begin
NeoSendMessage(35, f);
NeoWaitMessage;
end;
function nouveau(menu: pointer): byte; // 35,1 New Menu : rend le numéro
begin
NeoWaitMessage;
wordParams[0] := word(menu);
appel(1);
result := NeoMessage.params[2];
end;
function point(f: byte; x, y: smallint): byte; // 35,3 Menu Select ou 35,4 Menu Track en (x, y)
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
appel(f);
result := NeoMessage.params[4]; // 35,3 : menu déroulé, 0 si aucun titre touché
end;
var choix_menu, choix_article: byte;
procedure fin; // 35,5 Menu Track End : menu et article choisis
begin
NeoWaitMessage;
appel(5);
choix_menu := NeoMessage.params[0];
choix_article := NeoMessage.params[1];
end;
procedure reinit; // 32,19 Toolbox Reset : plus aucun menu
begin
NeoWaitMessage;
NeoSendMessage(32, 19);
NeoWaitMessage;
end;
type Rect = record g, h, d, b: smallint; end;
var barre: Rect;
p1, p2, p3, t: byte;
begin
barre.g := 0; barre.h := 0; barre.d := 320; barre.b := 12;
reinit;
nouveau(@fichier);
p1 := NeoGetPixel(1, 2); // fond de la barre
t := NeoGetPixel(5, 2); // texte du titre
NeoWaitMessage;
NeoMessage.params[0] := 4;
NeoSendMessage(32, 4);
NeoWaitMessage;
wordParams[0] := word(@barre);
NeoSendMessage(32, 8); // le programme peint par-dessus la barre
NeoWaitMessage;
p2 := NeoGetPixel(1, 2);
appel(2); // Draw Menu Bar
p3 := NeoGetPixel(1, 2);
reinit;
writeln('Barre : ', p1, ' (titre ', t, '), peinte : ', p2, ', redessinee : ', p3);
end.Barre : 15 (titre 0), peinte : 4, redessinee : 15NeoBASIC
10 ' Redessiner la barre des menus (groupe 35, fonction 2, Trinity)
15 gosub 7000
20 ba = alloc(8) : doke ba, 0 : doke ba + 2, 0 : doke ba + 4, 320 : doke ba + 6, 12
30 gosub 8300
40 q = fi : gosub 8000
50 p1 = point(1, 2) : t = point(5, 2) : ' fond de la barre, texte du titre
60 while peek($ff00) : wend : poke $ff04, 4 : poke $ff01, 4 : poke $ff00, 32
70 while peek($ff00) : wend : doke $ff04, ba : poke $ff01, 8 : poke $ff00, 32 : ' le programme peint par-dessus la barre
80 while peek($ff00) : wend : p2 = point(1, 2)
90 f = 2 : gosub 8110 : ' Draw Menu Bar
100 p3 = point(1, 2)
110 gosub 8300
120 print "Barre : ";p1;" (titre ";t;"), peinte : ";p2;", redessinee : ";p3
130 end
7000 ' descripteurs de menus, lus sur place : titre precede de sa longueur, puis pour chaque article
7010 ' un octet d'options (bit 0 inactif, bit 1 coche, bit 7 separateur) et son texte, enfin $FF
7020 fi = alloc(36) : p = fi : s$ = "Fichier" : gosub 7100
7030 poke p, 0 : p = p + 1 : s$ = "Ouvrir" : gosub 7100 : ' article 1
7040 poke p, 1 : p = p + 1 : s$ = "Fermer" : gosub 7100 : ' article 2, inactif
7050 poke p, $80 : poke p + 1, 0 : p = p + 2 : ' article 3 : separateur
7060 poke p, 0 : p = p + 1 : s$ = "Quitter" : gosub 7100 : poke p, $ff : ' article 4
7070 ed = alloc(25) : p = ed : s$ = "Edition" : gosub 7100
7080 poke p, 2 : p = p + 1 : s$ = "Copier" : gosub 7100 : ' coche
7090 poke p, 0 : p = p + 1 : s$ = "Coller" : gosub 7100 : poke p, $ff : return
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 ' 35,1 New Menu, descripteur en q : numero dans mn, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 mn = peek($ff06) : return
8100 ' 35,3 Menu Select ou 35,4 Menu Track en (x, y) : menu deroule dans r (35,3)
8105 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y
8110 poke $ff01, f : poke $ff00, 35
8120 while peek($ff00) : wend : r = peek($ff08) : e = peek($ff02) : return
8200 ' 35,5 Menu Track End : menu dans cm, article dans ca
8210 while peek($ff00) : wend : f = 5 : gosub 8110
8220 cm = peek($ff04) : ca = peek($ff05) : return
8300 ' 32,19 Toolbox Reset : plus aucun menu
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnBarre : 15 (titre 0), peinte : 4, redessinee : 15Assembleur 65C02 (64tass)
; Redessiner la barre des menus (groupe 35, 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
lda #<b1
ldx #>b1
jsr envoi
lda #1
ldy #2
jsr pixel
sta p1
lda #5
ldy #2
jsr pixel
sta t
lda #<b2
ldx #>b2
jsr envoi
lda #<b3
ldx #>b3
jsr envoi
lda #1
ldy #2
jsr pixel
sta p2
lda #<b4
ldx #>b4
jsr envoi
lda #1
ldy #2
jsr pixel
sta p3
lda #<b5
ldx #>b5
jsr envoi
lda #<t6
ldx #>t6
jsr ecrire
lda p1
jsr decimal
lda #<t7
ldx #>t7
jsr ecrire
lda t
jsr decimal
lda #<t8
ldx #>t8
jsr ecrire
lda p2
jsr decimal
lda #<t9
ldx #>t9
jsr ecrire
lda p3
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
; Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
; un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
fichier: .byte 7
.text "Fichier"
.byte 0, 6
.text "Ouvrir" ; article 1
fermer: .byte 1, 6
.text "Fermer" ; article 2, inactif
.byte $80, 0 ; article 3 : séparateur
.byte 0, 7
.text "Quitter" ; article 4
.byte $FF
edition: .byte 7
.text "Edition"
.byte 2, 6
.text "Copier" ; coché
.byte 0, 6
.text "Coller"
.byte $FF
barre: .word 0, 0, 320, 12
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus aucun menu
b1: .byte 35, 1, 2 ; 35,1 : New Menu
.word fichier
p1: .byte 0
t: .byte 0
b2: .byte 32, 4, 1, 4 ; 32,4 : couleur 4
b3: .byte 32, 8, 2 ; 32,8 : le programme peint par-dessus la barre
.word barre
p2: .byte 0
b4: .byte 35, 2, 0 ; Draw Menu Bar
p3: .byte 0
b5: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus aucun menu
t6: .text "Barre : ", 0
t7: .text " (titre ", 0
t8: .text "), peinte : ", 0
t9: .text ", redessinee : ", 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
; 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 0Barre : 15 (titre 0), peinte : 4, redessinee : 1535,3 Menu Select Trinity
À appeler sur un clic : si un titre de menu est touché, déroule ce menu et rend son numéro.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | int16 | X de la souris |
P2-P3 | int16 | Y de la souris |
| Octets | Type | Rôle |
|---|---|---|
P4 | uint8 | menu déroulé (0 si aucun titre touché) |
Le programme appelle ensuite 35,4 à chaque mouvement de la souris et 35,5 au relâchement du bouton. Rien n'est sauvé sous le menu déroulé : à sa fermeture, la zone est effacée et les fenêtres qu'il couvrait reçoivent un événement de mise à jour (groupe 33). Au banc, « Fichier » occupe x 0 à 49 et « Edition » x 54 à 103. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
To call on a mouse down at Parameters:0,1 (X), Parameters:2,3 (Y) : if a menu title is hit, the menu is pulled down and its number returned in Parameter:4 (0 otherwise). The program then calls Menu Track on every mouse move and Menu Track End on the mouse up. Nothing is saved under the pull-down : when it closes, the area is erased and the windows it covered get an update event (group 33).
C (llvm-mos)
/* Dérouler un menu sur un clic (groupe 35, 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)
;
}
/* Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF. */
static uint8_t fichier[] = { 7, 'F', 'i', 'c', 'h', 'i', 'e', 'r',
0, 6, 'O', 'u', 'v', 'r', 'i', 'r', /* article 1 */
1, 6, 'F', 'e', 'r', 'm', 'e', 'r', /* article 2, inactif */
0x80, 0, /* article 3 : séparateur */
0, 7, 'Q', 'u', 'i', 't', 't', 'e', 'r', 0xFF }; /* article 4 */
static uint8_t edition[] = { 7, 'E', 'd', 'i', 't', 'i', 'o', 'n',
2, 6, 'C', 'o', 'p', 'i', 'e', 'r', /* coché */
0, 6, 'C', 'o', 'l', 'l', 'e', 'r', 0xFF };
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 uint8_t nouveau(uint8_t *menu) { /* 35,1 New Menu : rend le numéro */
libre();
p16(0, (uint16_t)menu);
api(35, 1);
return ControlPort.params[2];
}
static uint8_t point(uint8_t f, int16_t x, int16_t y) { /* 35,3 Menu Select ou 35,4 Menu Track en (x, y) */
libre();
p16(0, x);
p16(2, y);
api(35, f);
return ControlPort.params[4]; /* 35,3 : menu déroulé, 0 si aucun titre touché */
}
static uint8_t choix_menu, choix_article;
static void fin(void) { /* 35,5 Menu Track End : menu et article choisis */
libre();
api(35, 5);
choix_menu = ControlPort.params[0];
choix_article = ControlPort.params[1];
}
static void reinit(void) { /* 32,19 Toolbox Reset : plus aucun menu */
libre();
api(32, 19);
}
int main(void) {
uint8_t a, b, c;
reinit();
nouveau(fichier);
nouveau(edition);
a = point(3, 10, 5); /* Menu Select sur le titre « Fichier »... */
fin();
b = point(3, 60, 5); /* ... sur « Edition » */
fin();
c = point(3, 10, 100); /* hors de la barre : rien n'est déroulé */
reinit();
printf("Fichier : %u, Edition : %u, hors de la barre : %u\n", a, b, c);
return 0;
}Fichier : 1, Edition : 2, hors de la barre : 0Mad Pascal
// Dérouler un menu sur un clic (groupe 35, fonction 3, Trinity).
program mn3;
uses crt, neo6502;
// Descripteurs de menus (variables : le firmware y écrit), lus sur place : titre précédé de sa longueur, puis pour chaque article un octet
// d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
var fichier: array[0..35] of byte = (7, ord('F'), ord('i'), ord('c'), ord('h'), ord('i'), ord('e'), ord('r'),
0, 6, ord('O'), ord('u'), ord('v'), ord('r'), ord('i'), ord('r'), // article 1
1, 6, ord('F'), ord('e'), ord('r'), ord('m'), ord('e'), ord('r'), // article 2, inactif
$80, 0, // article 3 : séparateur
0, 7, ord('Q'), ord('u'), ord('i'), ord('t'), ord('t'), ord('e'), ord('r'), $FF); // article 4
edition: array[0..24] of byte = (7, ord('E'), ord('d'), ord('i'), ord('t'), ord('i'), ord('o'), ord('n'),
2, 6, ord('C'), ord('o'), ord('p'), ord('i'), ord('e'), ord('r'), // coché
0, 6, ord('C'), ord('o'), ord('l'), ord('l'), ord('e'), ord('r'), $FF);
procedure appel(f: byte); // appel 35,f (paramètres déjà posés)
begin
NeoSendMessage(35, f);
NeoWaitMessage;
end;
function nouveau(menu: pointer): byte; // 35,1 New Menu : rend le numéro
begin
NeoWaitMessage;
wordParams[0] := word(menu);
appel(1);
result := NeoMessage.params[2];
end;
function point(f: byte; x, y: smallint): byte; // 35,3 Menu Select ou 35,4 Menu Track en (x, y)
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
appel(f);
result := NeoMessage.params[4]; // 35,3 : menu déroulé, 0 si aucun titre touché
end;
var choix_menu, choix_article: byte;
procedure fin; // 35,5 Menu Track End : menu et article choisis
begin
NeoWaitMessage;
appel(5);
choix_menu := NeoMessage.params[0];
choix_article := NeoMessage.params[1];
end;
procedure reinit; // 32,19 Toolbox Reset : plus aucun menu
begin
NeoWaitMessage;
NeoSendMessage(32, 19);
NeoWaitMessage;
end;
var a, b, c: byte;
begin
reinit;
nouveau(@fichier);
nouveau(@edition);
a := point(3, 10, 5); // Menu Select sur le titre « Fichier »...
fin;
b := point(3, 60, 5); // ... sur « Edition »
fin;
c := point(3, 10, 100); // hors de la barre : rien n'est déroulé
reinit;
writeln('Fichier : ', a, ', Edition : ', b, ', hors de la barre : ', c);
end.Fichier : 1, Edition : 2, hors de la barre : 0NeoBASIC
10 ' Derouler un menu sur un clic (groupe 35, fonction 3, Trinity)
15 gosub 7000
20 gosub 8300
30 q = fi : gosub 8000 : q = ed : gosub 8000
40 f = 3 : x = 10 : y = 5 : gosub 8100 : a = r : gosub 8200 : ' Menu Select sur le titre « Fichier »...
50 f = 3 : x = 60 : gosub 8100 : b = r : gosub 8200 : ' ... sur « Edition »
60 f = 3 : x = 10 : y = 100 : gosub 8100 : c = r : ' hors de la barre : rien n'est deroule
70 gosub 8300
80 print "Fichier : ";a;", Edition : ";b;", hors de la barre : ";c
90 end
7000 ' descripteurs de menus, lus sur place : titre precede de sa longueur, puis pour chaque article
7010 ' un octet d'options (bit 0 inactif, bit 1 coche, bit 7 separateur) et son texte, enfin $FF
7020 fi = alloc(36) : p = fi : s$ = "Fichier" : gosub 7100
7030 poke p, 0 : p = p + 1 : s$ = "Ouvrir" : gosub 7100 : ' article 1
7040 poke p, 1 : p = p + 1 : s$ = "Fermer" : gosub 7100 : ' article 2, inactif
7050 poke p, $80 : poke p + 1, 0 : p = p + 2 : ' article 3 : separateur
7060 poke p, 0 : p = p + 1 : s$ = "Quitter" : gosub 7100 : poke p, $ff : ' article 4
7070 ed = alloc(25) : p = ed : s$ = "Edition" : gosub 7100
7080 poke p, 2 : p = p + 1 : s$ = "Copier" : gosub 7100 : ' coche
7090 poke p, 0 : p = p + 1 : s$ = "Coller" : gosub 7100 : poke p, $ff : return
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 ' 35,1 New Menu, descripteur en q : numero dans mn, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 mn = peek($ff06) : return
8100 ' 35,3 Menu Select ou 35,4 Menu Track en (x, y) : menu deroule dans r (35,3)
8105 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y
8110 poke $ff01, f : poke $ff00, 35
8120 while peek($ff00) : wend : r = peek($ff08) : e = peek($ff02) : return
8200 ' 35,5 Menu Track End : menu dans cm, article dans ca
8210 while peek($ff00) : wend : f = 5 : gosub 8110
8220 cm = peek($ff04) : ca = peek($ff05) : return
8300 ' 32,19 Toolbox Reset : plus aucun menu
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnFichier : 1, Edition : 2, hors de la barre : 0Assembleur 65C02 (64tass)
; Dérouler un menu sur un clic (groupe 35, 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
lda #<b1
ldx #>b1
jsr envoi
lda #<b2
ldx #>b2
jsr envoi
lda #<b3
ldx #>b3
jsr envoi
lda ControlPort+8 ; P4 : menu déroulé
sta a
lda #<b4
ldx #>b4
jsr envoi
lda #<b5
ldx #>b5
jsr envoi
lda ControlPort+8 ; P4 : menu déroulé
sta b
lda #<b6
ldx #>b6
jsr envoi
lda #<b7
ldx #>b7
jsr envoi
lda ControlPort+8 ; P4 : menu déroulé
sta c
lda #<b8
ldx #>b8
jsr envoi
lda #<t9
ldx #>t9
jsr ecrire
lda a
jsr decimal
lda #<t10
ldx #>t10
jsr ecrire
lda b
jsr decimal
lda #<t11
ldx #>t11
jsr ecrire
lda c
jsr decimal
lda #13
jsr WriteCharacter
rts
; Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
; un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
fichier: .byte 7
.text "Fichier"
.byte 0, 6
.text "Ouvrir" ; article 1
fermer: .byte 1, 6
.text "Fermer" ; article 2, inactif
.byte $80, 0 ; article 3 : séparateur
.byte 0, 7
.text "Quitter" ; article 4
.byte $FF
edition: .byte 7
.text "Edition"
.byte 2, 6
.text "Copier" ; coché
.byte 0, 6
.text "Coller"
.byte $FF
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus aucun menu
b1: .byte 35, 1, 2 ; 35,1 : New Menu
.word fichier
b2: .byte 35, 1, 2 ; 35,1 : New Menu
.word edition
b3: .byte 35, 3, 4 ; Menu Select sur le titre « Fichier »...
.word 10, 5
a: .byte 0
b4: .byte 35, 5, 0 ; 35,5 : Menu Track End
b5: .byte 35, 3, 4 ; ... sur « Edition »
.word 60, 5
b: .byte 0
b6: .byte 35, 5, 0 ; 35,5 : Menu Track End
b7: .byte 35, 3, 4 ; hors de la barre : rien n'est déroulé
.word 10, 100
c: .byte 0
b8: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus aucun menu
t9: .text "Fichier : ", 0
t10: .text ", Edition : ", 0
t11: .text ", hors de la barre : ", 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
; 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 0Fichier : 1, Edition : 2, hors de la barre : 035,4 Menu Track Trinity
Met en évidence l'article sous la souris dans le menu déroulé ; sur un autre titre, déroule ce menu.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | int16 | X de la souris |
P2-P3 | int16 | Y de la souris |
Sorties : aucune.
Au banc, les articles font 10 lignes chacun, à partir de la ligne 13. Un article inactif ou un séparateur n'est jamais choisi : 35,5 rend alors 0, 0. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Highlights the item under Parameters:0,1 (X), Parameters:2,3 (Y) in the pulled down menu ; moving over another title pulls that menu down instead.
C (llvm-mos)
/* Suivre la souris dans un menu (groupe 35, 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)
;
}
/* Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF. */
static uint8_t fichier[] = { 7, 'F', 'i', 'c', 'h', 'i', 'e', 'r',
0, 6, 'O', 'u', 'v', 'r', 'i', 'r', /* article 1 */
1, 6, 'F', 'e', 'r', 'm', 'e', 'r', /* article 2, inactif */
0x80, 0, /* article 3 : séparateur */
0, 7, 'Q', 'u', 'i', 't', 't', 'e', 'r', 0xFF }; /* article 4 */
static uint8_t edition[] = { 7, 'E', 'd', 'i', 't', 'i', 'o', 'n',
2, 6, 'C', 'o', 'p', 'i', 'e', 'r', /* coché */
0, 6, 'C', 'o', 'l', 'l', 'e', 'r', 0xFF };
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 uint8_t nouveau(uint8_t *menu) { /* 35,1 New Menu : rend le numéro */
libre();
p16(0, (uint16_t)menu);
api(35, 1);
return ControlPort.params[2];
}
static uint8_t point(uint8_t f, int16_t x, int16_t y) { /* 35,3 Menu Select ou 35,4 Menu Track en (x, y) */
libre();
p16(0, x);
p16(2, y);
api(35, f);
return ControlPort.params[4]; /* 35,3 : menu déroulé, 0 si aucun titre touché */
}
static uint8_t choix_menu, choix_article;
static void fin(void) { /* 35,5 Menu Track End : menu et article choisis */
libre();
api(35, 5);
choix_menu = ControlPort.params[0];
choix_article = ControlPort.params[1];
}
static void reinit(void) { /* 32,19 Toolbox Reset : plus aucun menu */
libre();
api(32, 19);
}
int main(void) {
uint8_t m1, a1, m2, a2, m3, a3;
reinit();
nouveau(fichier);
nouveau(edition);
point(3, 10, 5);
point(4, 15, 18); /* Menu Track sur le premier article (lignes 13 à 22) */
fin(); m1 = choix_menu; a1 = choix_article;
point(3, 10, 5);
point(4, 15, 28); /* article 2, inactif */
fin(); m2 = choix_menu; a2 = choix_article;
point(3, 10, 5);
point(4, 60, 5); /* passer sur un autre titre déroule son menu */
point(4, 65, 18);
fin(); m3 = choix_menu; a3 = choix_article;
reinit();
printf("Ouvrir : %u, %u ; inactif : %u, %u\nAutre titre : %u, %u\n", m1, a1, m2, a2, m3, a3);
return 0;
}Ouvrir : 1, 1 ; inactif : 0, 0
Autre titre : 2, 1Mad Pascal
// Suivre la souris dans un menu (groupe 35, fonction 4, Trinity).
program mn4;
uses crt, neo6502;
// Descripteurs de menus (variables : le firmware y écrit), lus sur place : titre précédé de sa longueur, puis pour chaque article un octet
// d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
var fichier: array[0..35] of byte = (7, ord('F'), ord('i'), ord('c'), ord('h'), ord('i'), ord('e'), ord('r'),
0, 6, ord('O'), ord('u'), ord('v'), ord('r'), ord('i'), ord('r'), // article 1
1, 6, ord('F'), ord('e'), ord('r'), ord('m'), ord('e'), ord('r'), // article 2, inactif
$80, 0, // article 3 : séparateur
0, 7, ord('Q'), ord('u'), ord('i'), ord('t'), ord('t'), ord('e'), ord('r'), $FF); // article 4
edition: array[0..24] of byte = (7, ord('E'), ord('d'), ord('i'), ord('t'), ord('i'), ord('o'), ord('n'),
2, 6, ord('C'), ord('o'), ord('p'), ord('i'), ord('e'), ord('r'), // coché
0, 6, ord('C'), ord('o'), ord('l'), ord('l'), ord('e'), ord('r'), $FF);
procedure appel(f: byte); // appel 35,f (paramètres déjà posés)
begin
NeoSendMessage(35, f);
NeoWaitMessage;
end;
function nouveau(menu: pointer): byte; // 35,1 New Menu : rend le numéro
begin
NeoWaitMessage;
wordParams[0] := word(menu);
appel(1);
result := NeoMessage.params[2];
end;
function point(f: byte; x, y: smallint): byte; // 35,3 Menu Select ou 35,4 Menu Track en (x, y)
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
appel(f);
result := NeoMessage.params[4]; // 35,3 : menu déroulé, 0 si aucun titre touché
end;
var choix_menu, choix_article: byte;
procedure fin; // 35,5 Menu Track End : menu et article choisis
begin
NeoWaitMessage;
appel(5);
choix_menu := NeoMessage.params[0];
choix_article := NeoMessage.params[1];
end;
procedure reinit; // 32,19 Toolbox Reset : plus aucun menu
begin
NeoWaitMessage;
NeoSendMessage(32, 19);
NeoWaitMessage;
end;
var m1, a1, m2, a2, m3, a3: byte;
begin
reinit;
nouveau(@fichier);
nouveau(@edition);
point(3, 10, 5);
point(4, 15, 18); // Menu Track sur le premier article (lignes 13 à 22)
fin; m1 := choix_menu; a1 := choix_article;
point(3, 10, 5);
point(4, 15, 28); // article 2, inactif
fin; m2 := choix_menu; a2 := choix_article;
point(3, 10, 5);
point(4, 60, 5); // passer sur un autre titre déroule son menu
point(4, 65, 18);
fin; m3 := choix_menu; a3 := choix_article;
reinit;
writeln('Ouvrir : ', m1, ', ', a1, ' ; inactif : ', m2, ', ', a2);
writeln('Autre titre : ', m3, ', ', a3);
end.Ouvrir : 1, 1 ; inactif : 0, 0
Autre titre : 2, 1NeoBASIC
10 ' Suivre la souris dans un menu (groupe 35, fonction 4, Trinity)
15 gosub 7000
20 gosub 8300
30 q = fi : gosub 8000 : q = ed : gosub 8000
40 f = 3 : x = 10 : y = 5 : gosub 8100
50 f = 4 : x = 15 : y = 18 : gosub 8100 : ' Menu Track sur le premier article (lignes 13 a 22)
60 gosub 8200 : m1 = cm : a1 = ca
70 f = 3 : x = 10 : y = 5 : gosub 8100
80 f = 4 : x = 15 : y = 28 : gosub 8100 : ' article 2, inactif
90 gosub 8200 : m2 = cm : a2 = ca
100 f = 3 : x = 10 : y = 5 : gosub 8100
110 f = 4 : x = 60 : y = 5 : gosub 8100 : ' passer sur un autre titre deroule son menu
120 f = 4 : x = 65 : y = 18 : gosub 8100
130 gosub 8200 : m3 = cm : a3 = ca
140 gosub 8300
150 print "Ouvrir : ";m1;", ";a1;" ; inactif : ";m2;", ";a2
160 print "Autre titre : ";m3;", ";a3
170 end
7000 ' descripteurs de menus, lus sur place : titre precede de sa longueur, puis pour chaque article
7010 ' un octet d'options (bit 0 inactif, bit 1 coche, bit 7 separateur) et son texte, enfin $FF
7020 fi = alloc(36) : p = fi : s$ = "Fichier" : gosub 7100
7030 poke p, 0 : p = p + 1 : s$ = "Ouvrir" : gosub 7100 : ' article 1
7040 poke p, 1 : p = p + 1 : s$ = "Fermer" : gosub 7100 : ' article 2, inactif
7050 poke p, $80 : poke p + 1, 0 : p = p + 2 : ' article 3 : separateur
7060 poke p, 0 : p = p + 1 : s$ = "Quitter" : gosub 7100 : poke p, $ff : ' article 4
7070 ed = alloc(25) : p = ed : s$ = "Edition" : gosub 7100
7080 poke p, 2 : p = p + 1 : s$ = "Copier" : gosub 7100 : ' coche
7090 poke p, 0 : p = p + 1 : s$ = "Coller" : gosub 7100 : poke p, $ff : return
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 ' 35,1 New Menu, descripteur en q : numero dans mn, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 mn = peek($ff06) : return
8100 ' 35,3 Menu Select ou 35,4 Menu Track en (x, y) : menu deroule dans r (35,3)
8105 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y
8110 poke $ff01, f : poke $ff00, 35
8120 while peek($ff00) : wend : r = peek($ff08) : e = peek($ff02) : return
8200 ' 35,5 Menu Track End : menu dans cm, article dans ca
8210 while peek($ff00) : wend : f = 5 : gosub 8110
8220 cm = peek($ff04) : ca = peek($ff05) : return
8300 ' 32,19 Toolbox Reset : plus aucun menu
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnOuvrir : 1, 1 ; inactif : 0, 0
Autre titre : 2, 1Assembleur 65C02 (64tass)
; Suivre la souris dans un menu (groupe 35, 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
lda #<b1
ldx #>b1
jsr envoi
lda #<b2
ldx #>b2
jsr envoi
lda #<b3
ldx #>b3
jsr envoi
lda #<b4
ldx #>b4
jsr envoi
lda #<b5
ldx #>b5
jsr envoi
lda ControlPort+4 ; menu choisi
sta m1
lda ControlPort+5 ; article choisi
sta a1
lda #<b6
ldx #>b6
jsr envoi
lda #<b7
ldx #>b7
jsr envoi
lda #<b8
ldx #>b8
jsr envoi
lda ControlPort+4 ; menu choisi
sta m2
lda ControlPort+5 ; article choisi
sta a2
lda #<b9
ldx #>b9
jsr envoi
lda #<b10
ldx #>b10
jsr envoi
lda #<b11
ldx #>b11
jsr envoi
lda #<b12
ldx #>b12
jsr envoi
lda ControlPort+4 ; menu choisi
sta m3
lda ControlPort+5 ; article choisi
sta a3
lda #<b13
ldx #>b13
jsr envoi
lda #<t14
ldx #>t14
jsr ecrire
lda m1
jsr decimal
lda #<t15
ldx #>t15
jsr ecrire
lda a1
jsr decimal
lda #<t16
ldx #>t16
jsr ecrire
lda m2
jsr decimal
lda #<t17
ldx #>t17
jsr ecrire
lda a2
jsr decimal
lda #13
jsr WriteCharacter
lda #<t18
ldx #>t18
jsr ecrire
lda m3
jsr decimal
lda #<t19
ldx #>t19
jsr ecrire
lda a3
jsr decimal
lda #13
jsr WriteCharacter
rts
; Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
; un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
fichier: .byte 7
.text "Fichier"
.byte 0, 6
.text "Ouvrir" ; article 1
fermer: .byte 1, 6
.text "Fermer" ; article 2, inactif
.byte $80, 0 ; article 3 : séparateur
.byte 0, 7
.text "Quitter" ; article 4
.byte $FF
edition: .byte 7
.text "Edition"
.byte 2, 6
.text "Copier" ; coché
.byte 0, 6
.text "Coller"
.byte $FF
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus aucun menu
b1: .byte 35, 1, 2 ; 35,1 : New Menu
.word fichier
b2: .byte 35, 1, 2 ; 35,1 : New Menu
.word edition
b3: .byte 35, 3, 4 ; 35,3 : Menu Select
.word 10, 5
b4: .byte 35, 4, 4 ; Menu Track sur le premier article (lignes 13 à 22)
.word 15, 18
b5: .byte 35, 5, 0 ; 35,5 : Menu Track End
m1: .byte 0
a1: .byte 0
b6: .byte 35, 3, 4 ; 35,3 : Menu Select
.word 10, 5
b7: .byte 35, 4, 4 ; article 2, inactif
.word 15, 28
b8: .byte 35, 5, 0 ; 35,5 : Menu Track End
m2: .byte 0
a2: .byte 0
b9: .byte 35, 3, 4 ; 35,3 : Menu Select
.word 10, 5
b10: .byte 35, 4, 4 ; passer sur un autre titre déroule son menu
.word 60, 5
b11: .byte 35, 4, 4 ; 35,4 : Menu Track
.word 65, 18
b12: .byte 35, 5, 0 ; 35,5 : Menu Track End
m3: .byte 0
a3: .byte 0
b13: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus aucun menu
t14: .text "Ouvrir : ", 0
t15: .text ", ", 0
t16: .text " ; inactif : ", 0
t17: .text ", ", 0
t18: .text "Autre titre : ", 0
t19: .text ", ", 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
; 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 0Ouvrir : 1, 1 ; inactif : 0, 0
Autre titre : 2, 135,5 Menu Track End Trinity
Ferme le menu déroulé et rend le menu et l'article choisis.
Entrées : aucune.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | menu choisi (0 si rien) |
P1 | uint8 | article choisi, à partir de 1 (0 si rien) |
Bouton relâché hors du menu : rien n'est choisi. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Closes the pulled down menu and returns the chosen menu in Parameter:0 and item in Parameter:1 (1..), both 0 if nothing enabled was chosen.
C (llvm-mos)
/* Fermer le menu et lire le choix (groupe 35, 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)
;
}
/* Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF. */
static uint8_t fichier[] = { 7, 'F', 'i', 'c', 'h', 'i', 'e', 'r',
0, 6, 'O', 'u', 'v', 'r', 'i', 'r', /* article 1 */
1, 6, 'F', 'e', 'r', 'm', 'e', 'r', /* article 2, inactif */
0x80, 0, /* article 3 : séparateur */
0, 7, 'Q', 'u', 'i', 't', 't', 'e', 'r', 0xFF }; /* article 4 */
static uint8_t edition[] = { 7, 'E', 'd', 'i', 't', 'i', 'o', 'n',
2, 6, 'C', 'o', 'p', 'i', 'e', 'r', /* coché */
0, 6, 'C', 'o', 'l', 'l', 'e', 'r', 0xFF };
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 uint8_t nouveau(uint8_t *menu) { /* 35,1 New Menu : rend le numéro */
libre();
p16(0, (uint16_t)menu);
api(35, 1);
return ControlPort.params[2];
}
static uint8_t point(uint8_t f, int16_t x, int16_t y) { /* 35,3 Menu Select ou 35,4 Menu Track en (x, y) */
libre();
p16(0, x);
p16(2, y);
api(35, f);
return ControlPort.params[4]; /* 35,3 : menu déroulé, 0 si aucun titre touché */
}
static uint8_t choix_menu, choix_article;
static void fin(void) { /* 35,5 Menu Track End : menu et article choisis */
libre();
api(35, 5);
choix_menu = ControlPort.params[0];
choix_article = ControlPort.params[1];
}
static void reinit(void) { /* 32,19 Toolbox Reset : plus aucun menu */
libre();
api(32, 19);
}
int main(void) {
uint8_t m1, a1, m2, a2;
reinit();
nouveau(fichier);
point(3, 10, 5);
point(4, 15, 48); /* article 4, « Quitter » */
fin(); m1 = choix_menu; a1 = choix_article; /* Menu Track End, au relâchement du bouton */
point(3, 10, 5);
point(4, 200, 200); /* bouton relâché hors du menu */
fin(); m2 = choix_menu; a2 = choix_article;
reinit();
printf("Quitter : %u, %u ; dehors : %u, %u\n", m1, a1, m2, a2);
return 0;
}Quitter : 1, 4 ; dehors : 0, 0Mad Pascal
// Fermer le menu et lire le choix (groupe 35, fonction 5, Trinity).
program mn5;
uses crt, neo6502;
// Descripteurs de menus (variables : le firmware y écrit), lus sur place : titre précédé de sa longueur, puis pour chaque article un octet
// d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
var fichier: array[0..35] of byte = (7, ord('F'), ord('i'), ord('c'), ord('h'), ord('i'), ord('e'), ord('r'),
0, 6, ord('O'), ord('u'), ord('v'), ord('r'), ord('i'), ord('r'), // article 1
1, 6, ord('F'), ord('e'), ord('r'), ord('m'), ord('e'), ord('r'), // article 2, inactif
$80, 0, // article 3 : séparateur
0, 7, ord('Q'), ord('u'), ord('i'), ord('t'), ord('t'), ord('e'), ord('r'), $FF); // article 4
edition: array[0..24] of byte = (7, ord('E'), ord('d'), ord('i'), ord('t'), ord('i'), ord('o'), ord('n'),
2, 6, ord('C'), ord('o'), ord('p'), ord('i'), ord('e'), ord('r'), // coché
0, 6, ord('C'), ord('o'), ord('l'), ord('l'), ord('e'), ord('r'), $FF);
procedure appel(f: byte); // appel 35,f (paramètres déjà posés)
begin
NeoSendMessage(35, f);
NeoWaitMessage;
end;
function nouveau(menu: pointer): byte; // 35,1 New Menu : rend le numéro
begin
NeoWaitMessage;
wordParams[0] := word(menu);
appel(1);
result := NeoMessage.params[2];
end;
function point(f: byte; x, y: smallint): byte; // 35,3 Menu Select ou 35,4 Menu Track en (x, y)
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
appel(f);
result := NeoMessage.params[4]; // 35,3 : menu déroulé, 0 si aucun titre touché
end;
var choix_menu, choix_article: byte;
procedure fin; // 35,5 Menu Track End : menu et article choisis
begin
NeoWaitMessage;
appel(5);
choix_menu := NeoMessage.params[0];
choix_article := NeoMessage.params[1];
end;
procedure reinit; // 32,19 Toolbox Reset : plus aucun menu
begin
NeoWaitMessage;
NeoSendMessage(32, 19);
NeoWaitMessage;
end;
var m1, a1, m2, a2: byte;
begin
reinit;
nouveau(@fichier);
point(3, 10, 5);
point(4, 15, 48); // article 4, « Quitter »
fin; m1 := choix_menu; a1 := choix_article; // Menu Track End, au relâchement du bouton
point(3, 10, 5);
point(4, 200, 200); // bouton relâché hors du menu
fin; m2 := choix_menu; a2 := choix_article;
reinit;
writeln('Quitter : ', m1, ', ', a1, ' ; dehors : ', m2, ', ', a2);
end.Quitter : 1, 4 ; dehors : 0, 0NeoBASIC
10 ' Fermer le menu et lire le choix (groupe 35, fonction 5, Trinity)
15 gosub 7000
20 gosub 8300
30 q = fi : gosub 8000
40 f = 3 : x = 10 : y = 5 : gosub 8100
50 f = 4 : x = 15 : y = 48 : gosub 8100 : ' article 4, « Quitter »
60 gosub 8200 : m1 = cm : a1 = ca : ' Menu Track End, au relachement du bouton
70 f = 3 : x = 10 : y = 5 : gosub 8100
80 f = 4 : x = 200 : y = 200 : gosub 8100 : ' bouton relache hors du menu
90 gosub 8200 : m2 = cm : a2 = ca
100 gosub 8300
110 print "Quitter : ";m1;", ";a1;" ; dehors : ";m2;", ";a2
120 end
7000 ' descripteurs de menus, lus sur place : titre precede de sa longueur, puis pour chaque article
7010 ' un octet d'options (bit 0 inactif, bit 1 coche, bit 7 separateur) et son texte, enfin $FF
7020 fi = alloc(36) : p = fi : s$ = "Fichier" : gosub 7100
7030 poke p, 0 : p = p + 1 : s$ = "Ouvrir" : gosub 7100 : ' article 1
7040 poke p, 1 : p = p + 1 : s$ = "Fermer" : gosub 7100 : ' article 2, inactif
7050 poke p, $80 : poke p + 1, 0 : p = p + 2 : ' article 3 : separateur
7060 poke p, 0 : p = p + 1 : s$ = "Quitter" : gosub 7100 : poke p, $ff : ' article 4
7070 ed = alloc(25) : p = ed : s$ = "Edition" : gosub 7100
7080 poke p, 2 : p = p + 1 : s$ = "Copier" : gosub 7100 : ' coche
7090 poke p, 0 : p = p + 1 : s$ = "Coller" : gosub 7100 : poke p, $ff : return
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 ' 35,1 New Menu, descripteur en q : numero dans mn, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 mn = peek($ff06) : return
8100 ' 35,3 Menu Select ou 35,4 Menu Track en (x, y) : menu deroule dans r (35,3)
8105 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y
8110 poke $ff01, f : poke $ff00, 35
8120 while peek($ff00) : wend : r = peek($ff08) : e = peek($ff02) : return
8200 ' 35,5 Menu Track End : menu dans cm, article dans ca
8210 while peek($ff00) : wend : f = 5 : gosub 8110
8220 cm = peek($ff04) : ca = peek($ff05) : return
8300 ' 32,19 Toolbox Reset : plus aucun menu
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnQuitter : 1, 4 ; dehors : 0, 0Assembleur 65C02 (64tass)
; Fermer le menu et lire le choix (groupe 35, 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 #<b0
ldx #>b0
jsr envoi
lda #<b1
ldx #>b1
jsr envoi
lda #<b2
ldx #>b2
jsr envoi
lda #<b3
ldx #>b3
jsr envoi
lda #<b4
ldx #>b4
jsr envoi
lda ControlPort+4 ; menu choisi
sta m1
lda ControlPort+5 ; article choisi
sta a1
lda #<b5
ldx #>b5
jsr envoi
lda #<b6
ldx #>b6
jsr envoi
lda #<b7
ldx #>b7
jsr envoi
lda ControlPort+4 ; menu choisi
sta m2
lda ControlPort+5 ; article choisi
sta a2
lda #<b8
ldx #>b8
jsr envoi
lda #<t9
ldx #>t9
jsr ecrire
lda m1
jsr decimal
lda #<t10
ldx #>t10
jsr ecrire
lda a1
jsr decimal
lda #<t11
ldx #>t11
jsr ecrire
lda m2
jsr decimal
lda #<t12
ldx #>t12
jsr ecrire
lda a2
jsr decimal
lda #13
jsr WriteCharacter
rts
; Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
; un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
fichier: .byte 7
.text "Fichier"
.byte 0, 6
.text "Ouvrir" ; article 1
fermer: .byte 1, 6
.text "Fermer" ; article 2, inactif
.byte $80, 0 ; article 3 : séparateur
.byte 0, 7
.text "Quitter" ; article 4
.byte $FF
edition: .byte 7
.text "Edition"
.byte 2, 6
.text "Copier" ; coché
.byte 0, 6
.text "Coller"
.byte $FF
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus aucun menu
b1: .byte 35, 1, 2 ; 35,1 : New Menu
.word fichier
b2: .byte 35, 3, 4 ; 35,3 : Menu Select
.word 10, 5
b3: .byte 35, 4, 4 ; article 4, « Quitter »
.word 15, 48
b4: .byte 35, 5, 0 ; 35,5 : Menu Track End
m1: .byte 0
a1: .byte 0
b5: .byte 35, 3, 4 ; 35,3 : Menu Select
.word 10, 5
b6: .byte 35, 4, 4 ; bouton relâché hors du menu
.word 200, 200
b7: .byte 35, 5, 0 ; 35,5 : Menu Track End
m2: .byte 0
a2: .byte 0
b8: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus aucun menu
t9: .text "Quitter : ", 0
t10: .text ", ", 0
t11: .text " ; dehors : ", 0
t12: .text ", ", 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
; 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 0Quitter : 1, 4 ; dehors : 0, 035,6 Set Item Flags Trinity
Change les options d'un article (bit 0 inactif, bit 1 coché), dans le descripteur.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | numéro du menu |
P1 | uint8 | numéro de l'article (1, 2...) |
P2 | uint8 | options |
Sorties : aucune.
L'octet est écrit dans le descripteur du programme : l'exemple le relit. L'article est redessiné si son menu est déroulé. En Mad Pascal, le descripteur doit être une variable : un tableau constant est lu à la compilation et l'écriture du firmware ne se voit pas. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Sets the flags (bit 0 disabled, bit 1 checked) of item Parameter:1 of menu Parameter:0 to Parameter:2, in the descriptor ; the item is redrawn if its menu is pulled down.
C (llvm-mos)
/* Activer ou cocher un article (groupe 35, 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)
;
}
/* Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF. */
static uint8_t fichier[] = { 7, 'F', 'i', 'c', 'h', 'i', 'e', 'r',
0, 6, 'O', 'u', 'v', 'r', 'i', 'r', /* article 1 */
1, 6, 'F', 'e', 'r', 'm', 'e', 'r', /* article 2, inactif */
0x80, 0, /* article 3 : séparateur */
0, 7, 'Q', 'u', 'i', 't', 't', 'e', 'r', 0xFF }; /* article 4 */
static uint8_t edition[] = { 7, 'E', 'd', 'i', 't', 'i', 'o', 'n',
2, 6, 'C', 'o', 'p', 'i', 'e', 'r', /* coché */
0, 6, 'C', 'o', 'l', 'l', 'e', 'r', 0xFF };
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 uint8_t nouveau(uint8_t *menu) { /* 35,1 New Menu : rend le numéro */
libre();
p16(0, (uint16_t)menu);
api(35, 1);
return ControlPort.params[2];
}
static uint8_t point(uint8_t f, int16_t x, int16_t y) { /* 35,3 Menu Select ou 35,4 Menu Track en (x, y) */
libre();
p16(0, x);
p16(2, y);
api(35, f);
return ControlPort.params[4]; /* 35,3 : menu déroulé, 0 si aucun titre touché */
}
static uint8_t choix_menu, choix_article;
static void fin(void) { /* 35,5 Menu Track End : menu et article choisis */
libre();
api(35, 5);
choix_menu = ControlPort.params[0];
choix_article = ControlPort.params[1];
}
static void reinit(void) { /* 32,19 Toolbox Reset : plus aucun menu */
libre();
api(32, 19);
}
int main(void) {
uint8_t m, m1, a1, m2, a2;
reinit();
m = nouveau(fichier);
point(3, 10, 5); point(4, 15, 28); fin(); /* « Fermer », inactif */
m1 = choix_menu; a1 = choix_article;
libre();
ControlPort.params[0] = m;
ControlPort.params[1] = 2;
ControlPort.params[2] = 2; /* Set Item Flags : actif et coché */
api(35, 6);
point(3, 10, 5); point(4, 15, 28); fin();
m2 = choix_menu; a2 = choix_article;
reinit();
printf("Avant : %u, %u ; actif : %u, %u\n", m1, a1, m2, a2);
printf("Octet dans le descripteur : %u\n", fichier[16]); /* les options sont écrites sur place */
return 0;
}Avant : 0, 0 ; actif : 1, 2
Octet dans le descripteur : 2Mad Pascal
// Activer ou cocher un article (groupe 35, fonction 6, Trinity).
program mn6;
uses crt, neo6502;
// Descripteurs de menus (variables : le firmware y écrit), lus sur place : titre précédé de sa longueur, puis pour chaque article un octet
// d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
var fichier: array[0..35] of byte = (7, ord('F'), ord('i'), ord('c'), ord('h'), ord('i'), ord('e'), ord('r'),
0, 6, ord('O'), ord('u'), ord('v'), ord('r'), ord('i'), ord('r'), // article 1
1, 6, ord('F'), ord('e'), ord('r'), ord('m'), ord('e'), ord('r'), // article 2, inactif
$80, 0, // article 3 : séparateur
0, 7, ord('Q'), ord('u'), ord('i'), ord('t'), ord('t'), ord('e'), ord('r'), $FF); // article 4
edition: array[0..24] of byte = (7, ord('E'), ord('d'), ord('i'), ord('t'), ord('i'), ord('o'), ord('n'),
2, 6, ord('C'), ord('o'), ord('p'), ord('i'), ord('e'), ord('r'), // coché
0, 6, ord('C'), ord('o'), ord('l'), ord('l'), ord('e'), ord('r'), $FF);
procedure appel(f: byte); // appel 35,f (paramètres déjà posés)
begin
NeoSendMessage(35, f);
NeoWaitMessage;
end;
function nouveau(menu: pointer): byte; // 35,1 New Menu : rend le numéro
begin
NeoWaitMessage;
wordParams[0] := word(menu);
appel(1);
result := NeoMessage.params[2];
end;
function point(f: byte; x, y: smallint): byte; // 35,3 Menu Select ou 35,4 Menu Track en (x, y)
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
appel(f);
result := NeoMessage.params[4]; // 35,3 : menu déroulé, 0 si aucun titre touché
end;
var choix_menu, choix_article: byte;
procedure fin; // 35,5 Menu Track End : menu et article choisis
begin
NeoWaitMessage;
appel(5);
choix_menu := NeoMessage.params[0];
choix_article := NeoMessage.params[1];
end;
procedure reinit; // 32,19 Toolbox Reset : plus aucun menu
begin
NeoWaitMessage;
NeoSendMessage(32, 19);
NeoWaitMessage;
end;
var m, m1, a1, m2, a2: byte;
begin
reinit;
m := nouveau(@fichier);
point(3, 10, 5); point(4, 15, 28); fin; // « Fermer », inactif
m1 := choix_menu; a1 := choix_article;
NeoWaitMessage;
NeoMessage.params[0] := m;
NeoMessage.params[1] := 2;
NeoMessage.params[2] := 2; // Set Item Flags : actif et coché
appel(6);
point(3, 10, 5); point(4, 15, 28); fin;
m2 := choix_menu; a2 := choix_article;
reinit;
writeln('Avant : ', m1, ', ', a1, ' ; actif : ', m2, ', ', a2);
writeln('Octet dans le descripteur : ', fichier[16]); // les options sont écrites sur place
end.Avant : 0, 0 ; actif : 1, 2
Octet dans le descripteur : 2NeoBASIC
10 ' Activer ou cocher un article (groupe 35, fonction 6, Trinity)
15 gosub 7000
20 gosub 8300
30 q = fi : gosub 8000 : m = mn
40 f = 3 : x = 10 : y = 5 : gosub 8100 : f = 4 : x = 15 : y = 28 : gosub 8100 : gosub 8200 : ' « Fermer », inactif
50 m1 = cm : a1 = ca
60 while peek($ff00) : wend : poke $ff04, m : poke $ff05, 2 : poke $ff06, 2 : f = 6 : gosub 8110 : ' Set Item Flags : actif et coche
70 f = 3 : x = 10 : y = 5 : gosub 8100 : f = 4 : x = 15 : y = 28 : gosub 8100 : gosub 8200
80 m2 = cm : a2 = ca
90 gosub 8300
100 print "Avant : ";m1;", ";a1;" ; actif : ";m2;", ";a2
110 print "Octet dans le descripteur : ";peek(fi + 16) : ' les options sont ecrites sur place
120 end
7000 ' descripteurs de menus, lus sur place : titre precede de sa longueur, puis pour chaque article
7010 ' un octet d'options (bit 0 inactif, bit 1 coche, bit 7 separateur) et son texte, enfin $FF
7020 fi = alloc(36) : p = fi : s$ = "Fichier" : gosub 7100
7030 poke p, 0 : p = p + 1 : s$ = "Ouvrir" : gosub 7100 : ' article 1
7040 poke p, 1 : p = p + 1 : s$ = "Fermer" : gosub 7100 : ' article 2, inactif
7050 poke p, $80 : poke p + 1, 0 : p = p + 2 : ' article 3 : separateur
7060 poke p, 0 : p = p + 1 : s$ = "Quitter" : gosub 7100 : poke p, $ff : ' article 4
7070 ed = alloc(25) : p = ed : s$ = "Edition" : gosub 7100
7080 poke p, 2 : p = p + 1 : s$ = "Copier" : gosub 7100 : ' coche
7090 poke p, 0 : p = p + 1 : s$ = "Coller" : gosub 7100 : poke p, $ff : return
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 ' 35,1 New Menu, descripteur en q : numero dans mn, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 mn = peek($ff06) : return
8100 ' 35,3 Menu Select ou 35,4 Menu Track en (x, y) : menu deroule dans r (35,3)
8105 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y
8110 poke $ff01, f : poke $ff00, 35
8120 while peek($ff00) : wend : r = peek($ff08) : e = peek($ff02) : return
8200 ' 35,5 Menu Track End : menu dans cm, article dans ca
8210 while peek($ff00) : wend : f = 5 : gosub 8110
8220 cm = peek($ff04) : ca = peek($ff05) : return
8300 ' 32,19 Toolbox Reset : plus aucun menu
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnAvant : 0, 0 ; actif : 1, 2
Octet dans le descripteur : 2Assembleur 65C02 (64tass)
; Activer ou cocher un article (groupe 35, 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+6 ; P2 : numéro du menu
sta m
lda #<b2
ldx #>b2
jsr envoi
lda #<b3
ldx #>b3
jsr envoi
lda #<b4
ldx #>b4
jsr envoi
lda ControlPort+4 ; menu choisi
sta m1
lda ControlPort+5 ; article choisi
sta a1
jsr WaitMessage
lda m
sta ControlPort+4 ; P0 : menu
lda #2
sta ControlPort+5 ; P1 : article 2
sta ControlPort+6 ; P2 : options 2, actif et coché
lda #35
ldx #6 ; Set Item Flags
jsr appel
lda #<b5
ldx #>b5
jsr envoi
lda #<b6
ldx #>b6
jsr envoi
lda #<b7
ldx #>b7
jsr envoi
lda ControlPort+4 ; menu choisi
sta m2
lda ControlPort+5 ; article choisi
sta a2
lda #<b8
ldx #>b8
jsr envoi
lda #<t9
ldx #>t9
jsr ecrire
lda m1
jsr decimal
lda #<t10
ldx #>t10
jsr ecrire
lda a1
jsr decimal
lda #<t11
ldx #>t11
jsr ecrire
lda m2
jsr decimal
lda #<t12
ldx #>t12
jsr ecrire
lda a2
jsr decimal
lda #13
jsr WriteCharacter
lda #<t13
ldx #>t13
jsr ecrire
lda fermer
jsr decimal
lda #13
jsr WriteCharacter
rts
; Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
; un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
fichier: .byte 7
.text "Fichier"
.byte 0, 6
.text "Ouvrir" ; article 1
fermer: .byte 1, 6
.text "Fermer" ; article 2, inactif
.byte $80, 0 ; article 3 : séparateur
.byte 0, 7
.text "Quitter" ; article 4
.byte $FF
edition: .byte 7
.text "Edition"
.byte 2, 6
.text "Copier" ; coché
.byte 0, 6
.text "Coller"
.byte $FF
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus aucun menu
b1: .byte 35, 1, 2 ; 35,1 : New Menu
.word fichier
m: .byte 0
b2: .byte 35, 3, 4 ; 35,3 : Menu Select
.word 10, 5
b3: .byte 35, 4, 4 ; « Fermer », inactif
.word 15, 28
b4: .byte 35, 5, 0 ; 35,5 : Menu Track End
m1: .byte 0
a1: .byte 0
b5: .byte 35, 3, 4 ; 35,3 : Menu Select
.word 10, 5
b6: .byte 35, 4, 4 ; 35,4 : Menu Track
.word 15, 28
b7: .byte 35, 5, 0 ; 35,5 : Menu Track End
m2: .byte 0
a2: .byte 0
b8: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus aucun menu
t9: .text "Avant : ", 0
t10: .text ", ", 0
t11: .text " ; actif : ", 0
t12: .text ", ", 0
t13: .text "Octet dans le descripteur : ", 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
; 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 0Avant : 0, 0 ; actif : 1, 2
Octet dans le descripteur : 235,7 Dispose Menu Trinity
Retire un menu de la barre.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | numéro du menu |
Sorties : aucune.
Les titres suivants se décalent vers la gauche : après le retrait de « Fichier », « Edition » est touché en (10, 5). NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Removes menu Parameter:0 from the menu bar.
C (llvm-mos)
/* Retirer un menu de la barre (groupe 35, fonction 7, 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)
;
}
/* Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF. */
static uint8_t fichier[] = { 7, 'F', 'i', 'c', 'h', 'i', 'e', 'r',
0, 6, 'O', 'u', 'v', 'r', 'i', 'r', /* article 1 */
1, 6, 'F', 'e', 'r', 'm', 'e', 'r', /* article 2, inactif */
0x80, 0, /* article 3 : séparateur */
0, 7, 'Q', 'u', 'i', 't', 't', 'e', 'r', 0xFF }; /* article 4 */
static uint8_t edition[] = { 7, 'E', 'd', 'i', 't', 'i', 'o', 'n',
2, 6, 'C', 'o', 'p', 'i', 'e', 'r', /* coché */
0, 6, 'C', 'o', 'l', 'l', 'e', 'r', 0xFF };
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 uint8_t nouveau(uint8_t *menu) { /* 35,1 New Menu : rend le numéro */
libre();
p16(0, (uint16_t)menu);
api(35, 1);
return ControlPort.params[2];
}
static uint8_t point(uint8_t f, int16_t x, int16_t y) { /* 35,3 Menu Select ou 35,4 Menu Track en (x, y) */
libre();
p16(0, x);
p16(2, y);
api(35, f);
return ControlPort.params[4]; /* 35,3 : menu déroulé, 0 si aucun titre touché */
}
static uint8_t choix_menu, choix_article;
static void fin(void) { /* 35,5 Menu Track End : menu et article choisis */
libre();
api(35, 5);
choix_menu = ControlPort.params[0];
choix_article = ControlPort.params[1];
}
static void reinit(void) { /* 32,19 Toolbox Reset : plus aucun menu */
libre();
api(32, 19);
}
int main(void) {
uint8_t a, x10, x60;
reinit();
a = nouveau(fichier);
nouveau(edition);
libre(); ControlPort.params[0] = a; api(35, 7); /* Dispose Menu */
x10 = point(3, 10, 5); if (x10) fin();
x60 = point(3, 60, 5); if (x60) fin();
reinit();
printf("Apres retrait : en (10, 5) : %u, en (60, 5) : %u\n", x10, x60);
return 0;
}Apres retrait : en (10, 5) : 2, en (60, 5) : 0Mad Pascal
// Retirer un menu de la barre (groupe 35, fonction 7, Trinity).
program mn7;
uses crt, neo6502;
// Descripteurs de menus (variables : le firmware y écrit), lus sur place : titre précédé de sa longueur, puis pour chaque article un octet
// d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
var fichier: array[0..35] of byte = (7, ord('F'), ord('i'), ord('c'), ord('h'), ord('i'), ord('e'), ord('r'),
0, 6, ord('O'), ord('u'), ord('v'), ord('r'), ord('i'), ord('r'), // article 1
1, 6, ord('F'), ord('e'), ord('r'), ord('m'), ord('e'), ord('r'), // article 2, inactif
$80, 0, // article 3 : séparateur
0, 7, ord('Q'), ord('u'), ord('i'), ord('t'), ord('t'), ord('e'), ord('r'), $FF); // article 4
edition: array[0..24] of byte = (7, ord('E'), ord('d'), ord('i'), ord('t'), ord('i'), ord('o'), ord('n'),
2, 6, ord('C'), ord('o'), ord('p'), ord('i'), ord('e'), ord('r'), // coché
0, 6, ord('C'), ord('o'), ord('l'), ord('l'), ord('e'), ord('r'), $FF);
procedure appel(f: byte); // appel 35,f (paramètres déjà posés)
begin
NeoSendMessage(35, f);
NeoWaitMessage;
end;
function nouveau(menu: pointer): byte; // 35,1 New Menu : rend le numéro
begin
NeoWaitMessage;
wordParams[0] := word(menu);
appel(1);
result := NeoMessage.params[2];
end;
function point(f: byte; x, y: smallint): byte; // 35,3 Menu Select ou 35,4 Menu Track en (x, y)
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
appel(f);
result := NeoMessage.params[4]; // 35,3 : menu déroulé, 0 si aucun titre touché
end;
var choix_menu, choix_article: byte;
procedure fin; // 35,5 Menu Track End : menu et article choisis
begin
NeoWaitMessage;
appel(5);
choix_menu := NeoMessage.params[0];
choix_article := NeoMessage.params[1];
end;
procedure reinit; // 32,19 Toolbox Reset : plus aucun menu
begin
NeoWaitMessage;
NeoSendMessage(32, 19);
NeoWaitMessage;
end;
var a, x10, x60: byte;
begin
reinit;
a := nouveau(@fichier);
nouveau(@edition);
NeoWaitMessage;
NeoMessage.params[0] := a;
appel(7); // Dispose Menu
x10 := point(3, 10, 5); if x10 <> 0 then fin;
x60 := point(3, 60, 5); if x60 <> 0 then fin;
reinit;
writeln('Apres retrait : en (10, 5) : ', x10, ', en (60, 5) : ', x60);
end.Apres retrait : en (10, 5) : 2, en (60, 5) : 0NeoBASIC
10 ' Retirer un menu de la barre (groupe 35, fonction 7, Trinity)
15 gosub 7000
20 gosub 8300
30 q = fi : gosub 8000 : a = mn : q = ed : gosub 8000
40 while peek($ff00) : wend : poke $ff04, a : f = 7 : gosub 8110 : ' Dispose Menu
50 f = 3 : x = 10 : y = 5 : gosub 8100 : x1 = r : if r then gosub 8200
60 f = 3 : x = 60 : y = 5 : gosub 8100 : x6 = r : if r then gosub 8200
70 gosub 8300
80 print "Apres retrait : en (10, 5) : ";x1;", en (60, 5) : ";x6
90 end
7000 ' descripteurs de menus, lus sur place : titre precede de sa longueur, puis pour chaque article
7010 ' un octet d'options (bit 0 inactif, bit 1 coche, bit 7 separateur) et son texte, enfin $FF
7020 fi = alloc(36) : p = fi : s$ = "Fichier" : gosub 7100
7030 poke p, 0 : p = p + 1 : s$ = "Ouvrir" : gosub 7100 : ' article 1
7040 poke p, 1 : p = p + 1 : s$ = "Fermer" : gosub 7100 : ' article 2, inactif
7050 poke p, $80 : poke p + 1, 0 : p = p + 2 : ' article 3 : separateur
7060 poke p, 0 : p = p + 1 : s$ = "Quitter" : gosub 7100 : poke p, $ff : ' article 4
7070 ed = alloc(25) : p = ed : s$ = "Edition" : gosub 7100
7080 poke p, 2 : p = p + 1 : s$ = "Copier" : gosub 7100 : ' coche
7090 poke p, 0 : p = p + 1 : s$ = "Coller" : gosub 7100 : poke p, $ff : return
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 ' 35,1 New Menu, descripteur en q : numero dans mn, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 mn = peek($ff06) : return
8100 ' 35,3 Menu Select ou 35,4 Menu Track en (x, y) : menu deroule dans r (35,3)
8105 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y
8110 poke $ff01, f : poke $ff00, 35
8120 while peek($ff00) : wend : r = peek($ff08) : e = peek($ff02) : return
8200 ' 35,5 Menu Track End : menu dans cm, article dans ca
8210 while peek($ff00) : wend : f = 5 : gosub 8110
8220 cm = peek($ff04) : ca = peek($ff05) : return
8300 ' 32,19 Toolbox Reset : plus aucun menu
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnApres retrait : en (10, 5) : 2, en (60, 5) : 0Assembleur 65C02 (64tass)
; Retirer un menu de la barre (groupe 35, fonction 7, 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+6 ; P2 : numéro du menu
sta a
lda #<b2
ldx #>b2
jsr envoi
jsr WaitMessage
lda a
sta ControlPort+4
lda #35
ldx #7 ; Dispose Menu
jsr appel
lda #<b3
ldx #>b3
jsr envoi
lda ControlPort+8 ; P4 : menu déroulé
sta x1
lda x1
beq _s4
lda #<b5
ldx #>b5
jsr envoi
_s4:
lda #<b6
ldx #>b6
jsr envoi
lda ControlPort+8 ; P4 : menu déroulé
sta x6
lda x6
beq _s7
lda #<b8
ldx #>b8
jsr envoi
_s7:
lda #<b9
ldx #>b9
jsr envoi
lda #<t10
ldx #>t10
jsr ecrire
lda x1
jsr decimal
lda #<t11
ldx #>t11
jsr ecrire
lda x6
jsr decimal
lda #13
jsr WriteCharacter
rts
; Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
; un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
fichier: .byte 7
.text "Fichier"
.byte 0, 6
.text "Ouvrir" ; article 1
fermer: .byte 1, 6
.text "Fermer" ; article 2, inactif
.byte $80, 0 ; article 3 : séparateur
.byte 0, 7
.text "Quitter" ; article 4
.byte $FF
edition: .byte 7
.text "Edition"
.byte 2, 6
.text "Copier" ; coché
.byte 0, 6
.text "Coller"
.byte $FF
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus aucun menu
b1: .byte 35, 1, 2 ; 35,1 : New Menu
.word fichier
a: .byte 0
b2: .byte 35, 1, 2 ; 35,1 : New Menu
.word edition
b3: .byte 35, 3, 4 ; 35,3 : Menu Select
.word 10, 5
x1: .byte 0
b5: .byte 35, 5, 0 ; 35,5 : Menu Track End
b6: .byte 35, 3, 4 ; 35,3 : Menu Select
.word 60, 5
x6: .byte 0
b8: .byte 35, 5, 0 ; 35,5 : Menu Track End
b9: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus aucun menu
t10: .text "Apres retrait : en (10, 5) : ", 0
t11: .text ", en (60, 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
; 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 0Apres retrait : en (10, 5) : 2, en (60, 5) : 035,8 Get Item Flags Trinity
Rend les options d'un article.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | numéro du menu |
P1 | uint8 | numéro de l'article (1, 2...) |
| Octets | Type | Rôle |
|---|---|---|
P2 | uint8 | options (bit 0 inactif, bit 1 coché, bit 7 séparateur) |
Le séparateur rend 128 (bit 7), l'article coché 2. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Returns the flags of item Parameter:1 of menu Parameter:0 in Parameter:2.
C (llvm-mos)
/* Lire les options d'un article (groupe 35, fonction 8, 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)
;
}
/* Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF. */
static uint8_t fichier[] = { 7, 'F', 'i', 'c', 'h', 'i', 'e', 'r',
0, 6, 'O', 'u', 'v', 'r', 'i', 'r', /* article 1 */
1, 6, 'F', 'e', 'r', 'm', 'e', 'r', /* article 2, inactif */
0x80, 0, /* article 3 : séparateur */
0, 7, 'Q', 'u', 'i', 't', 't', 'e', 'r', 0xFF }; /* article 4 */
static uint8_t edition[] = { 7, 'E', 'd', 'i', 't', 'i', 'o', 'n',
2, 6, 'C', 'o', 'p', 'i', 'e', 'r', /* coché */
0, 6, 'C', 'o', 'l', 'l', 'e', 'r', 0xFF };
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 uint8_t nouveau(uint8_t *menu) { /* 35,1 New Menu : rend le numéro */
libre();
p16(0, (uint16_t)menu);
api(35, 1);
return ControlPort.params[2];
}
static uint8_t point(uint8_t f, int16_t x, int16_t y) { /* 35,3 Menu Select ou 35,4 Menu Track en (x, y) */
libre();
p16(0, x);
p16(2, y);
api(35, f);
return ControlPort.params[4]; /* 35,3 : menu déroulé, 0 si aucun titre touché */
}
static uint8_t choix_menu, choix_article;
static void fin(void) { /* 35,5 Menu Track End : menu et article choisis */
libre();
api(35, 5);
choix_menu = ControlPort.params[0];
choix_article = ControlPort.params[1];
}
static void reinit(void) { /* 32,19 Toolbox Reset : plus aucun menu */
libre();
api(32, 19);
}
static uint8_t options(uint8_t m, uint8_t a) { /* Get Item Flags */
libre();
ControlPort.params[0] = m;
ControlPort.params[1] = a;
api(35, 8);
return ControlPort.params[2];
}
int main(void) {
uint8_t a, b, f[4], c, i;
reinit();
a = nouveau(fichier);
b = nouveau(edition);
for (i = 0; i < 4; i++)
f[i] = options(a, i + 1);
c = options(b, 1);
reinit();
printf("Fichier : %u %u %u %u ; Copier : %u\n", f[0], f[1], f[2], f[3], c);
return 0;
}Fichier : 0 1 128 0 ; Copier : 2Mad Pascal
// Lire les options d'un article (groupe 35, fonction 8, Trinity).
program mn8;
uses crt, neo6502;
// Descripteurs de menus (variables : le firmware y écrit), lus sur place : titre précédé de sa longueur, puis pour chaque article un octet
// d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
var fichier: array[0..35] of byte = (7, ord('F'), ord('i'), ord('c'), ord('h'), ord('i'), ord('e'), ord('r'),
0, 6, ord('O'), ord('u'), ord('v'), ord('r'), ord('i'), ord('r'), // article 1
1, 6, ord('F'), ord('e'), ord('r'), ord('m'), ord('e'), ord('r'), // article 2, inactif
$80, 0, // article 3 : séparateur
0, 7, ord('Q'), ord('u'), ord('i'), ord('t'), ord('t'), ord('e'), ord('r'), $FF); // article 4
edition: array[0..24] of byte = (7, ord('E'), ord('d'), ord('i'), ord('t'), ord('i'), ord('o'), ord('n'),
2, 6, ord('C'), ord('o'), ord('p'), ord('i'), ord('e'), ord('r'), // coché
0, 6, ord('C'), ord('o'), ord('l'), ord('l'), ord('e'), ord('r'), $FF);
procedure appel(f: byte); // appel 35,f (paramètres déjà posés)
begin
NeoSendMessage(35, f);
NeoWaitMessage;
end;
function nouveau(menu: pointer): byte; // 35,1 New Menu : rend le numéro
begin
NeoWaitMessage;
wordParams[0] := word(menu);
appel(1);
result := NeoMessage.params[2];
end;
function point(f: byte; x, y: smallint): byte; // 35,3 Menu Select ou 35,4 Menu Track en (x, y)
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
appel(f);
result := NeoMessage.params[4]; // 35,3 : menu déroulé, 0 si aucun titre touché
end;
var choix_menu, choix_article: byte;
procedure fin; // 35,5 Menu Track End : menu et article choisis
begin
NeoWaitMessage;
appel(5);
choix_menu := NeoMessage.params[0];
choix_article := NeoMessage.params[1];
end;
procedure reinit; // 32,19 Toolbox Reset : plus aucun menu
begin
NeoWaitMessage;
NeoSendMessage(32, 19);
NeoWaitMessage;
end;
function options(m, a: byte): byte; // Get Item Flags
begin
NeoWaitMessage;
NeoMessage.params[0] := m;
NeoMessage.params[1] := a;
appel(8);
result := NeoMessage.params[2];
end;
var a, b, c, i: byte;
f: array[0..3] of byte;
begin
reinit;
a := nouveau(@fichier);
b := nouveau(@edition);
for i := 0 to 3 do f[i] := options(a, i + 1);
c := options(b, 1);
reinit;
writeln('Fichier : ', f[0], ' ', f[1], ' ', f[2], ' ', f[3], ' ; Copier : ', c);
end.Fichier : 0 1 128 0 ; Copier : 2NeoBASIC
10 ' Lire les options d'un article (groupe 35, fonction 8, Trinity)
15 gosub 7000
20 gosub 8300
30 q = fi : gosub 8000 : a = mn : q = ed : gosub 8000 : b = mn
40 dim o(3) : for k = 0 to 3 : m = a : t = k + 1 : gosub 2000 : o(k) = op : next k
50 m = b : t = 1 : gosub 2000 : c = op
60 gosub 8300
70 print "Fichier : ";o(0);" ";o(1);" ";o(2);" ";o(3);" ; Copier : ";c
80 end
2000 ' Get Item Flags : article t du menu m, options dans op
2010 while peek($ff00) : wend : poke $ff04, m : poke $ff05, t : f = 8 : gosub 8110
2020 op = peek($ff06) : return
7000 ' descripteurs de menus, lus sur place : titre precede de sa longueur, puis pour chaque article
7010 ' un octet d'options (bit 0 inactif, bit 1 coche, bit 7 separateur) et son texte, enfin $FF
7020 fi = alloc(36) : p = fi : s$ = "Fichier" : gosub 7100
7030 poke p, 0 : p = p + 1 : s$ = "Ouvrir" : gosub 7100 : ' article 1
7040 poke p, 1 : p = p + 1 : s$ = "Fermer" : gosub 7100 : ' article 2, inactif
7050 poke p, $80 : poke p + 1, 0 : p = p + 2 : ' article 3 : separateur
7060 poke p, 0 : p = p + 1 : s$ = "Quitter" : gosub 7100 : poke p, $ff : ' article 4
7070 ed = alloc(25) : p = ed : s$ = "Edition" : gosub 7100
7080 poke p, 2 : p = p + 1 : s$ = "Copier" : gosub 7100 : ' coche
7090 poke p, 0 : p = p + 1 : s$ = "Coller" : gosub 7100 : poke p, $ff : return
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 ' 35,1 New Menu, descripteur en q : numero dans mn, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 mn = peek($ff06) : return
8100 ' 35,3 Menu Select ou 35,4 Menu Track en (x, y) : menu deroule dans r (35,3)
8105 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y
8110 poke $ff01, f : poke $ff00, 35
8120 while peek($ff00) : wend : r = peek($ff08) : e = peek($ff02) : return
8200 ' 35,5 Menu Track End : menu dans cm, article dans ca
8210 while peek($ff00) : wend : f = 5 : gosub 8110
8220 cm = peek($ff04) : ca = peek($ff05) : return
8300 ' 32,19 Toolbox Reset : plus aucun menu
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnFichier : 0 1 128 0 ; Copier : 2Assembleur 65C02 (64tass)
; Lire les options d'un article (groupe 35, fonction 8, 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+6 ; P2 : numéro du menu
sta a
lda #<b2
ldx #>b2
jsr envoi
lda ControlPort+6 ; P2 : numéro du menu
sta b
ldx #1
_o: phx
jsr WaitMessage
plx
lda a
sta ControlPort+4 ; P0 : menu
stx ControlPort+5 ; P1 : article
phx
lda #35
ldx #8 ; Get Item Flags
jsr appel
plx
lda ControlPort+6
sta o-1,x
inx
cpx #5
bne _o
jsr WaitMessage
lda b
sta ControlPort+4
lda #1
sta ControlPort+5
lda #35
ldx #8 ; Get Item Flags
jsr appel
lda ControlPort+6
sta c
lda #<b3
ldx #>b3
jsr envoi
lda #<t4
ldx #>t4
jsr ecrire
ldx #0
_a5: lda #' '
jsr WriteCharacter
lda o,x
jsr decimal
inx
cpx #4
bne _a5
lda #<t6
ldx #>t6
jsr ecrire
lda c
jsr decimal
lda #13
jsr WriteCharacter
rts
; Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
; un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
fichier: .byte 7
.text "Fichier"
.byte 0, 6
.text "Ouvrir" ; article 1
fermer: .byte 1, 6
.text "Fermer" ; article 2, inactif
.byte $80, 0 ; article 3 : séparateur
.byte 0, 7
.text "Quitter" ; article 4
.byte $FF
edition: .byte 7
.text "Edition"
.byte 2, 6
.text "Copier" ; coché
.byte 0, 6
.text "Coller"
.byte $FF
o: .fill 4
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus aucun menu
b1: .byte 35, 1, 2 ; 35,1 : New Menu
.word fichier
a: .byte 0
b2: .byte 35, 1, 2 ; 35,1 : New Menu
.word edition
b: .byte 0
c: .byte 0
b3: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus aucun menu
t4: .text "Fichier :", 0
t6: .text " ; Copier : ", 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
; 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 0Fichier : 0 1 128 0 ; Copier : 235,9 Set Menu Bar Bounds Trinity
Limite la barre des menus entre deux abscisses au lieu de toute la largeur de l'écran.
| Octets | Type | Rôle |
|---|---|---|
P0-P1 | int16 | bord gauche |
P2-P3 | int16 | bord droit, exclu (0 : toute la largeur) |
| Octets | Type | Rôle |
|---|---|---|
erreur | uint8 | 1 si le bord gauche est négatif ou si le droit ne dépasse pas le gauche |
Le premier titre commence au bord gauche plus 4 ; un clic hors de la barre ne touche rien, et un menu déroulé ne dépasse pas le bord droit. Un menu déroulé est fermé, puis la barre est redessinée à sa nouvelle place ; ce qu'elle couvrait avant est laissé tel quel. 32,19 rend toute la largeur. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
Keeps the menu bar between X = Parameters:0,1 (left) and X = Parameters:2,3 (right, excluded) instead of the whole width of the screen (Trinity T-83) : the first title starts at left + 4, clicks outside the bar hit nothing, and a pull-down never goes past the right edge. Right = 0 gives back the full width, which is also the state after a reset ; a right edge past the screen is taken as the screen edge. A pulled down menu is closed, then the bar is redrawn at its new place ; what it covered before is left as it is (the program repaints it). Sets the error flag if left is negative or right is not greater than left.
C (llvm-mos)
/* Limiter la barre des menus (groupe 35, fonction 9, 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)
;
}
/* Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF. */
static uint8_t fichier[] = { 7, 'F', 'i', 'c', 'h', 'i', 'e', 'r',
0, 6, 'O', 'u', 'v', 'r', 'i', 'r', /* article 1 */
1, 6, 'F', 'e', 'r', 'm', 'e', 'r', /* article 2, inactif */
0x80, 0, /* article 3 : séparateur */
0, 7, 'Q', 'u', 'i', 't', 't', 'e', 'r', 0xFF }; /* article 4 */
static uint8_t edition[] = { 7, 'E', 'd', 'i', 't', 'i', 'o', 'n',
2, 6, 'C', 'o', 'p', 'i', 'e', 'r', /* coché */
0, 6, 'C', 'o', 'l', 'l', 'e', 'r', 0xFF };
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 uint8_t nouveau(uint8_t *menu) { /* 35,1 New Menu : rend le numéro */
libre();
p16(0, (uint16_t)menu);
api(35, 1);
return ControlPort.params[2];
}
static uint8_t point(uint8_t f, int16_t x, int16_t y) { /* 35,3 Menu Select ou 35,4 Menu Track en (x, y) */
libre();
p16(0, x);
p16(2, y);
api(35, f);
return ControlPort.params[4]; /* 35,3 : menu déroulé, 0 si aucun titre touché */
}
static uint8_t choix_menu, choix_article;
static void fin(void) { /* 35,5 Menu Track End : menu et article choisis */
libre();
api(35, 5);
choix_menu = ControlPort.params[0];
choix_article = ControlPort.params[1];
}
static void reinit(void) { /* 32,19 Toolbox Reset : plus aucun menu */
libre();
api(32, 19);
}
static uint8_t bornes(int16_t g, int16_t d) { /* Set Menu Bar Bounds : de g à d (exclu) ; d = 0 : tout l'écran */
libre();
p16(0, g);
p16(2, d);
api(35, 9);
return ControlPort.error;
}
int main(void) {
uint8_t a, b, e;
reinit();
nouveau(fichier);
bornes(100, 300); /* le premier titre commence en 104 */
a = point(3, 10, 5); if (a) fin();
b = point(3, 110, 5); if (b) fin();
e = bornes(200, 100); /* droite avant gauche : refusé */
bornes(0, 0);
reinit();
printf("En (10, 5) : %u, en (110, 5) : %u\nBornes a l'envers : erreur %u\n", a, b, e);
return 0;
}En (10, 5) : 0, en (110, 5) : 1
Bornes a l'envers : erreur 1Mad Pascal
// Limiter la barre des menus (groupe 35, fonction 9, Trinity).
program mn9;
uses crt, neo6502;
// Descripteurs de menus (variables : le firmware y écrit), lus sur place : titre précédé de sa longueur, puis pour chaque article un octet
// d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
var fichier: array[0..35] of byte = (7, ord('F'), ord('i'), ord('c'), ord('h'), ord('i'), ord('e'), ord('r'),
0, 6, ord('O'), ord('u'), ord('v'), ord('r'), ord('i'), ord('r'), // article 1
1, 6, ord('F'), ord('e'), ord('r'), ord('m'), ord('e'), ord('r'), // article 2, inactif
$80, 0, // article 3 : séparateur
0, 7, ord('Q'), ord('u'), ord('i'), ord('t'), ord('t'), ord('e'), ord('r'), $FF); // article 4
edition: array[0..24] of byte = (7, ord('E'), ord('d'), ord('i'), ord('t'), ord('i'), ord('o'), ord('n'),
2, 6, ord('C'), ord('o'), ord('p'), ord('i'), ord('e'), ord('r'), // coché
0, 6, ord('C'), ord('o'), ord('l'), ord('l'), ord('e'), ord('r'), $FF);
procedure appel(f: byte); // appel 35,f (paramètres déjà posés)
begin
NeoSendMessage(35, f);
NeoWaitMessage;
end;
function nouveau(menu: pointer): byte; // 35,1 New Menu : rend le numéro
begin
NeoWaitMessage;
wordParams[0] := word(menu);
appel(1);
result := NeoMessage.params[2];
end;
function point(f: byte; x, y: smallint): byte; // 35,3 Menu Select ou 35,4 Menu Track en (x, y)
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
appel(f);
result := NeoMessage.params[4]; // 35,3 : menu déroulé, 0 si aucun titre touché
end;
var choix_menu, choix_article: byte;
procedure fin; // 35,5 Menu Track End : menu et article choisis
begin
NeoWaitMessage;
appel(5);
choix_menu := NeoMessage.params[0];
choix_article := NeoMessage.params[1];
end;
procedure reinit; // 32,19 Toolbox Reset : plus aucun menu
begin
NeoWaitMessage;
NeoSendMessage(32, 19);
NeoWaitMessage;
end;
function bornes(g, d: smallint): byte; // Set Menu Bar Bounds : de g à d (exclu) ; d = 0 : tout l'écran
begin
NeoWaitMessage;
wordParams[0] := word(g);
wordParams[1] := word(d);
appel(9);
result := NeoMessage.error;
end;
var a, b, e: byte;
begin
reinit;
nouveau(@fichier);
bornes(100, 300); // le premier titre commence en 104
a := point(3, 10, 5); if a <> 0 then fin;
b := point(3, 110, 5); if b <> 0 then fin;
e := bornes(200, 100); // droite avant gauche : refusé
bornes(0, 0);
reinit;
writeln('En (10, 5) : ', a, ', en (110, 5) : ', b);
writeln('Bornes a l''envers : erreur ', e);
end.En (10, 5) : 0, en (110, 5) : 1
Bornes a l'envers : erreur 1NeoBASIC
10 ' Limiter la barre des menus (groupe 35, fonction 9, Trinity)
15 gosub 7000
20 gosub 8300
30 q = fi : gosub 8000
40 g = 100 : d = 300 : gosub 2000 : ' le premier titre commence en 104
50 f = 3 : x = 10 : y = 5 : gosub 8100 : a = r : if r then gosub 8200
60 f = 3 : x = 110 : y = 5 : gosub 8100 : b = r : if r then gosub 8200
70 g = 200 : d = 100 : gosub 2000 : e9 = e : ' droite avant gauche : refuse
80 g = 0 : d = 0 : gosub 2000
90 gosub 8300
100 print "En (10, 5) : ";a;", en (110, 5) : ";b
110 print "Bornes a l'envers : erreur ";e9
120 end
2000 ' Set Menu Bar Bounds : de g a d (exclu) ; d = 0 : tout l'ecran
2010 while peek($ff00) : wend : doke $ff04, g : doke $ff06, d : f = 9 : goto 8110
7000 ' descripteurs de menus, lus sur place : titre precede de sa longueur, puis pour chaque article
7010 ' un octet d'options (bit 0 inactif, bit 1 coche, bit 7 separateur) et son texte, enfin $FF
7020 fi = alloc(36) : p = fi : s$ = "Fichier" : gosub 7100
7030 poke p, 0 : p = p + 1 : s$ = "Ouvrir" : gosub 7100 : ' article 1
7040 poke p, 1 : p = p + 1 : s$ = "Fermer" : gosub 7100 : ' article 2, inactif
7050 poke p, $80 : poke p + 1, 0 : p = p + 2 : ' article 3 : separateur
7060 poke p, 0 : p = p + 1 : s$ = "Quitter" : gosub 7100 : poke p, $ff : ' article 4
7070 ed = alloc(25) : p = ed : s$ = "Edition" : gosub 7100
7080 poke p, 2 : p = p + 1 : s$ = "Copier" : gosub 7100 : ' coche
7090 poke p, 0 : p = p + 1 : s$ = "Coller" : gosub 7100 : poke p, $ff : return
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 ' 35,1 New Menu, descripteur en q : numero dans mn, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 mn = peek($ff06) : return
8100 ' 35,3 Menu Select ou 35,4 Menu Track en (x, y) : menu deroule dans r (35,3)
8105 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y
8110 poke $ff01, f : poke $ff00, 35
8120 while peek($ff00) : wend : r = peek($ff08) : e = peek($ff02) : return
8200 ' 35,5 Menu Track End : menu dans cm, article dans ca
8210 while peek($ff00) : wend : f = 5 : gosub 8110
8220 cm = peek($ff04) : ca = peek($ff05) : return
8300 ' 32,19 Toolbox Reset : plus aucun menu
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnEn (10, 5) : 0, en (110, 5) : 1
Bornes a l'envers : erreur 1Assembleur 65C02 (64tass)
; Limiter la barre des menus (groupe 35, fonction 9, 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 #<b2
ldx #>b2
jsr envoi
lda #<b3
ldx #>b3
jsr envoi
lda ControlPort+8 ; P4 : menu déroulé
sta a
lda a
beq _s4
lda #<b5
ldx #>b5
jsr envoi
_s4:
lda #<b6
ldx #>b6
jsr envoi
lda ControlPort+8 ; P4 : menu déroulé
sta b
lda b
beq _s7
lda #<b8
ldx #>b8
jsr envoi
_s7:
lda #<b9
ldx #>b9
jsr envoi
lda ControlPort+2
sta e
lda #<b10
ldx #>b10
jsr envoi
lda #<b11
ldx #>b11
jsr envoi
lda #<t12
ldx #>t12
jsr ecrire
lda a
jsr decimal
lda #<t13
ldx #>t13
jsr ecrire
lda b
jsr decimal
lda #13
jsr WriteCharacter
lda #<t14
ldx #>t14
jsr ecrire
lda e
jsr decimal
lda #13
jsr WriteCharacter
rts
; Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
; un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
fichier: .byte 7
.text "Fichier"
.byte 0, 6
.text "Ouvrir" ; article 1
fermer: .byte 1, 6
.text "Fermer" ; article 2, inactif
.byte $80, 0 ; article 3 : séparateur
.byte 0, 7
.text "Quitter" ; article 4
.byte $FF
edition: .byte 7
.text "Edition"
.byte 2, 6
.text "Copier" ; coché
.byte 0, 6
.text "Coller"
.byte $FF
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus aucun menu
b1: .byte 35, 1, 2 ; 35,1 : New Menu
.word fichier
b2: .byte 35, 9, 4 ; Set Menu Bar Bounds : de 100 à 300 (exclu)
.word 100, 300
b3: .byte 35, 3, 4 ; 35,3 : Menu Select
.word 10, 5
a: .byte 0
b5: .byte 35, 5, 0 ; 35,5 : Menu Track End
b6: .byte 35, 3, 4 ; 35,3 : Menu Select
.word 110, 5
b: .byte 0
b8: .byte 35, 5, 0 ; 35,5 : Menu Track End
b9: .byte 35, 9, 4 ; droite avant gauche : refusé
.word 200, 100
e: .byte 0
b10: .byte 35, 9, 4 ; 0 : tout l'écran
.word 0, 0
b11: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus aucun menu
t12: .text "En (10, 5) : ", 0
t13: .text ", en (110, 5) : ", 0
t14: .text "Bornes a l'envers : 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
; 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 0En (10, 5) : 0, en (110, 5) : 1
Bornes a l'envers : erreur 135,10 Menu Key Trinity
Pilote les menus au clavier, avec le code d'une touche.
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | code de la touche (message2 d'un événement de touche, groupe 33) |
| Octets | Type | Rôle |
|---|---|---|
P0 | uint8 | 0 touche inutilisée, 1 menu déroulé, 2 article choisi, 3 menu fermé sans choix |
P1 | uint8 | menu choisi (si P0 = 2) |
P2 | uint8 | article choisi (si P0 = 2) |
Barre fermée, F10 ($43) déroule le premier menu, premier article actif en évidence ; toute autre touche rend 0 et reste au programme. Menu déroulé : Gauche ($50) et Droite ($4F) changent de menu, Haut ($52) et Bas ($51) passent d'un article actif à l'autre (séparateurs et articles inactifs sautés, en boucle), Entrée ($28) choisit, Échap ($29) ou F10 ferme. La souris (35,3 à 35,5) fonctionne toujours. NeoBASIC n'a pas de mot-clé pour cet appel.
Texte de la documentation du firmware (anglais)
The menus from the keyboard (Trinity T-89). Pass the key code (message2 of a key down or auto key event, group 33) in Parameter:0. With the bar closed, F10 pulls the first menu down with its first enabled item highlighted. With a menu down : Left and Right pull the previous or next menu down, Up and Down move to the previous or next enabled item (separators and disabled items are skipped ; both wrap), Enter chooses, Escape or F10 closes. On return Parameter:0 is 0 if the key was not used (bar closed and not F10 : the program handles the key), 1 if it was used and a menu is down, 2 if an item was chosen (menu in Parameter:1, item in Parameter:2, as Function 35,5), 3 if the menu was closed without a choice. The mouse (35,3 to 35,5) keeps working.
C (llvm-mos)
/* Piloter les menus au clavier (groupe 35, fonction 10, 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)
;
}
/* Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF. */
static uint8_t fichier[] = { 7, 'F', 'i', 'c', 'h', 'i', 'e', 'r',
0, 6, 'O', 'u', 'v', 'r', 'i', 'r', /* article 1 */
1, 6, 'F', 'e', 'r', 'm', 'e', 'r', /* article 2, inactif */
0x80, 0, /* article 3 : séparateur */
0, 7, 'Q', 'u', 'i', 't', 't', 'e', 'r', 0xFF }; /* article 4 */
static uint8_t edition[] = { 7, 'E', 'd', 'i', 't', 'i', 'o', 'n',
2, 6, 'C', 'o', 'p', 'i', 'e', 'r', /* coché */
0, 6, 'C', 'o', 'l', 'l', 'e', 'r', 0xFF };
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 uint8_t nouveau(uint8_t *menu) { /* 35,1 New Menu : rend le numéro */
libre();
p16(0, (uint16_t)menu);
api(35, 1);
return ControlPort.params[2];
}
static uint8_t point(uint8_t f, int16_t x, int16_t y) { /* 35,3 Menu Select ou 35,4 Menu Track en (x, y) */
libre();
p16(0, x);
p16(2, y);
api(35, f);
return ControlPort.params[4]; /* 35,3 : menu déroulé, 0 si aucun titre touché */
}
static uint8_t choix_menu, choix_article;
static void fin(void) { /* 35,5 Menu Track End : menu et article choisis */
libre();
api(35, 5);
choix_menu = ControlPort.params[0];
choix_article = ControlPort.params[1];
}
static void reinit(void) { /* 32,19 Toolbox Reset : plus aucun menu */
libre();
api(32, 19);
}
/* Codes des touches (message2 des événements du groupe 33). */
#define F10 0x43
#define BAS 0x51
#define DROITE 0x4F
#define ENTREE 0x28
#define ECHAP 0x29
static uint8_t touche(uint8_t code) { /* Menu Key : 0 inutilisée, 1 menu déroulé, 2 choix, 3 fermé */
libre();
ControlPort.params[0] = code;
api(35, 10);
return ControlPort.params[0];
}
int main(void) {
uint8_t r0, r1, r2, r3, m, a, r4, r5;
reinit();
nouveau(fichier);
nouveau(edition);
r0 = touche(4); /* « a », barre fermée : le programme garde la touche */
r1 = touche(F10); /* déroule « Fichier », « Ouvrir » en évidence */
r2 = touche(BAS); /* saute l'article inactif et le séparateur : « Quitter » */
r3 = touche(ENTREE);
m = ControlPort.params[1];
a = ControlPort.params[2];
touche(F10);
r4 = touche(DROITE); /* menu suivant */
r5 = touche(ECHAP);
reinit();
printf("Touche a : %u\nF10 : %u, bas : %u, Entree : %u (menu %u, article %u)\n", r0, r1, r2, r3, m, a);
printf("F10, droite : %u, Echap : %u\n", r4, r5);
return 0;
}Touche a : 0
F10 : 1, bas : 1, Entree : 2 (menu 1, article 4)
F10, droite : 1, Echap : 3Mad Pascal
// Piloter les menus au clavier (groupe 35, fonction 10, Trinity).
program mn10;
uses crt, neo6502;
// Descripteurs de menus (variables : le firmware y écrit), lus sur place : titre précédé de sa longueur, puis pour chaque article un octet
// d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
var fichier: array[0..35] of byte = (7, ord('F'), ord('i'), ord('c'), ord('h'), ord('i'), ord('e'), ord('r'),
0, 6, ord('O'), ord('u'), ord('v'), ord('r'), ord('i'), ord('r'), // article 1
1, 6, ord('F'), ord('e'), ord('r'), ord('m'), ord('e'), ord('r'), // article 2, inactif
$80, 0, // article 3 : séparateur
0, 7, ord('Q'), ord('u'), ord('i'), ord('t'), ord('t'), ord('e'), ord('r'), $FF); // article 4
edition: array[0..24] of byte = (7, ord('E'), ord('d'), ord('i'), ord('t'), ord('i'), ord('o'), ord('n'),
2, 6, ord('C'), ord('o'), ord('p'), ord('i'), ord('e'), ord('r'), // coché
0, 6, ord('C'), ord('o'), ord('l'), ord('l'), ord('e'), ord('r'), $FF);
procedure appel(f: byte); // appel 35,f (paramètres déjà posés)
begin
NeoSendMessage(35, f);
NeoWaitMessage;
end;
function nouveau(menu: pointer): byte; // 35,1 New Menu : rend le numéro
begin
NeoWaitMessage;
wordParams[0] := word(menu);
appel(1);
result := NeoMessage.params[2];
end;
function point(f: byte; x, y: smallint): byte; // 35,3 Menu Select ou 35,4 Menu Track en (x, y)
begin
NeoWaitMessage;
wordParams[0] := word(x);
wordParams[1] := word(y);
appel(f);
result := NeoMessage.params[4]; // 35,3 : menu déroulé, 0 si aucun titre touché
end;
var choix_menu, choix_article: byte;
procedure fin; // 35,5 Menu Track End : menu et article choisis
begin
NeoWaitMessage;
appel(5);
choix_menu := NeoMessage.params[0];
choix_article := NeoMessage.params[1];
end;
procedure reinit; // 32,19 Toolbox Reset : plus aucun menu
begin
NeoWaitMessage;
NeoSendMessage(32, 19);
NeoWaitMessage;
end;
const F10 = $43; BAS = $51; DROITE = $4F; ENTREE = $28; ECHAP = $29; // codes des touches (message2, groupe 33)
function touche(code: byte): byte; // Menu Key : 0 inutilisée, 1 menu déroulé, 2 choix, 3 fermé
begin
NeoWaitMessage;
NeoMessage.params[0] := code;
appel(10);
result := NeoMessage.params[0];
end;
var r0, r1, r2, r3, m, a, r4, r5: byte;
begin
reinit;
nouveau(@fichier);
nouveau(@edition);
r0 := touche(4); // « a », barre fermée : le programme garde la touche
r1 := touche(F10); // déroule « Fichier », « Ouvrir » en évidence
r2 := touche(BAS); // saute l'article inactif et le séparateur : « Quitter »
r3 := touche(ENTREE);
m := NeoMessage.params[1];
a := NeoMessage.params[2];
touche(F10);
r4 := touche(DROITE); // menu suivant
r5 := touche(ECHAP);
reinit;
writeln('Touche a : ', r0);
writeln('F10 : ', r1, ', bas : ', r2, ', Entree : ', r3, ' (menu ', m, ', article ', a, ')');
writeln('F10, droite : ', r4, ', Echap : ', r5);
end.Touche a : 0
F10 : 1, bas : 1, Entree : 2 (menu 1, article 4)
F10, droite : 1, Echap : 3NeoBASIC
10 ' Piloter les menus au clavier (groupe 35, fonction 10, Trinity)
15 gosub 7000
20 ' codes des touches (message2 des evenements du groupe 33)
30 f1 = $43 : ba = $51 : dr = $4f : en = $28 : ec = $29
40 gosub 8300
50 q = fi : gosub 8000 : q = ed : gosub 8000
60 k = 4 : gosub 2000 : r0 = kr : ' « a », barre fermee : le programme garde la touche
70 k = f1 : gosub 2000 : r1 = kr : ' deroule « Fichier », « Ouvrir » en evidence
80 k = ba : gosub 2000 : r2 = kr : ' saute l'article inactif et le separateur : « Quitter »
90 k = en : gosub 2000 : r3 = kr : m = peek($ff05) : a = peek($ff06)
100 k = f1 : gosub 2000
110 k = dr : gosub 2000 : r4 = kr : ' menu suivant
120 k = ec : gosub 2000 : r5 = kr
130 gosub 8300
140 print "Touche a : ";r0
150 print "F10 : ";r1;", bas : ";r2;", Entree : ";r3;" (menu ";m;", article ";a;")"
160 print "F10, droite : ";r4;", Echap : ";r5
170 end
2000 ' Menu Key : 0 inutilisee, 1 menu deroule, 2 choix, 3 ferme
2010 while peek($ff00) : wend : poke $ff04, k : f = 10 : gosub 8110
2020 kr = peek($ff04) : return
7000 ' descripteurs de menus, lus sur place : titre precede de sa longueur, puis pour chaque article
7010 ' un octet d'options (bit 0 inactif, bit 1 coche, bit 7 separateur) et son texte, enfin $FF
7020 fi = alloc(36) : p = fi : s$ = "Fichier" : gosub 7100
7030 poke p, 0 : p = p + 1 : s$ = "Ouvrir" : gosub 7100 : ' article 1
7040 poke p, 1 : p = p + 1 : s$ = "Fermer" : gosub 7100 : ' article 2, inactif
7050 poke p, $80 : poke p + 1, 0 : p = p + 2 : ' article 3 : separateur
7060 poke p, 0 : p = p + 1 : s$ = "Quitter" : gosub 7100 : poke p, $ff : ' article 4
7070 ed = alloc(25) : p = ed : s$ = "Edition" : gosub 7100
7080 poke p, 2 : p = p + 1 : s$ = "Copier" : gosub 7100 : ' coche
7090 poke p, 0 : p = p + 1 : s$ = "Coller" : gosub 7100 : poke p, $ff : return
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 ' 35,1 New Menu, descripteur en q : numero dans mn, erreur dans e
8010 while peek($ff00) : wend : doke $ff04, q : f = 1 : gosub 8110
8020 mn = peek($ff06) : return
8100 ' 35,3 Menu Select ou 35,4 Menu Track en (x, y) : menu deroule dans r (35,3)
8105 while peek($ff00) : wend : doke $ff04, x : doke $ff06, y
8110 poke $ff01, f : poke $ff00, 35
8120 while peek($ff00) : wend : r = peek($ff08) : e = peek($ff02) : return
8200 ' 35,5 Menu Track End : menu dans cm, article dans ca
8210 while peek($ff00) : wend : f = 5 : gosub 8110
8220 cm = peek($ff04) : ca = peek($ff05) : return
8300 ' 32,19 Toolbox Reset : plus aucun menu
8310 while peek($ff00) : wend : poke $ff01, 19 : poke $ff00, 32
8320 while peek($ff00) : wend : returnTouche a : 0
F10 : 1, bas : 1, Entree : 2 (menu 1, article 4)
F10, droite : 1, Echap : 3Assembleur 65C02 (64tass)
; Piloter les menus au clavier (groupe 35, fonction 10, 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 #<b2
ldx #>b2
jsr envoi
lda #4 ; « a », barre fermée : le programme garde la touche
jsr touche
sta r0
lda #F10 ; déroule « Fichier », « Ouvrir » en évidence
jsr touche
sta r1
lda #BAS ; saute l'article inactif et le séparateur
jsr touche
sta r2
lda #ENTREE
jsr touche
sta r3
lda ControlPort+5 ; P1 : menu choisi
sta m
lda ControlPort+6 ; P2 : article
sta a
lda #F10
jsr touche
lda #DROITE ; menu suivant
jsr touche
sta r4
lda #ECHAP
jsr touche
sta r5
lda #<b3
ldx #>b3
jsr envoi
lda #<t4
ldx #>t4
jsr ecrire
lda r0
jsr decimal
lda #13
jsr WriteCharacter
lda #<t5
ldx #>t5
jsr ecrire
lda r1
jsr decimal
lda #<t6
ldx #>t6
jsr ecrire
lda r2
jsr decimal
lda #<t7
ldx #>t7
jsr ecrire
lda r3
jsr decimal
lda #<t8
ldx #>t8
jsr ecrire
lda m
jsr decimal
lda #<t9
ldx #>t9
jsr ecrire
lda a
jsr decimal
lda #<t10
ldx #>t10
jsr ecrire
lda #13
jsr WriteCharacter
lda #<t11
ldx #>t11
jsr ecrire
lda r4
jsr decimal
lda #<t12
ldx #>t12
jsr ecrire
lda r5
jsr decimal
lda #13
jsr WriteCharacter
rts
; Descripteurs de menus, lus sur place : titre précédé de sa longueur, puis pour chaque article
; un octet d'options (bit 0 inactif, bit 1 coché, bit 7 séparateur) et son texte, enfin $FF.
fichier: .byte 7
.text "Fichier"
.byte 0, 6
.text "Ouvrir" ; article 1
fermer: .byte 1, 6
.text "Fermer" ; article 2, inactif
.byte $80, 0 ; article 3 : séparateur
.byte 0, 7
.text "Quitter" ; article 4
.byte $FF
edition: .byte 7
.text "Edition"
.byte 2, 6
.text "Copier" ; coché
.byte 0, 6
.text "Coller"
.byte $FF
; Codes des touches (message2 des événements du groupe 33).
F10 = $43
BAS = $51
DROITE = $4F
ENTREE = $28
ECHAP = $29
b0: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus aucun menu
b1: .byte 35, 1, 2 ; 35,1 : New Menu
.word fichier
b2: .byte 35, 1, 2 ; 35,1 : New Menu
.word edition
r0: .byte 0
r1: .byte 0
r2: .byte 0
r3: .byte 0
m: .byte 0
a: .byte 0
r4: .byte 0
r5: .byte 0
b3: .byte 32, 19, 0 ; 32,19 Toolbox Reset : plus aucun menu
t4: .text "Touche a : ", 0
t5: .text "F10 : ", 0
t6: .text ", bas : ", 0
t7: .text ", Entree : ", 0
t8: .text " (menu ", 0
t9: .text ", article ", 0
t10: .text ")", 0
t11: .text "F10, droite : ", 0
t12: .text ", Echap : ", 0
; Menu Key (35,10) sur la touche A : rend 0 inutilisée, 1 menu déroulé, 2 choix, 3 fermé.
touche: pha
jsr WaitMessage
pla
sta ControlPort+4
lda #35
ldx #10
jsr appel
lda ControlPort+4
rts
; 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
; 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 0Touche a : 0
F10 : 1, bas : 1, Entree : 2 (menu 1, article 4)
F10, droite : 1, Echap : 3