← ST-Computer 11 / 1989

Menüleisten total

Programmierpraxis

Eine GEM-Menüleiste, die horizontal Am oberen Bildschirmrand in einer vorgegebenen Schriftgrösse erscheint, ist zugegeben sehr praktisch und mit einigen GFA-BASIC-Befehlen auch leicht zu verwalten. Wie wäre es aber z.B., wenn man nicht nur eine Menüleiste, sondern beliebig viele darstellen könnte? Und wie wäre es dann, wenn man diese Menüleisten auf dem Bildschirm dort plazieren könnte, wo man dies gerade haben will, wenn man diese Menüleisten in vier verschieden Schriftgrössen und einer beliebigen Textfarbe zeichnen könnte, wenn man diese Menüleisten nicht nur horizontal sondern auch vertikal zeichnen könnte, wenn ..., wenn ..., wenn ..., das wäre doch nicht schlecht, oder?

Die hier vorgestellten Routinen ermöglichen es, einem Programm auf einfache Weise eine individuelle Note zu geben, ohne auf das bekannte Prinzip der GEM-Menüleisten verzichten zu müssen. Ein Nachteil dieser Routinen soll gleich zu Anfang genannt werden: Es ist nicht möglich. Accessories aus diesen Routinen heraus aufzurufen. Es ist daher sinnvoll, auch die normale Menüleiste zu verwenden, wenn man nicht auf Accessories verzichten will. Das können die Routinen:

  • Unterstützung aller drei Auflösungen
  • Verwaltung einer beliebigen Anzahl von Menüleisten
  • horizontale oder vertikale Ausrichtung der Menüs
  • wahlweise nach links, rechts, oben oder unten ausklappende Pull-Down-Menüs
  • Menüleisten beliebig auf dem Bildschirm plazierbar
  • 4 Schriftgrößen und frei definierbare Textfarbe
  • versteckte Menüleisten möglich
  • erst nach Mausklick ausklappende Pull-Down-Menüs möglich
  • Menüeinträge können, zusätzlich zu den vom GEM bekannten Möglichkeiten, fett dargestellt werden (z.B. für Überschriften)
  • einfaches Ändern der Menüeinträge (neuer Text kann beliebige Länge haben)

Der Menüaufbau

Die Data-Zeilen für eine Menüleiste sollten folgendermaßen aufgebaut sein: Der erste String in den Daten ist der erste Menütitel, danach folgen die einzelnen Menüeinträge, abgeschlossen wird das ganze mit einem Leerstring. Dann folgt der nächste Titel, usw., das Ende einer Menüleiste wird mit “***” angegeben. Daran anschließend können Daten für weitere Menüleisten nach dem selben Schema folgen. Wenn das erste Zeichen eines Menüeintrages ein “+” oder ist, wird der Eintrag direkt unwählbar fett (“+”), oder unwählbar hell (“-”) gemacht. Das oder “+” erscheint nicht im Eintrag. Der Aufbau der Daten ist somit fast identisch mit dem von GFA-BASIC für GEM-Menüs verwendeten Prinzip. Die Menüdaten werden mit folgenden Befehlen eingelesen:

Restore >Menülabel< Gosub Menues_berechnen(n) Restore >Menülabel< Gosub Menues_initialisieren (x_res,y_res)

n ist die Anzahl der Menüleisten, die am Stück eingelesen werden sollen. In x_res und y_res müssen die maximal möglichen Bildschirmkoordinaten angegeben werden (z.B. 639 und 399 für hohe Auflösung). Das ist schon alles, was zur Initialisierung notwendig ist, danach kann es losgehen.

Weitere Befehle

Gosub Menu_paint(m_nr,x1,y1,x2,y2,r1!,r2!,v!,k!) zeichnet und aktiviert eine Menüleiste.

m_nr entspricht der laufenden Nummer der Menüleiste (m_nr ≥0).

x1,y1,x2,y2 sind die Bildschirmkoordinaten der Menüleiste.

x1 und y1 sind die Koordinaten der in Schreibrichtung linken unteren Ecke des Menüs.

x2 und y2 geben dabei jeweils die Breite des Menüs an, wobei die Menüleiste immer mindestens so breit ist, wie es für den Menütext benötigt wird. Wird als Wert -1 angegeben, nimmt die Routine Standardwerte an.

