Mit dem Modul Fensterfarben des neuen CPX-Kontrollfeldes für MEGA STE und TT kann man ein Muster für jedes Fensterelement einstellen. Wenn man aber für verschiedene Elemente das gleiche Muster oder die gleiche Farbe haben möchte, muß man für jedes Element die selbe Einstellungsprozedur wiederholen. Diese Arbeit kann man sich aber ersparen, weil es auch einfacher geht: Man selektiert ein Element und macht die gewünschte Einstellung. Nun klickt man auf das Element und hält die Maustaste gedrückt. Siehe da, der Mauspfeil wandelt sich zur Patschhand, und wenn man sie nun auf ein anderes Element zieht, übernimmt dieses sofort die gerade gemachten Einstellungen. Schade, daß man erst durch Zufall auf solche Erleichterungen stößt, das Handbuch ist hierzu nicht sehr auskunftsfreudig.
Ch. Rössig, W 2863 Ritterhude 2
Normale Dialogboxen lassen nur eine begrenzte Zeilenzahl zu. Mit dem hier vorgestellten Programm kann man selber eine Dialogbox erstellen, die dann soviele Zeilen enthält, wie man will. Um eine neue Zeile zu beginnen, muß man einfach nur den Längsbalken „|“ (ASCII Nr. 124) setzen. Das Programm benötigt einen Monochrommonitor.
Folgende Parameter wurden benutzt:
art - Textart: 0 = normal, 1 = fett, usw.
txt$ - der auszugebende Text
x_breite - Pixel-Breite auf der x-Achse
y_breite - Pixel-Breite auf der y-Achse
zeilen_anz - Anzahl der auszugebenden Zeilen
A. Hitzschke, W-2990 Papenburg
' Programm zur Erstellung einer Dialogbox
' (c)1991 by MAXON-Computer
' Autor: Andre Hitschke
' ab GFA-BASIC 1.0
'
GOSUB dialog(art,txt$,x_breite,y_breite,zeilen_anz)
'
PROCEDURE dialog(art,txt$,xx,yy,anz)
SGET sc$
x1=320-(xx/2)
x2=320+(xx/2)
y1=200-(yy/2)-20
y2=200+(yy/2)+30
DEFFILL 1,0,0
PBOX x1-4,y1-4,x2+4,y2+4
BOX x1,y1/x2,y2
BOX x1-1,y1-1,x2+1/y2+1
BOX 280,y2-45,360,y2-10
BOX 279,y2-45,361,y2-10
BOX 279,y2-44,361,y2-11
BOX 27 8,y2-46,362,y2-9
DEFTEXT 1,0,0,13
TEXT 312,y2-22,"OK"
DEFTEXT 1,art,0,13
i=0
FOR a=1 TO anz
INC i
t$=" "
FOR i=1 TO LEN(txt$)
EXIT IF MID$(txt$,i,1)="|"
t$=t$+MID$(txt$,i,1)
NEXT i
TEXT 320-(LEN(t$)/2)*8,y1+(a+20),t$
NEXT a
GRAPHMODE 1
DEFFILL 1,1,1
DO
IF ASC(INKEY$)=13
GOTO return
ENDIF
SHOWM
MOUSE x,y,k
IF k=1
IF x>280 AND x<360 AND y>y2-45 AND y<y2-10
GRAPHMODE 3
PBOX 280,y2-44,360,y2-11
GRAPHMODE 1
PLOT 280,y2-44
REPEAT
UNTIL MOUSEK=0
GOTO return
ENDIF
IF x>x1 AND x<x2 AND y>y1 AND y>y2
ELSE
OUT 2,7
ENDIF
ENDIF
LOOP
return:
SPUT sc$
RETURN
Die Benutzeroberfläche des ATARI ist eigentlich komfortabel genug, aber manchmal nervt es schon, wenn man sich durch diverse Ordner „durchklicken“ muß, um ein Programm zu starten. In der ST-COMPUTER 10/91 wurde zwar schon eine entsprechende Lösung auf gezeigt, allerdings mit erheblichen Einschränkungen.
Mein Vorschlag ist da etwas aufwendiger. Kernstück ist ein kleines MAXON-Pascal-Programm, welches nur die Aufgabe hat, den Programmpfad aus einer Datei zu lesen und dann das Programm zu starten. Man könnte dieses Programmgerüst sogar noch erweitern, um z.B. eine Kommandozeile zu übergeben oder mehrere Programme (à la AUTO-Ordner) zu starten. Nachdem das Programm compiliert wurde, gehe man am besten folgendermaßen vor:
Wenn man einen Ordner speziell nur für diese Batch-Dateien anlegt und diese nach dem Booten in einem Fenster anzeigen läßt, kann man die Programme per Doppelklick unmittelbar von dort aus starten.
M. Grimm, W 6073 Egelsbach
Program BatchPrg;
{$R-,S-,I-,V-,D-,M 2,1,1,5}
(* Kein Debugging und so wenig Speicher wie *)
(* möglich reservieren *)
Uses Dos;
Var PrgPfad : PathStr;
DataFile : Text;
Direktory : DirStr;
PrgName : NameStr;
Ext ; ExtStr;
Begin
Reset ( DataFile, ParmStr(1));
(* Batchdatei öffnen, ParmStr (1) gibt den, *)
(* vom Desktop übergebenen Commandstring *)
(* zurück. In diesem Fall den Zugriffspfad *)
(* der Batchdatei *)
If IOResult = 0 Then (* OK, kein Fehler *)
Begin
Readln(DataFile,PrgPfad); (* Prgpfad lesen *)
Close(DataFile); (* Batchdatei schließen *)
(* Folgendes setzt das akt. Laufwerk und *)
(* das akt. Direktory. Das ist nötig, *)
(* damit die Programme ihre Zusatzdateien *)
(* z.B. *.RSC auch finden. *)
FSplit(PrgPfad,Direktory,PrgName,Ext);
SetDrive(Ord(PrgPfad[1]-ORD('A'));
(* Laufwerk setzen (GEMDOS 14) *)
ChDir(Direktory);
(* Direktory setzen GEMDOS 59) *)
If (Ext = '.TOS') OR (Ext = '.TTP') Then
(* Bildschirm löschen *)
Write(#27,1E');
SwapVectors;
(* eine Spezialität von MAXON-Pascal *)
Exec(PrgPfad,'');
(* Programm starten (GEMDOS 75) *)
SwapVectors;
End;
End.
Vielschreiber kennen das Problem: Durch geschwindte Fingerakrobatik kommt es des öfteren vor, daß zwei folgende Buchstaben vertauscht werden. Beispiel: aus „aber“ wird „baer“. Nun gibt es aber schon einige clevere Textprogramme, die per Tastendruck die zwei Buchstaben links vom Cursor wieder zurücktauschen. Besitzt die Gewohnheitstextverarbeitung diese Option nicht, so könnte man mit einem Makrorekorder (wie z.B. in HARLEKIN oder MACREC) diese Vertauschfunktion leicht realisieren:
<Blockende> <links> <Blockanfang> <links> <Block verschieben> <Markierungen löschen> <rechts> <rechts>
In WORDPLUS funktioniert das so:
<ALT E> <links> <ALT S> <links> <ALT M> <ALT H> <rechts> <rechts>
Sollte „Block verschieben“ nicht vorhanden sein, geht es auch so:
<Blockende> <links> <Blockan-fang> <cut> <links> <paste> <rechts>
Der schnellen Erreichbarkeit wegen sollte man das Makro auf die ESC-Taste legen. Das beschriebene Verfahren sollte mit allen Textprogrammen funktionieren, welche entsprechende Tastenkürzel besitzen, keine Sicherheitsabfragen machen und auch keine Meldungen auf den Bildschirm bringen.
Dr. Ch. Giesse. Yogyakarta, Indonesien
Ein Fehler in der RENAME Anweisung von MAXON-Pascal, Version 1.5 läßt sich durch einen Patch der Datei MASPAS.PRG an der Stelle $13C1D beheben: „$402 ersetzen durch „$44“.
Dadurch wird die Befehlsfolge „pea(a7); pea $40(a7)“ korrigiert in „pea(a7); pea$44(a7)“.
H.A. Pohley, W-5042 Erftstadt
Anwender, die das Shareware-Desktop Gemini zusammen mit MultiGEM benutzen, kennen das Problem nur zu gut. Damit Gemini beim Programmstart nicht alle Fenster schließt, muß jedes Programm einzeln unter „Anwendung anmelden“ eingetragen und der Status „Fenster schließen“ deaktiviert werden. Könnte man nicht diese mühselige Arbeit umgehen, indem man Gemini defaultmäßig mitteilen würde, die Fenster immer geöffnet zu lassen?
Man kann! Folgende Zeile muß dazu in die Datei „MUPFEL.MUP“ mit einem Text-Editor eingetragen werden:
setenv GEMDEFAULT "W:Y"
Dadurch gewöhnt man Gemini diese etwas grobe Eigenart, einfach alle Fenster zu schließen, ab.
CM
Seit der ATART Messe in Düsseldorf gibt es das Update von TURBO C (2.0) auf PURE C. Was tut man bei einer neuen Compilerversion? Man übersetzt die beigefügten Demos und laßt sie laufen. Gesagt, getan - 2 Bomben!
Nachdem sichergestellt war, daß kein Hardware-Fehler vorlag, denn mit der alten Version funktionierte ja alles, war der Fehler mit dem sehr guten Debugger nach kurzer Zeit gefunden. Der Übeltäter war die Funktion delay(Verzögerung /ms/) in der Library pcextlib.lib.
Beim Aufruf der Funktion wird als Parameter die gewünschte Verzögerungszeit im ms übergeben. Innerhalb der Funktion werden daraus 5ms-Werte gemacht, die dann mittels der 200Hz-Uhr die Verzögerungszeit realisiert. Zu diesem Zweck muß auf die Speicherstelle $04BA.L zugegriffen werden. Dies wiederum ist erst nach Aufruf der GEM-Funktion „Super“ ohne Bombenwurf möglich. Diese Funktion darf man nicht im Supervisormodus aufrufen. Dies wurde offensichtlich als störend empfunden, die Funktion wurde so ergänzt, daß zuerst ermittelt wird, in welchem Prozessorstatus der Aufruf erfolgt ist. Die Originalfunktion ist, disassembliert mit dem Programm „DISPOBJ.TTP“, als Listing 1 beigefügt.
Wird dem GEM-Aufruf $20 der Wert 1L übergeben, wird der Status des aufrufenden Programms zurückgegeben. Diese Ergänzung wurde offensichtlich von einem versierten 80X86-Programmierer erstellt, denn die Werte werden in Intel-Manier auf den Stack gespeichert. Versiert war er deshalb, weil er es nicht für notwendig hielt, diese kleine Ergänzung zu testen. Die Funktion muß so korrigiert werden, wie Listig 2 es zeigt. Wird beim Linken diese neue Funktion vor der Library PCEXTLIB.LIB aufgerufen, ist im Programm dieser Fehler beseitigt.
G. Fritze, W-6729 Jockgrim
.MODULE GLOBAL
delay:
T000000: MOVEM.L D6-D7/A2,-(A7)
T000004: MOVEQ.L #$00,D7
T000006: MOVE.W D0,D7
T000008: CLR.W -(A7) «==
T00000A: MOVE.L #$00010020,-(A7) «==
T000010: TRAP #1
T000012: ADDQ.W #6,A7
T000014: MOVE.L D0,D6
T000016: BNE.B T000022
T000018: CLR.L -(A7)
T00001A: MOVE.W #$0020,-(A7)
T00001E: TRAP #1
T000020: ADDQ.W #6,A7
T000022: DIVU #$0005,D7
T000026: AND.L #$0000FFFF,D7
T00002C: ADD.L $04BA.W,D7
T000030: CMP.L $04BA.W,D7
T000034: BPL.B T000030
T000036: TST.W D6
T000038: BNE.B T000040
T00003A: MOVE.L D0,-(A7)
T00003C: MOVE.W #$0020,-(A7)
T000040: TRAP #1
T000042: ADDQ.W #6,A7
T000044: MOVEM.L (A7)+,D6-D7/A2
T000048: RTS
.END
; new delay routine in 'MOTOROLA' modus
; corrected by G. Fritze, Jockgrim
; (c)1991 by MAXON-Computer
clock_200 =$04BA
EXPORT delay
delay: MOVEM.L D6-D7,-(A7) ;save registers
MOVEQ.L #0, D7
MOVE.W D0, D7 ;delay value
MOVE.L #1, -(A7) ;inquire Status
MOVE.W #$20, -(A7)
TRAP #1
ADDQ.W #6, A7
MOVE.L D0, D6 ;save registers
BNE already_super
CLR.L -(A7) ;switch to super
;mode
MOVE.W #$20, -(A7)
TRAP #1
ADDQ.W #6, A7
already_super:
DIVU #$5, D7 ;5 ms Steps
AND.L #$FFFF, D7
ADD.L clock_200, D7 ;set limit value
wait: CMP.L clock_200, D7
BPL wait
TST.W D6 ;was in super
;mode?
BNE was_super ;yes
MOVE.L D0, -(A7) ;no, switch
;in user mode
MOVE.W #$20, -(A7)
TRAP #1
ADDQ.W #6,A7
was_super:
MOVEM.L (A7)+, D6-D7 ;restore
;registers
RTS
.END
In der ST-COMPUTER wurde in der Rubrik Quicktips schon einmal gezeigt, wie die Adresse einer Funktion in ST-Pascal+ ermittelt werden kann. Wird dieser Trick aber zweimal (!) angewandt, kann auf diese Art ein Funktions-Pointer realisiert werden. Damit läßt sich z.B. zu einem GEM-Window die Funktion abspeichern, die für einen Redraw zuständig ist.
Die erste Stufe ist das Ermitteln der Funktionsadresse. Dies geschieht wie in den erwähnten Artikeln dadurch, daß in der Deklaration ein Funktionspointer angegeben wird (siehe program test), in der Definition aber nur ein long_integer (siehe Modul f_ptr).
{$M+} program f_ptr; {$E+}
function
fkt_ptr(par:long_integer);
long_integer;
begin fkt_ptr:=par; end;
begin end.
In der zweiten Stufe wird das Verfahren genau umgekehrt. In der Deklaration (in program test) wird als Parameter ein long_integer erwartet, in der Definition (Modul f_exe) aber ein Funktions-Pointer.
{$M+} program f_exe; ($E+}
function fkt_exe(function
fkt(par:integer):boolean;
param: integer): boolean;
begin
fkt_exe:=fkt(param);
end;
begin end.
In einem Testprogramm kann man nun der Funktion fkt_ptr eine Funktion übergeben und bekommt die Adresse als long_integer zurück. Übergibt man diese Adresse an fkt_exe, wird die Funktion ausgeführt.
var fptr:long_integer;
erg:boolean;
function fkt_exe(fpar:long_integer;
param:integer):boolean;
external;
funktion fkt_ptr(function fkt(par:integer):boolean): long_integer;
external;
function f (par:integer) :boolean;
begin f:=(par<0); end;
begin fptr:=fkt_ptr(f);
erg:=fkt_exe(f,3); end.
M. Bernstein, W-6350 Bad Nauheim