Popup-Menüs in Omikron.BASIC

Smalltalk hat sie, der Amiga hat sie, aber GEM hat sie merkwürdigerweise nicht. Popup-Menüs sind in Aussehen und Wirkung Dropdown-Sorten ganz ähnlich, können aber nach Wunsch an jedem Platz des Bildschirms und Programmes!) eingesetzt werden.

Da sie leicht zu handhaben sind, haben sie außerdem den Vorteil, daß der Benutzer die gebotenen Alternativen da zu sehen bekommt, wohin er das Auge gerichtet hat: zum Beispiel gerade da, wo der Mauszeiger sich befand, als die Maustaste betätigt wurde. Dies macht die Benutzerführung Ihres Programmes angenehmer, direkter und schneller.

Die Spielregeln

Die Syntax ist möglichst einfach:

Popup(X,Y,Popup$,Reply)

X und Y sind die Koordinaten des oberen, linken Punktes des Menüs. Sie werden automatisch angepaßt, sollte durch die Wahl von X und Y das Menü (teilweise) außerhalb des Bildschirms fallen.

Durch Popup$ wird bestimmt, wie das Menü aussieht.
Es ist von folgendem Aufbau:

[-]EintragO|[-]Eintrag1|....

Das “|” Zeichen dient zur Trennung der einzelnen Einträge. Das optionale Minuszeichen [-] bedeutet, daß der darauffolgenden Eintrag dünn (disabled) darzustellen sei. Das erste Minuszeichen wird nicht ausgegeben. Beispiel :

" Hilfe |-------| Ändern | Löschen "

Es gibt hier vier Menüpunkte, wobei der zweite Eintrag dünn dargestellt wird mit 15(!) Minuszeichen.

Geben Sie nun

"- Hilfe |-------| Ändern | Löschen "

als Popup$ ein, dann wird auch “Hilfe” dünn ausgegeben (ohne Minuszeichen).

Das Ergebnis wird in Reply zurückgegeben. Im obenstehenden Beispiel ist das also 0, wenn “Hilfe”, 2, wenn “Ändern” und 3, wenn “Löschen” vom Benutzer gewählt wurde usw. Das Ergebnis ist -1, wenn außerhalb des Menüs geklickt oder wenn ein “disabled”-Menüpunkt gewählt wurde.

Das Programm

Hoffentlich spricht das Listing des Programmes für sich. Es gibt jedoch ein paar Punkte, die ich verdeutlichen muß.

  1. Sie können das Programm ohne Zeilennummern (CTRL-CLR/HOME) eintippen. Wenn Sie sie trotzdem benutzen wollen (warum eigentlich?), können Sie im Direktmodus RENUM anwenden und das Programm dann mit MERGE einbinden. Andernfalls können Sie mit F7-F7 (Block Start), F7-SHIFT F7 (Block End) und F7-F8 (Block Save) die Prozeduren abspeichern und darauf mit F7-SHIFT F8 (Block Load) in Ihrem Programm dahin plazieren, wo Sie sie haben wollen (so mache ich es immer).
  2. Falls Sie das AES benutzen (Dropdown-Menüs oder Windows), müssen Sie die Zeilen mit den Wind_Update-Anrufen am Anfang und Ende der Prozedur Popup ent-REMmen, um im Programmverlauf Ereigniskonflikten zuvorzukommen. Das Popup-Menü benimmt sich dann wie eine Form_Alert-Box. (Eine weitere Erklärung würde hier zu weit führen.)
    Die Wind_Update-Prozedur befindet sich in der GEMLIB; Das GEMSEL-Programm kümmert sich dann um den Rest.
  3. Variablen wie X,Y usw. können durch X%,Y% ersetzt werden. Ich habe das hier unterlassen, um das Tippen zu erleichtern.
  4. Die Prozeduren Getb(X,Y,B$) und Putb(X,Y.B$[,Modus]) am Ende des Listings emulieren den Get- und Put-Befehl des GFA-BASICs. Dies ist bei GFA-Omikron-Übersetzungen vielleicht recht nützlich. Für Nicht-Omikronianer sei gesagt, daß die Kopfzeile der Prozedur Putb zwar ein bißchen merkwürdig aussieht, aber so etwas in Omikron.BASIC ganz legitim ist.
  5. Diese Popup-Menüs sind für jede Bildschirmauflösung geeignet.

Hans Heemskerk