r1! = Richtung 1
r1! = false => horizontal
r1! = true => vertikal
r2! = Richtung 2
r2! = false => Pull-Downs nach unten oder rechts
r2! = true=> Pull-Downs nach oben oder links

v! = Versteckt-Flag
v! = false => Menü normal
v! = true => Menü versteckt
k! = Mausklick-Flag
k! = false => Pull-Downs normal
k! = true => Pull-Downs erscheinen erst nach Mausklick

GosubOn_menu(*m_nr,*m_p) fragt alle aktiven Menüleisten ab und gibt evtl. in m_nr die Nummer der Menüleiste, in m_p die Nummer des angewählten Eintrags zurück. Dieser Befehl sollte möglichst in eine Schleife gesetzt werden (z.B. DO..LOOP). Die Variablen müssen als Pointer eingesetzt werden, um eine Rückgabe zu ermöglichen!

Gosub Menu_image(m_nr,tg,f) setzt Textgröße und Farbe eines Menüs.

tg = Textgröße (0..3)
f = Textfarbe (0..15)

Gosub Menu_text(m_nr,m_p,a,t$) ändert Attribut und Text eines Eintrages.

m_p = Nummer des Menüeintrags
a = Attribut des Eintrags
a = -1 => keine Änderung,
a = 0 => normal,
a = 1 => fett (unwählbar),
a = 2 => hell (unwählbar),
a = 3 => normal mit Häkchen,
a ≥ 4 => hell mit Häkchen

t$ = Menüeintrag-String
wenn t$ = dann keine Änderung

Gosub Menu_kill(m_nr) löscht eine Menüleiste vom Bildschirm, um Änderungen in der Lage des Menüs oder in der Titelzeile zu ermöglichen.

Gosub Menu_lock(m_nr) sperrt die Bearbeitung eines Menüs, um z.B. einen Aufruf der in ihm enthaltenen Einträge vorübergehend zu vermeiden, oder in Verbindung mit Gosub Menu_kill(m_nr) ein Menü komplett zu entfernen. Die Daten des Menüs bleiben dabei erhalten und können für ein erneutes aktivieren der Menüleiste wieder genutzt werden. Alle anderen Prozeduren sollten nach Möglichkeit nicht genutzt werden, da das den normalen Ablauf mit hoher Wahrscheinlichkeit stören würde.

Die Variablen

Sämtliche von den Routinen benutzten externen Variablen haben ein M_ vorangestellt. Daher dürfte es, wenn man im übrigen Programm Variablennamen mit einem solchen Anfang vermeidet, nicht zu ungewollten Effekten kommen. Im Allgemeinen sollte man darauf verzichten, auf Variablen, die von den Routinen benutzt werden, direkt zuzugreifen, “legale” Ausnahmen davon sind:

  • M_hidden!(m_nr) => Flag für versteckte Menüleisten
  • M_klick!(m_nr) => Maus klick-Flag für Pull-Down-Menüs

Die Variable M_action! kam dazu genutzt werden, um fest-zustellen, ob eine Menüfunktion aktiviert wurde oder nicht. Falls M_action!=True ist, sollte man nicht im Bildschirm zeichnen, da es dann z.B. möglich wäre, daß ein ausgeklapptes Pull-Down-Menü “im Weg” ist.

' *********************************************** ' * Menü-Library von Matthias Andrä ' * (c) MAXON Computer GmbH ' *********************************************** ' Procedure Menues_berechnen(N%) ' Dimensionierungen der Arrays vornehmen ' und maximale Ausmaße der Menüs berechnen ' Local I%,M%,T$,M_mpd%,M_mtit% ' M_max%=Max(0,N%-1) Dim M_maxpulldown%(M_max%),M_maxtitel%(M_max%) Dim M_hidden!(M_max%),M_klick!(M_max%),M_back$(M_max%),M_back!(M_max%) Dim M_paint!(M_max%),M_aktiv!(M_max%), M_text_size%(M_max%) Dim M_th%(M_max%),M_tb%(M_max%),M_tof%(M_max%), M_color% (M_max%) Dim M_x% (M_max%) , M_y% (M_max%) , M_x1% (M_max%) , M_y1%(M_max%) Dim M_direction1!(M_max%),M_direction2!(M_max%) ' Clr M_mpd%,M_mtit% For M%=0 To M_max% M_maxpulldown%(M%)=0 M_maxtitel%(M%)=0 Clr I% M_titel!=True Repeat Read T$ Exit If T$="***" If M_titel! Inc M_maxtitel%(M%) Clr I%,M_titel! Endif If T$="" M_titel!=True M_maxpulldown%(M%)=Max(M_maxpulldown%,I%) Endif Inc I% Until T$="***" Dec M_maxpulldown%(M%) Dec M_maxtitel%(M%) M_mpd%=Max(M_mpd%,M_maxpulldown%(M%)) M_mtit%=Max(M_mtit%,M_maxtitel%(M%)) Next M% ' Dim Menu$(M_max%,M_mtit%,M_mpd%) Dim Menu_style%(M_max%,M_mtit%,M_mpd%) Return Procedure Menues_initialisieren(X_res%,Y_res%) ' Initialisiert die Daten der Menüleisten ' Local A$ M_xres%=X_res% M_yres%=Y_res% For M%=0 To M_max% For M_titel%=0 To M_maxtitel%(M%) For M_pulldown%=0 To M_maxpulldown%(M%) Let Menu$(M%,M_titel%,M_pulldown%)="" Next M_pulldown% Next M_titel% For M_titel%=0 To M_maxtitel%(M%) For M_pulldown%=0 To M_maxpulldown%(M%)+1 Read T$ Exit If T$="" If M_pulldown%=0 Let Menu$(M%,M_titel%,M_pulldown%)=" "+T$+" " Else A$=Left$(T$) If A$="-" Or A$="+" @Menu_nr(M%,M_titel%,M_pulldown%,*M_punkt%) @Menu_text(M%,M_punkt%,Asc(A$)-43-(Asc(A$)=43),"") T$=Mid$(T$,2) Endif Let Menu$(M%,M_titel%,M_pulldown%)=T$ Endif Next M_pulldown% Next M_titel% Read T$ Next M% For M%=0 To M_max% If Xbios(4)=2 Restore L_m2groesse Else Restore L_m1groesse Endif Read M_text_size%(M%),M_tb%(M%),M_th%(M%),M_tof%(M%) M_color%(M%)=1 M_hidden!(M%)=False Next M% M_tx%=-1 M_ty%=-1 M_pulldown%=-1 M_pd%=-1 Clr M_titel% Return Procedure Menu_image(M%,Groesse%,Farbe%) ' Setzen von Textgroesse und Farbe der Menüleiste ' Local I% L_m_groesse: Data 4,6,6,0 L_m1groesse : Data 6,8,8,0 L_m2groesse: Data 13,8,16,2 Data 32,16,32,4 ' If M%>=0 And M%<=M_max% If Groesse%>=0 Restore L_m_groesse Groesse%=Min(3,Groesse%) For I%=0 To Groesse% Read M_text_size%(M%),M_tb%(M%),M_th%(M%),M_tof%(M%) Next I% Endif If Farbe%>=0 M_color%(M%)=Min(15,Farbe%) Endif Endif Return Procedure Menu_paint(M%,X1%,Y1%,X2%,Y2%,Richtung1!,Richtung2!,Versteckt!,Klick!) ' Übernahme der Koordinaten für Menüleiste ' und Menüleiste zeichnen ( falls nicht versteckt ! ) ' If M%>=0 And M%<=M_max% M_direction1!(M%)=Richtung1! M_direction2!(M%)=Richtung2! M_hidden!(M%)=Versteckt! M_klick!(M%)=Klick! M_aktiv!(M%)=True If M_direction1!(M%) M_y%(M%)=M_yres% M_y1%(M%)=0 If Y1%>=0 M_y%(M%)=Min(M_yres%,Max(Y1%,M_tb%(M%)*2)) Endif If Y2%>=0 M_y1%(M%)=Min(Y1%,Y2%) Endif M_x%(M%)=Max(M_th%(M%),Min(M_xres%-2,X1%)) If Not M_hidden!(M%) @M_paint_ver Endif Else M_x%(M%)=0 M_x1%(M%)=M_xres% If X1%>=0 M_x%(M%)=Min(X1%,M_xres%-M_tb%(M%)*2) Endif If X2%>=0 M_x1%(M%)=Min(Max(X1%,X2%),M_xres%) Endif M_y%(M%)=Max(M_th%(M%),Min(M_yres%-2,Y1%)) If Not M_hidden!(M%) @M_paint_hor Endif Endif Endif Return Procedure On_menu(Adresse1%,Adresse2%) ' Fragt Menüleisten ab und gibt die Nummer des Menüs und ' eines evtl, angeklickten Menüpunktes zurück ' Local Mn%,M%,Mx%,My%,Mk%,M_end! Mouse Mx%,My%,Mk% Clr M_end!,M_action! If Menu_nr%>-1 And (Not M_pulldown! And M_invt!) @Menu_off(Menu_nr%) Endif For M%=0 To M_max% If M_aktiv!(M%) If M_pd%=M% Or M_pd%=-1 Mn%=-1 If M_pulldown! M_action!=True If Mx%>M_pdx% And Mx%<M_pdx1% And My%>M_pdy% And My%<M_pdy1%-1 M_pnr%=(My%-M_pdy%-1)/M_th%(M%)+1 If Menu_style%(M%,M_titel%,M_pnr%)=0 Or Menu_style%(M%,M_titel%,M_pnr%)=3 If M_nr%<>M_pnr% If M_punkt! Put Max(0,M_pdx%+1),Max(0,M_py%),M_punkt$,10 Endif M_py%=(M_pnr%-1)*M_th%(M%)+M_pdy%+1 M_py1%=M_py%+M_th%(M%) Get Max(0,M_pdx%+1),Max(0,M_py%),Min(M_xres%,M_pdx1%-1),Min(M_yres%,M_py1%),M_punkt$ Put Max(0,M_pdx%+1),Max(0,M_py%),M_punkt$,10 M_punkt%=M_pnr% M_nr%=M_pnr% M_punkt!=True Endif If Mk%=1 @Menu_nr(M%,M_titel%,M_punkt%,*Mn%) @Menu_pull_down_back M_end!=True Goto L_on_menu_end Endif Else Goto L_mpunkt_invert Endif Else L_mpunkt_invert: If M_punkt! Put Max(0,M_pdx%+1),Max(0,M_py%),M_punkt$,10 Clr M_punkt!,M_nr%,M_pnr%,M_punkt% Endif Endif Endif If M_direction1!(M%) If My%>=M_y1%(M%) And My%<=M_y%(M%) And Mx%>=M_x%(M%)-M_th%(M%) And Mx%<=M_x%(M%)+2 M_action!=True If M_hidden!(M%) And Not M_back!(M%) @M_paint_ver Endif If M_pulldown! Or (Mk%=1 And M_klick!(M%)) Or Not M_klick!(M%) Y%=M_y%(M%) For M_t%=0 To M_maxtitel%(M%) Sub Y%,Len(Menu$(M%,M_t%,0))*M_tb%(M%) Exit If Y%<My% Next M_t% Y%=Max(0,Y%) If Y%<My% If Y%<>M_ty% @Menu_inv(M%) Get M_x%(M%)-M_th%(M%)-M_direction2!(M%),Y%,M_x%(M%)+1-M_direction2!(M%),Y%+Len(Menu$(M%,M_t%,0))*M_tb%(M%),Inv_titel$ Put M_x%(M%)-M_th%(M%)-M_direction2!(M%),Y%,Inv_titel$,10 M_ty%=Y% M_titel%=M_t% M_invt!=True Endif Endif Endif Else Goto L_pulldown_delete Endif Else If My%>=M_y%(M%)-M_th%(M%) And My%<=M_y%(M%)+2 And Mx%>=M_x%(M%) And Mx%<=M_x1%(M%) M_action!=True If M_hidden!(M%) And Not M_back!(M%) @M_paint_hor Endif If M_pulldown! Or (Mk%=1 And M_klick!(M%)) Or Not M_klick!(M%) X%=M_x%(M%) For M_t%=0 To M_maxtitel%(M%) Add X%,Len(Menu$(M%,M_t%,0))*M_tb%(M%) Exit If X%>Mx% Next M_t% If X%>Mx% Sub X%,Len(Menu$(M%,M_t%,0))*M_tb%(M%) If X%<>M_tx% @Menu_inv(M%) Get X%,Max(0,M_y%(M%)-M_th%(M%)-M_direction2!(M%)),Min(M_xres%,Min(M_xres%,X%+Len(Menu$(M%,M_t%,0))* M_tb%(M%))),Min(M_yres%,M_y%(M%)+1-M_direction2!(M%)),Inv_titel$ Put X%,Max(0,M_y%(M%)-M_th%(M%)-M_direction2!(M%)), Inv_titel$,10 M_tx%=X% M_titel%=M_t% M_invt!=True Endif Endif Endif Else L_pulldown_delete: If M_paint!(M%) And ((M_pulldown! And Mk%=1) Or Not M_pulldown!) @Menu_pull_down_back @Menu_off(M%) Clr M_titel%,M_invt! M_back!(M%)=False M_ty%=-1 M_tx%=-1 Endif Endif Endif If M_invt! And M_titel%<>M_pulldown% @Menu_pull_down Endif L_on_menu_end: *Adresse1%=M% *Adresse2%=Mn% Endif Endif Exit If M_end! Next M% Return Procedure Menu_text(M%,M_n%,S%,T$) ' Ändert Menüeinträge ' Local I%,N%,Mn% If M%>=0 And M%<=M_max% Clr Mn% For I%=0 To M_maxtitel%(M%) For N%=0 To M_maxpulldown%(M%) Exit If Mn%=M_n% Sub Mn%,Menu$(M%,I%,N%)<>"" Next N% Exit If Mn%=M_n% Next I% If Mn%=M_n% If S%>=0 Let Menu_style%(M%,I%,N%)=S% Endif If T$<>"" Let Menu$(M%,I%,N%)=T$ Endif Endif Endif Return Procedure Menu_kill(M%) ' Löscht angegebene Menüleiste ' If M%>=0 And M%<=M_max% If M_direction1!(M%) Put M_x%(M%)-M_th%(M%),M_y1%(M%),M_back$(M%),3 Else Put M_x%(M%),M_y%(M%)-M_th%(M%),M_back$(M%),3 Endif Clr M_titel%, M_invt! M_paint!(M%)=False M_back!(M%)=False Endif Return Procedure Menu_lock(M%,Lock!) ' Sperrt Menübearbeitung, oder hebt Sperre auf ' M_aktiv!(M%)=Not Lock! Return ' ' **** interne Routinen für Menü-Library **** ' Procedure Menu_inv(M%) If M_invt! If M_direction1!(M%) Put Max(0,M_x%(M%)-M_th%(M%)-M_direction2!(M%)),M_ty%,Inv_titel$,10 M_ty%=-1 Else Put M_tx%,Max(0,M_y%(M%)-M_th%(M%)-M_direction2!(M%)),Inv_titel$,10 M_tx%=-1 Endif Clr M_titel%,Inv_titel$,M_invt! Endif Return Procedure Menu_off(M%) @Menu_inv(M%) If M_hidden!(M%) @Menu_kill(M%) Endif Return Procedure M_leiste_vorbereiten Clr M_leiste$ For M_titel%=0 To M_maxtitel%(M%) M_leiste$=M_leiste$+Menu$(M%,M_titel%,0) Next M_titel% M_paint!(M%)=True M_back!(M%)=True Graphmode 1 Color 1 Return Procedure M_paint_hor @M_leiste_vorbereiten M_x1%(M%)=Min(M_xres%,Max(M_x%(M%)+Len(M_leiste$)*M_tb%(M%),M_x1%(M%))) Get M_x%(M%),M_y%(M%)-M_th%(M%),M_x1%(M%),M_y%(M%)+2,M_back$(M%) Put M_x%(M%),M_y%(M%)-M_th%(M%),M_back$(M%),0 Deftext M_color%(M%),0,0,M_text_size%(M%) Text M_x%(M%),M_y%(M%)-M_tof%(M%),M_leiste$ If M_direction2!(M%) Line M_x%(M%),M_y%(M%)-M_th%(M%),M_x1%(M%),M_y%(M%)-M_th%(M%) Else Line M_x%(M%),M_y%(M%)+2,M_x1%(M%),M_y%(M%)+2 Endif Return Procedure M_paint_ver @M_leiste_vorbereiten M_y1%(M%)=Max(0,Min(M_y%(M%)-Len(M_leiste$)*M_tb%(M%),M_y1%(M%))) Get M_x%(M%)-M_th%(M%),M_y1%(M%),M_x%(M%)+2,M_y%(M%),M_back$(M%) Put M_x%(M%)-M_th%(M%),M_y1%(M%),M_back$(M%),0 Deftext M_color%(M%),0,900,M_text_size%(M%) Text M_x%(M%)-M_tof%(M%),M_y%(M%),M_leiste$ If M_direction2!(M%) Line M_x%(M%)-M_th%(M%),M_y%(M%),M_x%(M%)-M_th%(M%),M_y1%(M%) Else Line M_x%(M%)+2,M_y%(M%),M_x%(M%)+2,M_y1%(M%) Endif Return Procedure Menu_pull_down Local I%,Mn% @Menu_pull_down_back Clr I%,M_pdb% Repeat Inc I% M_pdb%=Max(M_pdb%,Len(Menu$(M%,M_titel%,I%))*M_tb%(M%)) Until I%>=M_maxpulldown%(M%) Or Menu$(M%,M_titel%,I%)="" Inc M_pdb% Add I%,Menu$(M%,M_titel%,I%)="" M_pdl%=I%*M_th%(M%)+2 If M_direction1!(M%) If M_direction2!(M%) M_pdx1%=M_x%(M%)-M_th%(M%) M_pdx%=M_pdx1%-M_pdb% Else M_pdx%=M_x%(M%)+2 M_pdx1%=M_pdx%+M_pdb% Endif M_pdy1%=M_ty%+Len(Menu$(M%,M_titel%,0))*M_tb%(M%) M_pdy%=M_pdy1%-M_pdl% Else M_pdx%=M_tx% M_pdx1%=M_tx%+M_pdb% If M_direction2!(M%) M_pdy1%=M_y%(M%)-M_th%(M%) M_pdy%=M_pdy1%-M_pdl% Else M_pdy%=M_y%(M%)+2 M_pdy1%=M_pdy%+M_pdl% Endif Endif Y%=M_pdy%-M_tof%(M%) M_pulldown%=M_titel% M_pulldown!=True M_pd%=M% Graphmode 1 Get Max(0,M_pdx%),Max(0,M_pdy%),Min(M_xres%,M_pdx1%),Min(M_yres%,M_pdy1%),M_pulldown$ Deffill 1,0,0 Pbox M_pdx%,M_pdy%,M_pdx1%,M_pdy1% For Mn%=1 To I% Add Y%,M_th%(M%) If Menu_style%(M%,M_titel%,Mn%)<3 If Menu_style%(M%,M_titel%,Mn%)=2 And M_text_size%(M%)=4 Deftext M_color%(M%),3,0,M_text_size%(M%) Else Deftext M_color%(M%),Menu_style%(M%,M_titel%,Mn%),0,M_text_size%(M%) Endif Text M_pdx%+1,Y%,Menu$(M%,M_titel%,Mn%) Else If Menu_style%(M%,M_titel%,Mn%)=3 Deftext M_color%(M%),0,0,M_text_size%(M%) Else If M_text_size%(M%)=4 Deftext M_color%(M%),3,0,M_text_size%(M%) Else Deftext M_color%(M%),2,0,M_text_size%(M%) Endif Endif Text M_pdx%+1,Y%,Menu$(M%,M_titel%,Mn%) Text M_pdx%+2,Y%,"" Endif Next Mn% Return Procedure Menu_pull_down_back If M_pulldown! Put Max(0,M_pdx%),Max(0,M_pdy%),M_pulldown$,3 M_pulldown%=-1 M_pd%=-1 Clr M_punkt!,M_pulldown!,M_pnr%,M_nr% Endif Return Procedure Menu_nr(M%,M_t%,M_n%,Adresse%) Local I%,N%,Nm% If M%>=0 And M%<=M_max% Clr Nm% For I%=0 To M_maxtitel%(M%) For N%=0 To M_maxpulldown%(M%) Exit If I%=M_t% And N%=M_n% Sub Nm%,Menu$(M%,I%,N%)<>"" Next N% Exit If I%=M_t% And N%=M_n% Next I% If I%>M_maxtitel%(M%) Clr Nm% Endif *Adresse%=Nm% Endif Return
Matthias Andrä