Beispiel für ein Popupmenü
' ****************************************************
' Popupmenues in OMIKRON.Basic (c) Hans Heemskerk 1988 
'
' Syntax
' Popup(X,Y,Popup$,Reply)
'   X,Y : Geben die Koordinaten des oberen, linken Punktes an.
'   Popup$="(-)Eintrag0|(-)Eintrag1|....."
'   (-) gibt an. ob der Eintrag "disabled" (duenn)
'       darzustellen ist.
'   Das erste Minuszeichen wird dabei nicht gezeichnet! 
'   Reply : Das Ergebnis = 0,1,2. .. fuer "able"-
'           Menuepunkte. oder 
'                        = -1 nenn ausserhalb des Menues
'                          geklickt oder ein "disabled"-Menuepunkt 
'                          gewaehlt wurde.
'
'   Fuer jede Bildschirmaufloesung geeignet.
'
'
' ************************************************
'                    HAUPTPROGRAMM
' ************************************************
PRINT CHR$(27);"f";: ' Cursor Aus ..
FILL COLOR =1: FILL STYLE =2,4: ' Desktopartiger Hintergrund ..

PBOX 0,0,640,400
MOUSEON
REPEAT
    Popup( MOUSEX , MOUSEY ," Diese Popupmenues | erscheinen gerade | 
    da, wo der | Mauszeiger | sich befindet |-------------------------| 
    Quit ",R)
UNTIL R=6
MOUSEOFF
END

' ************************************************
'
' Procedure Popup : Die eigentliche Prozedur.
'
' Benutzte Variablen
'   Anzahl : Anzahl der Menuepunkte 
'   I1,I2,Pop$ : Hilfsvariablen 
'   Breite.Hoehe : Dimensionen des Menues
'   Buffer$ : Der Bildschirmausschnitt wird in diesen Puffer gerettet.
'   Ch,Cw : Charakter-Hoehe und -Breite (sind Resolutionsabhaengig).
'   Sh,Sw : Screen Hoehe und Breite (ebenfalls).
'
'   ACHTUNG! Wenn Sie Windows u/o Dropdownmenus benutzen, 
'            müssen Sie die REMs vor den Wind_Update Anrufe entfernen.
'
' ************************************************
DEF PROC Popup(X,Y,Popup$,R Reply)
LOCAL Anzahl,I1,I2,Breite,Hoehe,Buffer$,Pop$
LOCAL Ch=8-8*( PEEK($44C)=2),Cw=8' Character-Breite und -Hoehe ..
LOCAL Sh=200-200*( PEEK($44C=2),Sw=640*( PEEK($44C)=0)*320' Bildschirmgroesse.

    ' Wind_Update(3) * Falls Sie Dropdown-Menues u/o Windows benutzen.

    Zeichne_Popup_Menu

    REPEAT UNTIL MOUSEBUT =0: ' Damit es nicht wieder sofort verschwindet ..

    ' Mausueberwachung ..
    REPEAT
        Finde_Eintrag(I2)
        IF I2<Anzahl AND MID$(Pop$,I2+1,1)=CHR$(1) THEN 
            Invertiere(X+1,Y+(Ch+2)#I2+1,Breite-2,(Ch+2))
            REPEAT Finde_Eintrag(I1) UNTIL I1<>I2 OR MOUSEBUT 
            Invertiere(X+1,Y+(Ch+2)*I2+1,Breite-2,(Ch+2))
        ENDIF 
    UNTIL MOUSEBUT

    ' Rueckgabe bestimmen ..
    Reply=I2

    IF I2<Anzahl AND MID$(Pop$,I2+1,1)= CHR$(1) THEN 
        Touch(X+1,Y+(Ch+2)*I2+1,Breite-2,(Ch+2))
    ELSE ' Disabled ..
        Reply=-1
    ENDIF

    ' Bildschirm wiederherstellen ..
    Putb(X-1,Y-1,Buffer$)
    ' Wind_Update(2) ' Falls Sie Dropdown Menues u/o Windows benutzen.

RETURN

' ************************************************
'
' Zeichne_Popup_Menu : Diese Prozedur analysiert Popup$.
'                      bestimmt die Anzahl
'                      der Menuepunkte, berechnet Hoehe und 
'                      Breite des Menues und zeichnet es.
'
' ************************************************
DEF PROC Zeichne_Popup_Menu

    ' Popup$ analysieren, Anzahl, Hoehe und Breite berechnen.

    I2=1:Anzahl=0:Breite=0
    REPEAT
        IF MID$(Popup$,I2,1)="-" THEN 
            Pop$=Pop$+ CHRS(0)
        ELSE
            Pop$=Pop$* CHRS(1)
        ENDIF
        Anzahl=Anzahl+1:I1= INSTR(I2,Popup$,"|")
        IF I1=0 THEN I1= LEN(Popup$)
        Breite= MAX(Breite,I1-I2+( MID$(Popup$,I2+1,1)="-")) 
        I2=I1+1 
    UNTIL I1=LEN(Popup$)

    ' Breite und Hoehe in Pixel ..
    Breite=(Breite)*Cw+2:Hoehe=Anzahl*(Ch+2)+2

    ' Damit das Menu auf dem Bildschirm passt ..
    X=X+((X+Breite)>=(Sw-3))*(X+Breite-(Sw-1))-(X<=1)
    Y=Y+((Y+Hoehe)>=(Sh-3))*(Y+Hoehe-(Sh-1))-(Y<=1)
    IF X<=0 THEN X=1 
    IF Y<=0 THEN Y=1

    FILL STYLE =0,1 ' Weiss ..
    MOUSEOFF

    ' Bildschirminhalt retten ..
    Getb(X-1,Y-1,Breite+2,Hoehe+2,Buffer$)

    ' Dicke box zeichnen ..
    PBOX X,Y,Breite,Hoehe: BOX X-1,Y-1,Breite+2,Hoehe+2

    ' Texte schreiben ..
    I2=1
    FOR I=0 TO Anzahl-1 
        I1= INSTR(I2, Popup$, "|")
        IF I1=0 THEN I1= LEN(Popup$)+1 
        IF MID$(Pop$,I+1,1)= CHRS(0) THEN ' Disabled 
            TEXT STYLE =2
            TEXT X+1,Y*Ch+I*(Ch+2), MID$(Popup$,I2+1,I1-I2-1) 
        ELSE ' Normal
            TEXT X+1,Y+Ch+I*(Ch+2), MID$(Popup$,I2,I1-I2)
        ENDIF
        TEXT STYLE =0 ' Normal 
        I2=I1+1 
    NEXT 
    MOUSEON 
 RETURN

' ************************************************
'
' Finde_Eintrag : Ermittelt, ueber welchem Menuepunkt der 
' Mauszeiger gerade schwebt.
'
' ************************************************

DEF PROC Finde_Eintrag(R I)
	FOR I=0 TO Anzahl-1 
		IF FN Maus_Ist_In(X,Y+I*(Ch+2),Breite,(Ch+2)) THEN EXIT
	NEXT
RETURN

' ************************************************
' Invertiere(X,Y.W.H) : Invertiert Rechteck (X,Y,W,H) 
' (d.h. Schwarz wird Weiss und umgekehrt).
' ************************************************

DEF PROC Invertiere(X,Y,W,H)
	MOUSEOFF : BITBLT X,Y,W,H TO X,Y,W,H,12: MOUSEON 
RETURN
' ************************************************
'
' Maus_Ist_In(X,Y,W,H) : Ermittelt, ob der Mauszeiger 
' sich in Rechteck (X,Y,W,H) befindet.
' ************************************************

DEF FN Maus_Ist_In(X,Y,W,H)= MOUSEX >X AND MOUSEY >Y AND MOUSEX <X+W ANO MOUSEY <Y+H

' ************************************************
'
' Touch(X,Y,W,H) : Flackereffekt an Rechteck (X,Y,W,H)
'
' ************************************************
DEF PROC Touch(X,Y,W,H)
LOCAL Q: FOR Q=1 TO 8: Invertiere(X,Y,W,H): WAIT .04: NEXT
RETURN
' ************************************************
'
' Getb(X,Y,W,H,R B$) : Rettet auf GFA-aehnliche Weise 
'             Rechteck (X,Y,W,H) in den Puffer B$.
'
' ************************************************

DEF PROC Getb(X,Y,W,H,R BS)
LOCAL Bytes=(W+15) SHR 4*H*(2 SHL(2- PEEK($44C)))+6 
	B$= SPACE$(Bytes): MOUSEOFF
	BITBLT X,Y,W,H TO LPEEK( VARPTR(B$))+ LPEEK( SEGPTR+28): MOUSEON 
RETURN
' ************************************************
'
' Putb(X,Y,B$) : Wiederherstellung des in B$ geretteten 
'                Rechtecks an (X,Y). (wie in GFA).
' ODER
'
' Putb(X,Y,B$,Modus) : Wiederherstellung des in B$ geretteten Rechtecks
'                      an (X,Y) mit Verknuepfung Modus
'
' ************************************************

IF 0 THEN DEF PROC Putb(X,Y,B$): LOCAL Modus=3 ELSE DEF PROC Putb(X,Y,B$,Modus)
LOCAL Adr= LPEEK( VARPTR(B$))+ LPEEK( SEGPTR +28)
LOCAL W= WPEEK(Adr+2),H= WPEEK(Adr+4)
	MOUSEOFF : BITBLT Adr TO X,Y,W,H,Modus: MOUSEON 
RETURN


Aus: ST-Computer 06 / 1988, Seite 129

Links

Copyright-Bestimmungen: siehe Über diese Seite