Professional Documents
Culture Documents
This is a listing of all the Lisa ToolKit 3.0 source code files. These files are for the most part written in Lisa Clascal, an
object-oriented Pascal that Apple Computer created from its Lisa Pascal compiler. Other source code languages exist
here too which includes the Lisa Workshop EXEC language (the BUILD files are in this) and various 68000 assembly
language sources such as LIBPL/CLASLIB.TEXT.
For detailed information about the Lisa ToolKit see Apple's extensive ToolKit documentation which includes the Lisa
ToolKit Reference Manual, a Clascal primer, and a ToolKit tutorial.Tmagazine's 1984 article "Software Frameworks"
which describes the ToolKit architecture and its various core classes.
Apple Lisa ToolKit 3.0 Source Code Listing -- 1 of 1012
Size Psize
---- ----12288
24
45056
88
69632
136
93184
182
66560
130
61440
120
Last-Mod-Date
------------02/06/84-11:01
08/29/84-14:49
08/29/84-15:08
08/17/84-11:25
08/17/84-11:27
08/17/84-11:29
Creation-Date
------------02/06/84-11:01
04/02/84-16:44
04/26/84-12:02
05/18/84-19:28
05/07/84-17:57
05/07/84-18:04
Attr
---C
C
Size Psize
---- ----95232
186
44032
86
78848
154
61440
120
37888
74
22528
44
Last-Mod-Date
------------08/17/84-11:32
08/17/84-15:20
08/17/84-15:29
08/17/84-15:23
04/25/84-18:58
08/29/84-15:06
Creation-Date
------------05/07/84-18:03
04/26/84-13:23
04/25/84-16:28
04/25/84-18:01
04/25/84-18:58
05/01/84-15:07
Attr
----
Size Psize
---- ----54272
106
43008
84
55296
108
70656
138
76800
150
33792
66
Last-Mod-Date
------------08/16/84-19:13
08/29/84-14:57
08/17/84-14:01
08/17/84-14:03
08/17/84-14:07
08/17/84-15:53
Creation-Date
------------05/07/84-18:02
05/16/84-08:57
05/01/84-15:50
04/30/84-13:17
04/30/84-14:26
04/26/84-13:03
Attr
---C
C
C
Size Psize
---- ----2048
4
2048
4
2048
4
2048
4
2048
4
2048
4
2048
4
2048
4
2048
4
3072
6
2048
4
3072
6
2560
5
2560
5
1536
3
58368
114
63488
124
102400
200
13312
26
10240
20
71680
140
12288
24
Last-Mod-Date
------------12/12/83-18:55
08/16/84-13:20
08/16/84-13:20
02/02/84-15:47
02/24/84-15:50
08/16/84-13:20
08/16/84-13:21
08/16/84-13:21
08/27/84-11:06
11/13/85-13:56
11/13/85-13:17
11/13/85-13:59
04/04/84-14:07
04/04/84-14:08
08/16/84-13:47
08/17/84-15:55
08/17/84-15:56
08/17/84-15:58
08/29/84-17:12
04/25/84-20:36
05/23/84-09:49
08/15/84-13:10
Creation-Date
------------12/12/83-18:55
09/21/83-14:49
05/15/84-14:58
02/02/84-15:47
02/24/84-15:50
02/24/84-15:50
04/26/84-11:31
05/01/84-15:23
02/24/84-15:51
11/13/85-13:18
11/13/85-13:17
11/13/85-13:18
04/04/84-14:07
04/04/84-14:08
08/16/84-13:47
04/25/84-17:01
05/21/84-09:25
05/21/84-09:30
05/18/84-15:29
04/25/84-20:36
05/18/84-17:44
08/14/84-17:23
Attr
----
$EXEC
{Assemble a module }
{filename build/assemb.text}
$
${ %0 -- pathname of the module to assemble}
${ %1 -- (optional) pathname of the resulting object file. Default name is %0}
${ %2 -- (optional) segment name for the resulting object file. Default is 'blank' segment}
$
$IF %0='' THEN
$WRITE 'File To Assemble? '
$READLN %0
$IF %1='' THEN
$WRITE "Name For Object File [<cr> For %0]? "
$READLN %1
$IF %2='' THEN
$WRITE 'Segment Name [<cr> For Blank Segment]? '
$READLN %2
$ENDIF
$ENDIF
$ENDIF
$DEFAULT %1 to %0
A{ssemble}%0
{source file}
{no listing file}
%1
{object file}
$IF %2<>'' THEN
R{un}changeseg
{re-assign segmentation (optional)}
%1
y%2
$ENDIF
$ENDEXEC
$EXEC
{Compile and Code Generate a Pascal Unit}
{filename build/comp.text}
$
${ %0 -- pathname of the unit to compile}
${ %1 -- (optional) pathname of the resulting object file. Defaults to %0}
${
Destroys file 'temp/c.i'}
${ %2 -- (optional) pathname of intrinsic.lib. Defaults to -#boot-intrinsic.lib}
$
$IF %0='' THEN
$WRITE 'File To Compile? '
$READLN %0
$IF %1='' THEN
$WRITE "Name For Object File [<cr> For %0]? "
$READLN %1
$IF %2='' THEN
$WRITE 'Name Of Intrinsic.lib [<cr> For -#boot-intrinsic.lib]? '
$READLN %2
$ENDIF
$ENDIF
$ENDIF
$DEFAULT %1 TO %0
$DEFAULT %2 TO '-#boot-intrinsic.lib'
P{ascal Compile}?{option flag}
%2
{intrinsic.lib}
%0
{source file}
{no listing file}
%1
{object file}
$ENDEXEC
$EXEC
{Install a Library in Intrinsic.lib}
{filename build/install.text}
$
${ %0 -- number of the library to install}
${ %1 -- (optional)pathname for input intrinsic.lib. Defaults to }
${
-#boot-intrinsic.lib}
${ %2 -- (optional) pathname for output intrinsic.lib. Defaults to %1}
$
$IF %0='' THEN
$WRITE 'Number Of The Library To Install? '
$READLN %0
$IF %1='' THEN
$WRITE 'Pathname For Input Intrinsic.lib [<cr> For -#boot-intrinsic.lib]? '
$READLN %1
$IF %2='' THEN
$WRITE 'Pathname For Output Intrinsic.lib [<cr> For -#boot-intrinsic.lib]? '
$READLN %2
$ENDIF
$ENDIF
$ENDIF
$DEFAULT %1 TO '-#boot-intrinsic.lib'
$DEFAULT %2 TO %1
R{un}IUmanager
%1
%2
I{nstall}%0
QY
$
F{ile-MGR}B{ackup}%2,$
Q{uit}
$ENDEXEC
{ libpl/paslibcall interface }
intrinsic;
interface
USES
{$U libos/syscall.obj }
syscall;
{ -----------------------------------------------------------------------------------}
CONST
CclearScreen
CclearEScreen
CclearELine
CgoHome
CleftArrow
CrightArrow
CupArrow
CdownArrow
= 1;
= 2;
= 3;
=
=
=
=
=
{move
{move
{move
{move
{move
11;
12;
13;
14;
15;
cursor
cursor
cursor
cursor
cursor
to home position}
left one character position}
right one character position}
up one line position}
down one line position}
{ -----------------------------------------------------------------------------------}
function PAbortFlag : boolean;
{ libtk/passwd interface }
INTRINSIC;
{Provides calls for Password Protection in the Lisa Toolkit}
{ Copyright 1983, 1984, Apple Computer Inc. }
INTERFACE
USES {$U -#BOOT-SYSCALL} syscall;
procedure MAKE_SECURE ( var ecode : integer;
var path
: pathname;
var passwd : e_name );
procedure KILL_SECURE ( var ecode : integer;
var path
: pathname;
var passwd : e_name );
procedure OPEN_SECURE ( var ecode
var path
var refnum
manip
var passwd
procedure RENAME_SECURE ( var
var
var
var
:
:
:
:
:
integer;
pathname;
integer;
mset;
e_name );
ecode
path
newName
passwd
:
:
:
:
integer;
pathname;
e_name;
e_name );
ecode
path
oldPasswd
newPasswd
:
:
:
:
integer;
pathname;
e_name;
e_name );
IMPLEMENTATION
{ FINIS }
{ libpl/ppaslibc interface }
intrinsic; interface
USES {$U libos/syscall.obj } syscall;
type
consoledest = (alscreen, mainscreen, xsorocA, xsorocB, folder, spare1, spare2, spare3); { max 8 }
dsProcCode = (dsResProg, dsSoftPwbtn, dsPrintDev, dsSetGPrefix, dsEnbDisk, dsGetDiskEnbF);
dsProcParam = record
case ProcCode : dsProcCode of
dsResProg
: (RProcessId : longint); {must be called before
the process starts running.}
dsSoftPwbtn : (SPButton : boolean);
{result}
dsPrintDev
: (PrDevice : e_name);
dsSetGPrefix : (errnum : INTEGER; prefix : pathname); {result}
dsEnbDisk
: (toEnbDisk : boolean);
dsGetDiskEnbF : (diskEnbF : boolean);
{result}
end;
{ ------ Procedures called by Shell only, some by WorkShop Shell only ---------------- }
PROCEDURE BlockIOInit;
procedure BlockIOdisinit;
implementation
{ FINIS }
{changed
{changed
{changed
{changed
02/06/84
01/20/84
01/18/84
01/09/84
1530
1530
0732
2105
;=============================================================================================
DEBUGF .EQU 1
; 1 to include $D+ info, 0 to exclude it
;=============================================================================================
.MACRO HEAD
.IF DEBUGF
LINK
A6,#0
MOVE.L (SP)+,A6
.ENDC
.ENDM
.MACRO TAIL
.IF DEBUGF
UNLK
A6
RTS
.ASCII %1
.ENDC
.ENDM
;=============================================================================================
.SEG
'SgPASres'
;=============================================================================================
.PROC
HEAD
%_GoLisabug
; PROCEDURE %_GoLisabug;
TRAP
RTS
#0
TAIL
'%_GOLISA'
;=============================================================================================
.FUNC
HEAD
%_GetA5
;
; FUNCTION %_GetA5: LONGINT;
;
; USES A0
;
MOVE.L (SP)+,A0
MOVE.L A5,(SP)
JMP
(A0)
TAIL
{ returns register A5 }
'%_GETA5 '
;=============================================================================================
.PROC %_MethodCall
HEAD
;
;
PROCEDURE %_MethodCall;
uses A0,A1,D0,D1,D2
MOVE.L
TST.B
(SP)+,A1
(A1)
;08
;08
A1 := Return Address
Swap in caller
MOVE
MOVE.B
LSL.W
#0,D0;
(A1)+,D0
#2,D0
;04
;08
;10
MOVE
MOVE.B
LSL.W
#0,D1;
(A1)+,D1
#2,D1
;04
;08
;10
MOVE.L
A1,-(SP)
;13
MOVE.L
4(SP),A0
;16
A0 := SELF
.IF DEBUGF
MOVE.L
BEQ
.ENDC
A0,D2
SELFNIL
;04
;08
MOVE.L
(A0),A0
;12
MOVE.L
(A0),A0
MOVE.L
MOVE.L
$00(A0,D0.W),A0 ;18
-4(A0,D1.W),A0 ;18
JMP
(A0)
;08
Jump to method
#0,D0
SELFNIL DIVS
TAIL
;12
'%_METHOD'
;=============================================================================================
.PROC %_SUPER
HEAD
;
;
PROCEDURE %_Super;
uses A0,A1,D0,D1,D2
MOVE.L
(SP)+,A1
;08
A1 := Return Address
MOVE
MOVE.B
LSL.W
#0,D1
1(SP),D1
#2,D1
;04
;12
;10
MOVE
MOVE.B
LSL.W
#0,D0
(SP)+,D0
#2,D0
;04
;08
;10
MOVE.W
MOVE.L
(SP)+,D2
(SP)+,A0
;08
;12
Chain distance
Slice table pointer of this class
MOVE.L
A1,-(SP)
;13
JMP
ENDSUPL
;10
;16
;10-14
MOVE.L
MOVE.L
$00(A0,D0.W),A0 ;18
-4(A0,D1.W),A0 ;18
JMP
(A0)
;08
Jump to method
'%_SUPER '
;=============================================================================================
.SEG
'SgPASini'
;=============================================================================================
.PROC %_JMPTO
HEAD
;
;
'%_JMPTO '
;=============================================================================================
.PROC %_EXITCA
HEAD
;
;
PROCEDURE %_ExitCaller;
modifies A6,SP
UNLK
UNLK
RTS
A6
A6
.IF DEBUGF
.ASCII '%_EXITCA'
.ENDC
;=============================================================================================
.PROC %_EXITPO
HEAD
;
;
;
4(A6),A0
MOVE.L
UNLK
MOVE.L
JMP
4(SP),A1
A6
A1,SP
(A0)
; A1 := newSP
; pop my caller's stack frame
; SP := newSP
.IF DEBUGF
.ASCII '%_EXITPO'
.ENDC
;=============================================================================================
.FUNC %_NextMethod
HEAD
;
;
;
FUNCTION
uses A0,A1,D0
MOVE.L
MOVE.L
TST.B
12(SP),A0
(A0),A1
(A1)
; @PC
; PC throughout this routine
; swap in the code to test
INTRPLP CMP.W
BEQ
CMP.W
BEQ
CMP.B
BEQ
CMP.W
BEQ
DIVS
#$4EBA,(A1)
JSR_PC
#$4EAD,(A1)
JSR_A5
#$A0,(A1)
INTJSR
#$3F3C,(A1)
PSHCON
#0,D0
PSHCON
MOVE.W
MOVE.B
MOVE.L
MOVE.W
#0,D0
2(A1),D0
8(SP),A0
D0,(A0)
;
;
;
;
Clear
D0 :=
A0 :=
store
MOVE.W
MOVE.B
SUB.W
MOVE.L
MOVE.W
#0,D0
3(A1),D0
#1,D0
4(SP),A0
D0,(A0)
;
;
;
;
;
ADD.L
JMP
#4,A1
INTRPLP
INTJSR
MOVE.L
AND.L
MOVE.L
(A1),D1
#$FFFFFF,D1
D1,A0
; D1 := IUJSR xxx
; D1 := targetLocation
; A0 := targetLocation
FINJSR
MOVE.L
A0,16(SP)
ADD.L
MOVE.L
MOVE.L
#4,A1
12(SP),A0
A1,(A0)
MOVE.L
ADD.W
4(SP),A0
#1,(A0)
; A0 := @methodNumber
; increment methodNumber
MOVE.L
ADD.L
JMP
(SP)+,A0
#12,SP
(A0)
JSR_PC
MOVE.W
LEA
JMP
2(A1),D0
2(A1,D0.W),A0
FINJSR
JSR_A5
MOVE.W
LEA
JMP
2(A1),D0
0(A5,D0.W),A0
FINJSR
TAIL
'%_NEXTME'
;=============================================================================================
.FUNC %_InsStack
HEAD
;
;
;
;
;
;
This routine must be used with extreme care. It inserts space in the middle of the stack.
It adjusts A6, A7, and the static chain, but it can not adjust other pointers that may
exist into the moved area; that is the responsibility of the caller.
This assumes that at least one static link needs adjustment
MOVE.L
MOVE.L
MOVE.L
(SP)+,D2
(SP)+,D1
(SP)+,D0
; D2 := Return address
; D1 := bytesToInsert: must be even and at least 4
; D0 := addrToInsertAt: must be even
SUB.L
SUB.W
LSR.W
SP,D0
#2,D0
#2,D0
INSLP
ADJLP
MOVE.L
SUB.L
MOVE.L
SP,A0
D1,SP
SP,A1
; A0 := Old SP
; SP := ultimate SP
; A1 := ultimate SP
TST.W
-1024(SP)
MOVE.L
DBF
(A0)+,(A1)+
D0,INSLP
SUB.L
MOVE.L
D1,A6
A6,A1
; A6 := ultimate A6
; A1 := addr of first static link
SUB.L
MOVE.L
MOVE.L
CMP.L
BLT
D1,(A1)
(A1),A1
(A1),D0
A0,D0
ADJLP
;
;
;
;
;
MOVE.L
JMP
D2,A1
(A1)
; A1 := Return address
; Return and Pray
TAIL
'%_INSSTA'
;=============================================================================================
.END
{UClascal -- In Spring '84 Release, part of PASLIB: only special units like UOBJECT will ever USE it}
{Copyright 1984, Apple Computer, Inc.}
{changed 04/02/84 1330
{changed
{changed
{changed
{changed
{changed
{changed
02/23/84
02/22/84
02/19/84
01/18/84
01/18/84
01/15/84
1200
1715
1908
2348
0737
1725
01/11/84
01/11/84
01/10/84
01/05/84
1714
1312
2117
2141
RESPONSIBILITIES...
The first class-init block is responsible for calling our procedure:
InitClascal(PROCEDURE Finished(error: INTEGER));
If no other class has already called it, then pleaseInitClascal will be TRUE, in case interested.
If an error occurs during initialization and InitClascal has been called, we'll call:
Finished(error);
The error code is an OS error code, except 3333 (need a new number!!!!) is our own error;
If an error occurs during initialization and InitClascal has not been called, we
do a Trap 0, which should get into LisaBug if present, else cause Technical Difficulties.
Just before returning from %_Pgm2, if FinishedProc is installed, we'll call:
Finished(0);
which may want to copy tables from pClasses, pSTables, pAuthors, pAliases (interface globals)
Typecast errors will also call Finished(3333) (need a new number!!!!)
}
{$SETC ForOS := TRUE }
UNIT UClascal;
{$SETC IsIntrinsic := TRUE }
{$IFC IsIntrinsic}
INTRINSIC;
{$ENDC}
INTERFACE
USES
{$U -#BOOT-SysCall
{$SETC fTrcClascal
{$SETC fSymClascal
{$SETC fDbgClascal
} SysCall;
:= FALSE}
:= TRUE}{FALSE}
:= TRUE}{FALSE}
{$%+}
CONST
maxClasses
maxUnits
= 800;
= 100;
maxAuthors
maxAliases
= 127;
= 127;
TYPE
TByte = -128..127; {The T-names are so programs can USE UObject, NOT USE UClascal, and use "Byte"}
TOctet = 0..255;
TOctets = PACKED ARRAY [0..32700] OF TOctet;
TPOctets = ^TOctets;
TS8 = STRING[8];
TS32 = STRING[32];
TA8 = PACKED ARRAY [1..8] OF CHAR;
TA32 = PACKED ARRAY [1..32] OF CHAR;
THashCompare = (cHole, cMatch, cMismatch);
TMethodArray = ARRAY [1..256] OF LONGINT;
TPMethodArray = ^TMethodArray;
TSliceTable = ARRAY [0..255] OF TPMethodArray;
TPSliceTable = ^TSliceTable;
TClassInfo = RECORD
classAlpha:
superIndex:
objectSize:
classAlias:
companyAndAuthor:
version:
oldestReadableVersion:
END;
{16 bytes
TA8;
INTEGER;
INTEGER;
TByte;
TByte;
TByte;
TByte;
per class}
{Class name in this program: Exactly 8 upper-case characters}
{Index of my superclass in ARRAY [1..xx] OF TClassInfo}
{SIZEOF(an object of this class) as declared}
{For ToolKit: Array index, or 0 if same as classAlpha}
{For ToolKit: Array index, or 0 if unspecified}
{For ToolKit: Version number of the object format (default=1)}
{For ToolKit: Oldest version number it is capable of updating}
{Each of the following types has only one member at run-time, and only during initialization}
{These arrays start out small, but can grow. Each has a single pointer that is updated automatically}
TClassArray
TPClassArray
TSTableArray
TPSTableArray
TAuthorArray
TPAuthorArray
TAliasArray
TPAliasArray
VAR
pleaseInitClascal: BOOLEAN;
classesInitialized: BOOLEAN;
pClasses:
pSTables:
pAuthors:
pAliases:
pMethods:
TPClassArray;
TPSTableArray;
TPAuthorArray;
TPAliasArray;
TPMethodArray;
{pointer to array of
{.................of
{.................of
{.................of
{.................of
limClasses:
limAuthors:
limAliases:
limMethods:
INTEGER;
INTEGER;
INTEGER;
INTEGER;
{space allocated in
{................in
{................in
{................in
numClasses:
INTEGER;
TClassInfo,
TPSliceTable,
TA32,
TA8,
ProcPtr,
numAuthors:
numAliases:
numMethods:
INTEGER;
INTEGER;
INTEGER;
{...................in pAuthors^}
{...................in pAliases^}
{...................in pMethods^
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
FUNCTION
FUNCTION
FUNCTION
FUNCTION
=
=
=
=
1;
1;
1;
1;
growClasses
growAuthors
growAliases
growMethods
=
=
=
=
100;
8;
32;
2000;
TYPE
TS255 = STRING[255];
TPA8 = ^TA8;
TPA32 = ^TA32;
TBytes = ARRAY [0..32700] OF TByte;
TPBytes = ^TBytes;
TWords = ARRAY [0..16350] OF INTEGER;
TPWords = ^TWords;
TPOctet = ^TOctet;
TPByte = ^TByte;
TPInt = ^INTEGER;
TPLint = ^LONGINT;
Handle = ^TPLint;
ProcPtr = ^LONGINT;
TIdxArray = ARRAY [0..maxClasses] OF INTEGER;
TPIdxArray = ^TIdxArray;
VAR
biggestAbstractClass:
mAllocAddr:
currCallCallPC:
INTEGER;
LONGINT;
LONGINT;
pHashName:
pHashUnit:
TPIdxArray;
TPUnitArray;
p%_Class:
pJmp%_Class:
ProcPtr;
ProcPtr;
pFinishedProc:
authorOfUnit:
oldNumClasses:
ProcPtr;
TByte;
INTEGER;
firstPackedName:
dictBase:
INTEGER;
LONGINT;
{$S SgPASres}
FUNCTION FindCn(index: INTEGER; VAR charsApart: BOOLEAN): LONGINT;
{The class names starting with index=firstPackedName are stored packed below the method table,
so the 8-character names start 8 bytes apart.
The class names before index=firstSpreadName are stored in the unused high-order
bytes of the method table, one every fourth byte, so the 8-character names start
32 bytes apart. This kludge saves 1-2K of resident storage in a ToolKit application.
The name of the first class ends just before dictBase, the second class precedes it, etc.}
VAR firstCharOffset: LONGINT;
BEGIN
classAlpha := pClasses^[index].classAlpha;
FOR i := 1 TO 8 DO
className[i] := classAlpha[i];
END
ELSE
BEGIN
dictAddr := FindCn(index, charsApart);
deltaAddr := 3*ORD(charsApart) + 1;
FOR i := 1 TO 8 DO
BEGIN
className[i] := CHAR(TPByte(dictAddr)^);
dictAddr := dictAddr + deltaAddr;
END;
END;
END;
PROCEDURE CpToCn(stp: TPSliceTable; VAR className: TS8);
BEGIN
CiToCn(CiOfCp(stp), className);
END;
PROCEDURE DefaultFinishedProc(error: INTEGER);
BEGIN
%_GoLisabug;
END;
PROCEDURE CallFinishedProc(PROCEDURE ModelFinishedProc(error: INTEGER); error: INTEGER);
VAR pModelFinishedProc: TPLint;
BEGIN
pModelFinishedProc := TPLint(ORD(@pModelFinishedProc) + 18);
pModelFinishedProc^ := ORD(pFinishedProc);
ModelFinishedProc(error);
END;
PROCEDURE CLAFail(error: INTEGER);
BEGIN
IF error = 0 THEN
error := 3333;
CallFinishedProc(DefaultFinishedProc, error);
END;
{$IFC fDbgClascal}
PROCEDURE CLABreak(s: TS255; n: LONGINT);
BEGIN
WriteLn('CLABreak: ', s, ' = ', n);
ClaFail(0);
END;
{$ENDC}
{Each expression "InClass(obj, TFoo)" generates:
%_InObCp(val, classPtr) or %_InObCn(val, 'TFOO
')
The former ("In Object Class Pointer") is generated when TFoo is defined in the same unit.
The latter ("In Object Class Name") is generated when TFoo is defined in another unit.
Both are defined below}
FUNCTION %_InObCp(ordObject, ordSTP: LONGINT): BOOLEAN;
TYPE
PST = ^TST;
TST = ARRAY[0..0] OF PST;
PPST = ^PST;
PPPST = ^PPST;
VAR trialSTP:
PST;
pSTP:
PPST;
BEGIN
%_InObCp := FALSE;
IF ordObject <> 0 THEN
BEGIN
trialSTP := PPPST(ordObject)^^;
pSTP := @trialSTP;
TPByte(pSTP)^ := 0;
WHILE trialSTP <> PST(ordSTP) DO
BEGIN
IF classesInitialized THEN
trialSTP := trialSTP^[-1]
ELSE
trialSTP := PST (TPMethodArray(pSTables^[pClasses^[CiOfCp(TPSliceTable(trialSTP))].superIndex]));
IF ORD(trialSTP) <= 0 THEN
EXIT(%_InObCp);
END;
%_InObCp := TRUE;
END;
END;
FUNCTION %_InObCn(ordObject: LONGINT; VAR className: TS8): BOOLEAN;
TYPE
PST = ^TST;
TST = ARRAY[0..0] OF PST;
PPST = ^PST;
PPPST = ^PPST;
VAR trialSTP:
PST;
tryClassName:
TS8;
pSTP:
PPST;
BEGIN
%_InObCn := FALSE;
IF ordObject <> 0 THEN
BEGIN
trialSTP := PPPST(ordObject)^^;
pSTP := @trialSTP;
TPByte(pSTP)^ := 0;
REPEAT
CpToCn(TPSliceTable(trialSTP), tryClassName);
IF tryClassName = className THEN
BEGIN
%_InObCn := TRUE;
EXIT(%_InObCn);
END;
IF classesInitialized THEN
trialSTP := trialSTP^[-1]
ELSE
trialSTP := PST(TPMethodArray(pSTables^[pClasses^[CiOfCp(TPSliceTable(trialSTP))].superIndex]));
UNTIL ORD(trialSTP) <= 0;
END;
END;
{Each typecast expression TFoo(val) with range checking on generates:
%_CkObCp(val, classPtr) or %_CkObCn(val, 'TFOO
')
The former ("Check Object Class Pointer") is generated when TFoo is defined in the same unit.
The latter ("Check Object Class Name") is generated when TFoo is defined in another unit.
Both are defined below}
FUNCTION %_CkObCp(ordObject, ordSTP: LONGINT): LONGINT;
VAR objClassName:
TS8;
desClassName:
TS8;
BEGIN
%_CkObCp := ordObject;
IF ordObject <> 0 THEN
IF NOT %_InObCp(ordObject, ordSTP) THEN
BEGIN
CpToCn(TPSliceTable(Handle(ordObject)^^), objClassName);
CpToCn(TPSliceTable(ordSTP), desClassName);
{$IFC fDbgClascal}
CLABreak(CONCAT('Attempt to coerce an object of class ',
CONCAT(objClassName,
CONCAT(' to a value of type ',
desClassName))),
0);
{$ELSEC}
CLAFail(0);
END;
{$ENDC}
EXIT(%_CkObCp);
END;
i:
INTEGER;
BEGIN
dictAddr := FindCn(index, charsApart);
IF charsApart THEN
FOR i := 1 TO 8 DO
BEGIN
TPByte(dictAddr)^ := TByte(classAlpha[i]);
dictAddr := dictAddr + 4;
END
ELSE
TPA8(dictAddr)^ := classAlpha;
END;
PROCEDURE _Abstract;
BEGIN
{$IFC fDbgClascal}
CLABreak('An ABSTRACT method has been called: you can''t continue', 0);
{$ELSEC}
CLAFail(0);
{$ENDC}
END;
PROCEDURE InsStack(addrOfGrownArray, afterByte, bytesToInsert: LONGINT);
PROCEDURE AdjustPArray(VAR addrOfOtherArray: LONGINT; which: TS32);
BEGIN
{$IFC fTrcClascal}
Write('... ', which, ' moved from ', addrOfOtherArray:12, ' to ');
{$ENDC}
IF (addrOfGrownArray + afterByte) >= addrOfOtherArray THEN
addrOfOtherArray := addrOfOtherArray - bytesToInsert;
{$IFC fTrcClascal}
WriteLn(addrOfOtherArray:12);
{$ENDC}
END;
BEGIN
{$IFC fTrcClascal}
WriteLn('$$$ About to insert ', bytesToInsert:4, ' bytes after byte ', afterByte:3,
' of ', addrOfGrownArray:5, '$$$');
{$ENDC}
%_InsStack(addrOfGrownArray + afterByte, bytesToInsert); {bytesToInsert must be even and at least 4}
AdjustPArray(LONGINT(pAuthors), 'pAuthors');
AdjustPArray(LONGINT(pAliases), 'pAliases');
AdjustPArray(LONGINT(pClasses), 'pClasses');
AdjustPArray(LONGINT(pSTables), 'pSTables');
AdjustPArray(LONGINT(pMethods), 'pMethods');
AdjustPArray(LONGINT(pHashName),'pHashName');
AdjustPArray(LONGINT(pHashUnit),'pHashUnit');
END;
FUNCTION MAllocate(numNeeded, numToGrowBy: INTEGER): LONGINT;
{** NO VAR PARAMETERS ALLOWED THAT ARE REFERENCED AFTER CALLING InsStack **}
VAR numBytes:
LONGINT;
bytesToInsert: LONGINT;
BEGIN
numBytes := 4 * numNeeded;
mAllocAddr := mAllocAddr - numBytes;
MAllocate := mAllocAddr;
bytesToInsert := ORD(pMethods) - mAllocAddr;
IF bytesToInsert > 0 THEN
BEGIN
IF bytesToInsert < (4 * numToGrowBy) THEN
bytesToInsert := 4 * numToGrowBy;
InsStack(ORD(pMethods), 0, bytesToInsert);
END;
{$IFC fTrcClascal}
WriteLn('******* Allocated ', numNeeded:3, ' method entries at ', mAllocAddr:5, '********');
{$ENDC}
END;
FUNCTION RAllocate(bytesPerRec, numNow, numToGrowBy, numRoomFor, maxNumAllowed: INTEGER;
whutzits: TS8; ordPArray: LONGINT): INTEGER;
{** NO VAR PARAMETERS ALLOWED THAT ARE REFERENCED AFTER CALLING InsStack **}
{bytesPerRec must be even; this function returns the new numRoomFor value}
VAR bytesToInsert: INTEGER;
BEGIN
IF (numRoomFor + numToGrowBy) > maxNumAllowed THEN
numToGrowBy := maxNumAllowed - numRoomFor;
IF numToGrowBy <= 0 THEN
{$IFC fDbgClascal}
CLABreak(CONCAT('Too many ', whutzits), maxNumAllowed);
{$ELSEC}
CLAFail(0);
{$ENDC}
bytesToInsert := bytesPerRec * numToGrowBy;
InsStack(ordPArray, bytesPerRec * numNow, bytesToInsert);
RAllocate := numRoomFor + numToGrowBy;
END;
CLAFail(0)
ELSE
BEGIN
numAliases := numAliases + 1;
TPA8(addr)^ := classAlias;
LookupAlias := numAliases;
END;
END;
PROCEDURE QUnitAuthor(VAR companyAndAuthor: TA32);
BEGIN
IF classesInitialized THEN
CLAFail(0);
authorOfUnit := LookupAuthor(companyAndAuthor);
END;
PROCEDURE QClassAuthor(VAR companyAndAuthor: TA32);
BEGIN
{Must call procedures before the WITH because Lookups might move pClasses^}
IF classesInitialized THEN
CLAFail(0);
pClasses^[numClasses].companyAndAuthor := LookupAuthor(companyAndAuthor);
END;
PROCEDURE QClassAlias(VAR classAlias: TA8);
BEGIN
{Must call procedures before the WITH because Lookups might move pClasses^}
IF classesInitialized THEN
CLAFail(0);
pClasses^[numClasses].classAlias := LookupAlias(classAlias);
END;
PROCEDURE QClassVersion(itsVersion, oldestItCanRead: TByte);
BEGIN
IF classesInitialized THEN
CLAFail(0);
WITH pClasses^[numClasses] DO
BEGIN
version := itsVersion;
oldestReadableVersion := oldestItCanRead;
END;
END;
FUNCTION NumSlices(classIndex: INTEGER): INTEGER;
VAR n: INTEGER;
BEGIN
n := 0;
WHILE classIndex > 0 DO
BEGIN
classIndex := pClasses^[classIndex].superIndex;
n := n + 2;
END;
NumSlices := n;
END;
FUNCTION CallCallPC: LONGINT;
VAR dummy:
INTEGER;
{ must be first local and two bytes long }
BEGIN
CallCallPC := TPLint(TPLint(TPLint(ORD(@dummy) + 2)^)^ + 4)^;
{caller's caller's return address}
END;
FUNCTION CallPC: LONGINT;
VAR dummy:
INTEGER;
{ must be first local and two bytes long }
BEGIN
CallPC := TPLint(TPLint(ORD(@dummy) + 2)^ + 4)^;
{caller's return address}
END;
PROCEDURE SetCallPC(pc: LONGINT);
VAR dummy:
INTEGER;
{ must be first local and two bytes long }
addrOfPC:
LONGINT;
BEGIN
addrOfPC := TPLint(ORD(@dummy) + 2)^ + 4;
TPLint(addrOfPC)^ := pc;
{caller's return address}
END;
FUNCTION LookupInHashArray(tblSize: INTEGER; hashKey: LONGINT; toInsert: BOOLEAN;
FUNCTION Compare(index: INTEGER): THashCompare): INTEGER;
{toInsert, return: -index if entry already there, index (>0) if a hole found}
{not toInsert, return: index (> 0) if entry found, -index if not there}
{return 0 if table is full}
VAR probe:
INTEGER;
origProbe:
INTEGER;
hashCompare:
THashCompare;
BEGIN
{This could be made faster -- and probably should be}
LookupInHashArray := 0;
probe := hashKey;
probe := (ABS(probe) MOD tblSize) + 1;
origProbe := probe;
REPEAT
END;
hashCompare := Compare(probe);
IF hashCompare <> cMismatch THEN
BEGIN
IF toInsert = (hashCompare = cHole) THEN
LookupInHashArray := probe
ELSE
LookupInHashArray := - probe;
EXIT(LookupInHashArray);
END;
probe := probe + 1;
IF probe > tblSize THEN
probe := 1;
UNTIL probe = origProbe;
{$IFC fTrcClascal}
PROCEDURE DumpArrays;
VAR index:
INTEGER;
itsSTP:
TPSliceTable;
slices:
INTEGER;
s:
TS8;
j:
INTEGER;
i:
INTEGER;
level:
INTEGER;
methArrPtr:
TPMethodArray;
numAtThatLevel: INTEGER;
BEGIN
WriteLn;
WriteLn(' *************** ARRAYS *************** ');
WriteLn;
FOR index := 1 TO numClasses DO
BEGIN
Write('Class Index = ', index:3);
itsSTP := pSTables^[index];
Write(' Class Pointer = ', ORD(itsSTP):10);
slices := NumSlices(index);
Write(' Number of slices = ', slices:3);
s[0] := CHAR(8);
FOR j := 1 TO 8 DO
s[j] := pClasses^[index].classAlpha[j];
WriteLn(' Name = ', s);
i := index;
FOR level := slices - 1 DOWNTO 0 DO
BEGIN
Write('
Level ', level:1);
Write('
Index ', i:2);
methArrPtr := itsSTP^[level];
Write(' Method array ptr = ', ORD(methArrPtr):10);
numAtThatLevel := TPWords(pSTables^[i])^[ORD(ODD(level))-2];
Write(' numAtThatLevel ', numAtThatLevel:2);
IF methArrPtr = NIL THEN
WriteLn(', ... all Abstract')
ELSE
BEGIN
WriteLn;
FOR j := 1 TO numAtThatLevel DO
WriteLn(j:10, ORD(methArrPtr^[j]):10);
END;
END;
{$ENDC}
BEGIN
{Install Default Finished procedure}
pFinishedProc := @DefaultFinished;
{Initialize global interface variables}
pleaseInitClascal := TRUE;
classesInitialized := FALSE;
pClasses := @classes;
pSTables := @sTables;
pAuthors := @authors;
pAliases := @aliases;
pMethods := @methads;
{methads spelled funny because METHODS is a reserved word}
{NOTE: pMethods^[] is never written; the "ARRAY" can be > 32K bytes if necessary}
limClasses
limAuthors
limAliases
limMethods
:=
:=
:=
:=
minClasses;
minAuthors;
minAliases;
minMethods;
numClasses
numAuthors
numAliases
numMethods
:=
:=
:=
:=
0;
0;
0;
0;
{incremented by
{never modified
{never modified
{incremented by
%_Class}
in this unit; UOBJECT manages them}
in this unit; UOBJECT manages them}
FillArraysFrom, called by %_Class}
:= @hashName;
:= @hashUnit;
authorOfUnit := 0;
mAllocAddr := ORD(pMethods) + limMethods * 4;
biggestAbstractClass := 1;
currCallCallPC := 0;
p%_Class
:= @%_Class;
pJmp%_Class := GetPJmp%_Class;
{We can never return because we need our locals around during the unit initializations and need
the method tables around forever}
%_JmpTo(CallPC);
END;
PROCEDURE EndPreviousUnit; {We don't require companyAndAuthor--but client could do so at the end of %_Pgm2}
VAR i: INTEGER;
BEGIN
IF authorOfUnit <> 0 THEN
FOR i := oldNumClasses + 1 TO numClasses DO
WITH pClasses^[i] DO
IF companyAndAuthor = 0 THEN
companyAndAuthor := authorOfUnit;
authorOfUnit := 0;
oldNumClasses := numClasses;
END;
PROCEDURE %_Pgm2;
{** NO VAR PARAMETERS ALLOWED THAT ARE REFERENCED AFTER CALLING MAllocate **}
VAR dummy:
LONGINT; {MUST BE FIRST VAR AND 4 BYTES LONG!!!}
pAbstracts:
TPMethodArray;
index:
INTEGER;
extraLongs:
LONGINT;
itsSTP:
TPSliceTable;
slices:
INTEGER;
level:
INTEGER;
objSize:
INTEGER;
pInt:
TPInt;
pLint:
TPLint;
BEGIN
EndPreviousUnit;
{For any slice that was fully abstract, we will make it point at a special block of @_Abstract}
pAbstracts := TPMethodArray(MAllocate(biggestAbstractClass, 16));
numMethods := numMethods + biggestAbstractClass;
FOR index := 1 TO biggestAbstractClass DO
pAbstracts^[index] := ORD(@ _Abstract);
{Assure sufficient room for names}
dictBase := mAllocAddr + (numMethods * 4);
=
=
=
=
=
=
=
=
',
',
',
',
',
',
',
',
biggestAbstractClass:6);
numMethods:6);
firstPackedName:6);
extraLongs:6);
mAllocAddr:6);
dictBase:6);
ORD(pClasses):6);
ORD(pSTables):6);
{Search back from call to %_PGM2 for a MOVE.L A7, xxxx(A5) (opcode $2B4F); if found, calculate the
address that contains the saved A7 and stuff in mAllocAddr instead. Stop searching if we
find a LINK A5, xxxx instruction.}
pLint := Pointer(Ord(@dummy) + 8); {pLint^ should be our return address}
pInt := Pointer(pLint^);
WHILE (pInt^ <> $2B4F {MOVE.L A7, xxxx(A5)}) AND (pInt^ <> $4E55 {LINK A5, xxxx}) DO
pInt := Pointer(Ord(pInt) - 2);
IF pInt^ = $2B4F THEN
BEGIN
pInt := Pointer(Ord(pInt) + 2);
pLint := Pointer(pInt^ + %_GetA5);
pLint^ := mAllocAddr;
END;
{Final initialization of each class in turn}
FOR index := 1 TO numClasses DO
BEGIN
{Fill in missing slices}
itsSTP := pSTables^[index];
slices := NumSlices(index);
FOR level := 0 TO slices - 1 DO
IF itsSTP^[level] = NIL THEN
itsSTP^[level] := pAbstracts;
{Copy the name to the method table area}
StoreCn(index, pClasses^[index].classAlpha);
{The class index is recorded in the slice table, bytes 0 and 4 (high and low order bytes)}
{The object size is recorded in the slice table, bytes 8 and 12, unless there are only two slices,}
{..in which case the long before the slice table has a -1 in the even word and the object size
in the odd word, instead of a superlink}
objSize := pClasses^[index].objectSize;
IF slices > 2 THEN
BEGIN
TPOctets(itsSTP)^[8] := TPOctets(@objSize)^[0];
TPOctets(itsSTP)^[12] := TPOctets(@objSize)^[1];
itsSTP^[-1] := TPMethodArray(pSTables^[pClasses^[index].superIndex]);
END
ELSE
BEGIN
TPWords(itsSTP)^[-2] := -1;
TPWords(itsSTP)^[-1] := objSize;
END;
TPOctets(itsSTP)^[0] := TPOctets(@index)^[0];
TPOctets(itsSTP)^[4] := TPOctets(@index)^[1];
END;
{Report success to higher levels and let it copy the tables it may desire before we destroy them}
CallFinishedProc(DefaultFinishedProc, 0);
pClasses
:= NIL;
pSTables
:= NIL;
pAuthors
:= NIL;
pAliases
:= NIL;
pMethods
:= NIL;
{Just to keep things clean and consistent}
pHashName
:= NIL;
pHashUnit
:= NIL;
{Disable UnitAuthor, ClassAuthor, ClassVersion, ClassSize, and FinishedProc}
classesInitialized := TRUE;
{Exit from %_Pgm1, finally freeing its local storage below the TMethodArray}
%_ExitPoppingTo(mAllocAddr);
END;
{Each unit ends with:
.PROC unit#i
JSR %_Unit
; Defined below
JSR unit#x
; for every unit USEd by the unit within $CLASSES+ (in order USEd)...
...
JSR unit#z
JSR class-init#1 ; for every class implemented in unit#i...
...
JSR class-init#k
RTS
}
PROCEDURE %_Unit;
VAR unitPC:
hashUNIndex:
LONGINT;
INTEGER;
{$IFC fTrcClascal}
DumpArrays;
{$ENDC}
{*************************************************************************}
FillArraysFrom := pc;
END;
{The class-init routine of TFoo = SUBCLASS OF TSuperclass starts with:
JSR %_Class('TFOO
', 'TSUPERCL', @sliceTable, sizeOfEvenSlice, sizeOfOddSlice, objSize); Defined below
JSR method#1(sliceNumber*256 + methodNumber)
; for every method in the IMPLEMENTATION
...
; these calls are not executed: %_Class interprets them
JSR method#r(sliceNumber*256 + methodNumber)
; slice 0 is TObject, method 1 is first method
JSR %_Class
; just a terminator (The first call on %_Class interprets through here)}
PROCEDURE %_Class(itsClassName, itsSuperName: TS8; itsSTP: TPSliceTable;
itsEvenMethods, itsOddMethods, itsObjSize: INTEGER);
{** NO VAR PARAMETERS ALLOWED THAT ARE REFERENCED AFTER CALLING RAllocate & FillArraysFrom **}
VAR i:
INTEGER;
itsAlpha:
TA8;
superAlpha:
TA8;
nameHashIndex:
INTEGER;
superClIndex:
INTEGER;
superSTP:
TPSliceTable;
itsLevelNumber:
INTEGER;
pc:
LONGINT;
level:
INTEGER;
BEGIN
{First class of a unit?}
IF CallCallPC <> currCallCallPC THEN
BEGIN
EndPreviousUnit;
currCallCallPC := CallCallPC;
END;
{Increment numClasses but first be sure there is room in the arrays... this could move ALL the arrays!}
IF numClasses > (limClasses - 2) THEN
BEGIN
i {dummy} := RAllocate(SIZEOF(TClassInfo), numClasses,
growClasses, limClasses, maxClasses, 'Classes', ORD(pClasses));
limClasses := RAllocate(SIZEOF(TPSliceTable), numClasses,
growClasses, limClasses, maxClasses, 'Classes', ORD(pSTables));
END;
numClasses := numClasses + 1;
{Convert names from TS8 to TA8 type}
FOR i := 1 TO 8 DO
BEGIN
itsAlpha[i] := itsClassName[i];
superAlpha[i] := itsSuperName[i];
END;
{Enter this class into the name hash table}
nameHashIndex := LookupClassAlpha(itsAlpha, TRUE);
{Temporary variable needed because stack may quake}
IF nameHashIndex > 0 THEN
pHashName^[nameHashIndex] := numClasses
ELSE
{$IFC fDbgClascal}
IF nameHashIndex < 0 THEN
CLABreak('Class name appeared twice', numClasses)
ELSE
CLABreak('Class Name Hash table full', maxClasses);
{$ELSEC}
CLAFail(0);
{$ENDC}
{Hash the name of the superclass}
IF itsSuperName = 'NIL
' THEN
BEGIN
{This class has no superclass (e.g., TObject)}
superClIndex := 0;
itsLevelNumber := 0;
superSTP := NIL;
END
ELSE
BEGIN
superClIndex := pHashName^[LookupClassAlpha(superAlpha, FALSE)];
itsLevelNumber := NumSlices(superClIndex);
superSTP := pSTables^[superClIndex];
END;
{Fill this slice table with NILs for the moment}
FOR level := 0 TO itsLevelNumber + 1 DO
itsSTP^[level] := NIL;
{To be referenced from FillArraysFrom to calculate numAtThatLevel}
TPWords(itsSTP)^[-2] := itsEvenMethods;
TPWords(itsSTP)^[-1] := itsOddMethods;
{Initialize the fields of the class record}
WITH pClasses^[numClasses] DO
BEGIN
classAlpha := itsAlpha;
superIndex := superClIndex;
objectSize := itsObjSize;
{may be changed by a call on ClassSize from the class-init block}
classAlias := 0;
{may be supplied by a call on ClassAuthor from the class-init block}
companyAndAuthor := 0;
version := 1;
oldestReadableVersion := 1;
END;
{UNIT UABC}
{Copyright 1983, 1984, Apple Computer, Inc.}
{ *** METHODS NEED TO BE GROUPED INTO RIGHT CATEGORIES *** }
{ *** ADD reserve IN ALMOST EVERY CLASS ***}
{
{
{
{
UABC2.TEXT
UABC3.TEXT
UABC4.TEXT
UABC5.TEXT
TProcess-TDocDirectory-TDocManager-TClipboard-TCommand-TCutCopyCommand-TPasteCommand}
TImage-TView-TPaginatedView-TPageView-TPrintManager-THeading-TSelection}
TWindow-TDialogBox-TMenuBar-TFont}
TPanel-TBand-TPane-TMarginPad-TBodyPad-TScroller-TScrollBar}
UNIT UABC;
{$SETC IsIntrinsic := TRUE }
{$IFC IsIntrinsic}
INTRINSIC;
{$ENDC}
INTERFACE
USES
{$U UnitStd
} UnitStd,
{Client should not USE UnitStd}
{$U UnitHz
} UnitHz,
{Client should not USE UnitHz and MUST NOT USE Storage}
{$U libtk/UObject
} UObject,
{Client must USE UObject}
{$U -#BOOT-SysCall} SysCall,
{Client may USE SysCall}
{$IFC LibraryVersion > 20}
{$U LIBTK/Passwd} Passwd,
{$ENDC}
{$IFC LibraryVersion <= 20}
{$U FontMgr
} FontMgr,
{Client should USE UFont instead of FontMgr before QuickDraw}
{$ENDC}
{$U QuickDraw
} QuickDraw,
{Client must USE QuickDraw (unless we provide a type-stub for it)}
{$IFC LibraryVersion > 20}
{$U FontMgr
} FontMgr,
{Client should USE UFont instead of FontMgr after QuickDraw}
{$ENDC}
{$U libtk/UDraw
} UDraw,
{Client must USE UDraw}
{$U PMDecl
} PMDecl,
{$IFC libraryVersion <= 20}
{$U PrStd
} PrStd,
{$ENDC}
{$U WM.Events
} Events,
{$U WM.Folders } Folders,
{$U WM.Menus
} Menus,
{$U AlertMgr
} AlertMgr,
{$IFC LibraryVersion <= 20}
{$U PrProcs
} PrProcs,
{$ENDC}
{$U WMLstd
} WMLstd,
{$U WMLCrs
} WMLCrs,
{$U WMLSb
} WMLSb,
{$U WMLGrow
} WMLGrow,
{$U Scrap
} Scrap,
{$IFC libraryVersion <= 20}
{$U PrMgrUtil
} PrMgrUtil,
{$U PrMgr
} PrMgr,
{$ELSEC}
{$U PrStdInfo}
PrStdInfo,
{$U PrPublic}
PrPublic,
{$ENDC}
{$U FilerComm
} FilerComm;
{$SETC fDbgABC
{$SETC fRngABC
{$SETC fSymABC
{ S P R I N G }
:= fDbgOK}{FALSE}
:= fDbgOK}{FALSE}
:= fSymOK}{FALSE}
{$SETC fDebugMethods := fDbgABC} {if VAR also true, trace entries and/or exits}
CONST
maxMenus
maxFonts
maxSegments
maxSegSize
abortChunkSize
=
=
=
=
=
31;
{unfortunate, but menus must be in non-relocatable storage, & this is easiest}
11;
6;
$20000; {128K}
32768; {32k}
= 9;
= 6;
{amount the mouse must move from anchor before drag starts, unless}
{
TSelection.GetHysteresis is overridden}
noCursor
hiddenCursor
arrowCursor
crossCursor
= -2;
= -1;
= 1;
= 9;
{
{icrsHidden
{icrsInactive
{icrsLCCross
textCursor
checkCursor
smCrossCursor
fingerCursor
=
=
=
=
10;
12;
13;
14;
firstUserCursor = 100;
{icrsXIBeam
{icrsCheck
{icrsGECross
{icrsLFinger
nothingKind
= 0;
noCmdNumber
= 0;
docLdsn
docDsBytes
docExcess
= 3;
= 5120;
= 2048;
printLdsn
ascArwDown
ascArwLeft
ascArwRight
ascArwUp
ascBackspace
ascClear
ascEnter
ascReturn
ascTab
=
=
=
=
=
=
=
=
=
=
2;
$1F;
$1C;
$1D;
$1E;
$08;
$1B;
$03;
$0D;
$09;
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
9;
10;
11;
21;
22;
23;
24;
25;
26;
27;
28;
29;
30;
31;
32;
33;
34;
35;
36;
phOlderVersion
phNewerVersion
phConverting
phAborting
=
=
=
=
37;
38;
39;
40;
phPage
phTitle
= 41; {+SW+}
= 42; {+SW+}
phCantSave
phCantRevert
= 43;
= 44;
phCountry
= 45;
{Selection kinds}
phTooManyChars = 101;
phOddEven = 102;
phOddOnly = 103;
phEvenOnly = 104;
phOddOrEven = 105;
phMinPage = 106;
phMaxPage = 107;
phPageAlignment = 108;
phAlignment = 109;
phTopLeft = 110;
phTopCenter = 111;
phTopRight = 112;
phBotLeft = 113;
phBotCenter = 114;
phBotRight = 115;
phLaunchHeading = 116;
phPageMargins = 117;
phUnits = 118;
phInches = 119;
phCentimeters = 120;
phLeft = 121;
phLeftCluster = 122;
phTop = 123;
phTopCluster = 124;
{Phrases}
phRight = 125;
phRightCluster = 126;
phBottom = 127;
phBotCluster = 128;
phInstallMargins = 129;
phInchTitle= 130;
phCmTitle = 131;
phNewHeading = 132; {+SW+}
phOK = 142;
phCancel = 143;
{client should NOT lightly change the phrases for these, since they are used for}
{determining text and locations of OK/Cancel buttons for built-in ToolKit dialogs}
=
=
=
=
=
=
=
=
=
4201;
4202;
4203;
4304;
4305;
4306;
4307;
4308;
4309;
erWrongPassword = 4310;
erMaxToolKit
= 4499;
{command codes must be between 101 and 999}
uSetAllAside
uSetAside
uPutAway
uPrFmt
uPrintAsIs
uPrint
uPrMonitor
uSaveVersion
uRevertVersion
utSetAside
uSetClipAside
=
=
=
=
=
=
=
=
=
=
=
101;
102;
103;
104;
111;
105;
106;
107;
108;
109;
110;
{Typing Buzzword}
uTyping
= 150;
{The toolkit uses
uBackspace
=
uEnter
=
uForwardSpace
=
uReturn
=
uTab
=
uCopy
uCut
uPaste
uSelAll
uUndoLast
utUndoLast
utRedoLast
uClear
201;
202;
203;
204;
205;
206;
207;
208;
=
=
=
=
=
=
=
=
uFnt0
uFnt1
uFnt2
uFnt3
uFnt4
uFnt5
uFnt6
uFnt7
uFnt8
uFnt9
uFnt10
uFnt11
{$ENDC}
uModern
uClassic
=
=
=
=
=
=
=
=
=
=
=
=
u20Pitch
u15Pitch
u12Pitch
u10Pitch
u12Point
u14Point
u18Point
u24Point
=
=
=
=
=
=
=
=
330
330
330
330
330
330
330
330
uPlain
uBold
uItalic
uUnderline
uShadow
uOutline
uSuperscript
uSubscript
=
=
=
=
=
=
=
=
351;
352;
353;
354;
355;
356;
357;
358;
uPrvwMargins
uPrvwBreaks
uPrvwOff
uDesignPages
=
=
=
=
401;
402;
403;
405;
uShowFullSize
uReduce70Pct
uReduceToFit
= 406;
= 407;
= 408;
uSetHorzBreak
uSetVertBreak
uClearBreaks
= 411;
= 412;
= 413;
uRiseVertically
300;
301;
302;
303;
304;
305;
306;
307;
308;
309;
310;
311;
+
+
+
+
+
+
+
+
size20Pitch
size15Pitch
size12Pitch
size10Pitch
size12Point
size14Point
size18Point
size24Point
sizeMin;
sizeMin;
sizeMin;
sizeMin;
sizeMin;
sizeMin;
sizeMin;
sizeMin;
= 421;
uRiseHorizontally = 422;
uAddColumnStrip
uAddRowStrip
= 431;
= 432;
uReportEvents
= 501;
uCountHeap
= 506;
uCheckIndices
uDumpGlobals
uDumpPrelude
uExperimenting
uReptGarbage
uFreeGarbage
=
=
=
=
=
=
uMainScramble
uDocScramble
= 515;
= 516;
509;
510;
511;
512;
513;
514;
uEditDialog
= 521;
uStopEditDialog = 522;
{ the standard WantMenu will return FALSE for any menus with menuID >= mBuzzword;
buzzword menus should be assigned IDs >= 100;
debug menus should be assigned IDs 90-99 }
{$IFC fDbgABC}
mBuzzword
{$ELSEC}
mBuzzword
{$ENDC}
= 100;
=
90;
mnuClipFilePrint = 1000;
firstPrivateEvent = 100; {first event type that you can use in TProcess.SendEvent}
{$IFC NOT fDbgABC}
fExperimenting =
{$ENDC}
FALSE;
TYPE
TPrinterMetrics = RECORD
paperRect:
Rect;
{the physical rectangle}
printRect:
Rect;
{the printable rectangle}
res:
Point;
{resolution, spots/inch}
reserve:
ARRAY[0..7] OF BYTE;
END;
TAlertArg = 1..5;
TAlertCounter = 7..9;
TAlignment = (aLeft, aRight, aCenter, aJustify);
TPageAlignment = (aTopLeft, aTopCenter, aTopRight, aBottomLeft, aBottomCenter, aBottomRight);
TClickState =
RECORD
where: Point;
when: LONGINT;
clickCount: INTEGER;
fShift, fOption, fApple: BOOLEAN;
END;
TCmdNumber = INTEGER;
TCmdPhase = (doPhase, undoPhase, redoPhase);{doPhase first time, then undoPhase & redoPhase alternately}
TCursorNumber = INTEGER;
TEnumIcons = (iSkewer, iScrollBack, iFlipBack, iGrayA, iThumb, iGrayB, iFlipFwd, iScrollFwd); {TIcon}
TMousePhase = (mPress, mMove, mRelease);
TRevelation = (revealNone, revealSome, revealAll);
TPrReserve = ARRAY [0..127] OF Byte;
{lengthened}
TPrelude =
RECORD
password:
{2} INTEGER;
version:
{2} INTEGER;
{*** Should also do ABC version protection***}
country:
{2} INTEGER;
language:
{2} INTEGER;
preludeSize:
{2} INTEGER;
{SIZEOF(TPrelude), which precedes the heap}
unused:
{6} ARRAY [0..5] OF Byte;
{The above fields should occupy 16 bytes to meet the Lisa standard}
printPref:
{128} TPrReserve;
docSize:
{4} LONGINT;
{sum of the sizes of the consecutive data segments}
numSegments:
{2} INTEGER;
{no. of segments; all but the last are maxSegSize bytes}
docDirectory:
{4} TDocDirectory;
{Other fields may be added later}
END;
TPPrelude = ^TPrelude;
TSBoxID = LONGINT; {THSb alias}
TWindowID = LONGINT; {WindowPtr alias}
TWmgrCmd =
RECORD
cmdNumber:
menuIndex:
itemIndex:
END;
INTEGER;
Byte;
Byte;
{Cursor Tracking}
PROCEDURE {TProcess.}ChangeCursor(cursorNumber: TCursorNumber);
{ applications call ChangeCursor if they want to change the cursor shape }
PROCEDURE {TProcess.}DoCursorChange(cursorNumber: TCursorNumber);
{ applications implement DoCursorChange to test cursorNumber for one of their
cursor shapes; if found, it calls QuickDraw's SetCursor routine, otherwise
it calls the generic TProcess.DoCursorChange }
PROCEDURE {TProcess.}TrackCursor;
{Error Reporting}
PROCEDURE {TProcess.}ArgAlert(whichArg: TAlertArg; argText: S255); {whichArg = 1 to 5}
FUNCTION {TProcess.}Ask(phraseNumber: INTEGER): INTEGER;
PROCEDURE {TProcess.}BeginWait(phraseNumber: INTEGER);
FUNCTION {TProcess.}Caution(phraseNumber: INTEGER): BOOLEAN;
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
FUNCTION
PROCEDURE
{Initiate/Terminate}
PROCEDURE {TProcess.}Commence(phraseVersion: INTEGER); {process init after the process object exists}
PROCEDURE {TProcess.}Complete(allIsWell: BOOLEAN);
{Abort Handling}
FUNCTION {TProcess.}AbortRequest: BOOLEAN;
PROCEDURE {TProcess.}AbortXferSequential(whichWay: xReadWrite; pFirst: Ptr;
numBytes, chunkSize: LONGINT; fs: TFileScanner);
{Main Loop}
PROCEDURE {TProcess.}ObeyEvents(FUNCTION StopCondition: BOOLEAN);
{This will return IF: (1) amDying is TRUE (application terminated)
or (2) StopCondition returns TRUE (StopCondition is checked
only when no events are available, before starting to idle.)}
PROCEDURE {TProcess.}ObeyFilerEvent;
PROCEDURE {TProcess.}ObeyTheEvent;
PROCEDURE {TProcess.}Run;
{Private Events (Inter-process communication)}
PROCEDURE {TProcess.}HandlePrivateEvent(typeOfEvent: INTEGER; fromProcess: LONGINT;
when: LONGINT; otherData: LONGINT); DEFAULT;
PROCEDURE {TProcess.}SendEvent(typeOfEvent: INTEGER; targetProcess: LONGINT; otherData: LONGINT);
{Memory Management}
PROCEDURE {TProcess.}BindCurrentDocument;
{Open/Close Window/Document}
FUNCTION {TProcess.}NewDocManager(volumePrefix: TFilePath; openAsTool: BOOLEAN)
: TDocManager; DEFAULT;
{External Document Support}
PROCEDURE {TProcess.}CopyExternalDoc(VAR error: INTEGER;
externalName, volumePrefix: TFilePath); DEFAULT;
{This is called if the application puts icons into the clipboard and the user
then pastes them into a folder or disk.}
END;
TWindow;
TClassWorld;
{Creation/Destruction}
FUNCTION {TDocDirectory.}CREATE(object: TObject; heap: THeap; itsWindow: TWindow;
itsClassWorld: TClassWorld): TDocDirectory;
{Version Conversion}
PROCEDURE {TDocDirectory.}Adopt;
END;
TDocManager = SUBCLASS OF TObject
{Variables}
files:
RECORD
volumePrefix:
volume:
{$IFC LibraryVersion > 20}
password:
{$ENDC}
saveExists:
shouldSuspend:
shouldToolSave:
END;
dataSegment:
RECORD
refnum:
preludePtr:
changes:
END;
docHeap:
window:
pendingNote:
openedAsTool:
TFilePath;
TFilePath;
TPassword;
BOOLEAN;
BOOLEAN;
BOOLEAN;
{Creation/Destruction}
FUNCTION {TDocManager.}CREATE(object: TObject; heap: THeap; itsPathPrefix: TFilePath): TDocManager;
{Debugging}
{$IFC fDbgABC}
PROCEDURE {TDocManager.}DumpPrelude;
{$ENDC}
{Attributes}
FUNCTION {TDocManager.}WindowWithId(wmgrID: TWindowID): TWindow;
{Process Termination}
PROCEDURE {TDocManager.}Complete(allIsWell: BOOLEAN);
{Open/Close Window}
FUNCTION {TDocManager.}NewWindow(heap: THeap; wmgrID: TWindowID): TWindow; DEFAULT;
{Files}
PROCEDURE {TDocManager.}Close(afterSuspend: BOOLEAN);
{ CloseFiles is for the application to override if it has any of its own files that must be
closed }
PROCEDURE {TDocManager.}CloseFiles;
PROCEDURE {TDocManager.}Open(VAR error: INTEGER; wmgrID: TWindowID; VAR OpenedSuspended:Boolean);
PROCEDURE {TDocManager.}OpenBlank(VAR error: INTEGER; wmgrID: TWindowID);
PROCEDURE {TDocManager.}OpenSaved(VAR error: INTEGER; wmgrID: TWindowID);
PROCEDURE {TDocManager.}OpenSuspended(VAR error: INTEGER; wmgrID: TWindowID);
PROCEDURE {TDocManager.}RevertVersion(VAR error: INTEGER; wmgrID: TWindowID);
PROCEDURE {TDocManager.}SaveVersion(VAR error: INTEGER; volumePrefix: TFilePath;
andContinue: BOOLEAN);
PROCEDURE {TDocManager.}Suspend(VAR error: INTEGER);
{Data Segment}
PROCEDURE {TDocManager.}Assimilate(VAR error: INTEGER);
PROCEDURE {TDocManager.}Bind; DEFAULT;
PROCEDURE {TDocManager.}ConserveMemory(maxExcess: LONGINT; fGC: BOOLEAN);
{if fGC is TRUE also do a garbage collect -- on debugging versions,
we just report garbage, on non-debugging versions we free it
also.}
PROCEDURE {TDocManager.}Deactivate;
FUNCTION {TDocManager.}DfltHeapSize: LONGINT;
PROCEDURE {TDocManager.}ExpandMemory(bytesNeeded: LONGINT);
PROCEDURE {TDocManager.}KillSegments(first, last: INTEGER);
PROCEDURE {TDocManager.}MakeSegments(VAR error: INTEGER; oldSegments: INTEGER; newDocSize: LONGINT);
PROCEDURE {TDocManager.}ResumeAfterOpen(VAR error: INTEGER; wmgrID: TWindowID);
PROCEDURE {TDocManager.}SetSegSize(VAR error: INTEGER; minSize, maxExcess: LONGINT);
PROCEDURE {TDocManager.}Unbind; DEFAULT;
END;
TClipboard = SUBCLASS OF TDocManager
{Variables}
hasView:
hasPicture:
hasUniversalText:
BOOLEAN;
BOOLEAN;
BOOLEAN;
hasIcon:
BOOLEAN;
{****NOTE: The only way into or out of
cuttingTool:
LONGINT;
cuttingProcessID:
LONGINT;
clipCopy:
TFileScanner;
{Creation/Destruction}
FUNCTION {TClipboard.}CREATE(object: TObject; heap: THeap): TClipboard;
{Editing}
PROCEDURE {TClipboard.}AboutToCut;
PROCEDURE {TClipboard.}BeginCut;
PROCEDURE {TClipboard.}EndCut;
{Undo}
PROCEDURE {TClipboard.}CommitCut;
FUNCTION {TClipboard.}UndoCut: BOOLEAN; {return TRUE if succeeds}
{Identification}
PROCEDURE {TClipboard.}Inspect;
PROCEDURE {TClipboard.}Publicize;
{Data Segment}
{PROCEDURE TClipboard. Bind;}
{PROCEDURE TClipboard. Unbind;}
END;
TCommand = SUBCLASS OF TObject
{Variables}
cmdNumber:
TCmdNumber;
{the command number of the menu item that describes the command;
usually the same one the user chose, but not necessarily}
image:
TImage;
{If non-NIL, affects filtering by image.EachVirtualPart}
undoable:
BOOLEAN;
{TRUE iff this command is undoable}
doing:
BOOLEAN;
{TRUE if Performing or just did doPhase or redoPhase}
revelation:
TRevelation;
{revealNone/Some/All of selection before performing command}
unHiliteBefore: ARRAY [TCmdPhase] OF BOOLEAN; {TRUE -> Toolkit unhilites all selections before
perform}
hiliteAfter:
ARRAY [TCmdPhase] OF BOOLEAN; {TRUE -> Toolkit hilites all selections after perform}
{Creation/Destruction}
FUNCTION {TCommand.}CREATE(object: TObject; heap: THeap; itsCmdNumber: TCmdNumber;
itsImage: TImage; isUndoable: BOOLEAN; itsRevelation: TRevelation): TCommand;
{Filtering}
{commit a command}
{do, undo, or redo a command}
END;
TCutCopyCommand = SUBCLASS OF TCommand
{Variables}
isCut: BOOLEAN;
{Creation/Destruction}
FUNCTION {TCutCopyCommand.}CREATE(object: TObject; heap: THeap; itsCmdNumber: TCmdNumber;
itsImage: TImage; isCutCmd: BOOLEAN): TCutCopyCommand;
{Command Execution}
{PROCEDURE TCutCopyCommand. Commit;}
PROCEDURE {TCutCopyCommand.}DoCutCopy(clipSelection: TSelection; deleteOriginal: BOOLEAN;
cmdPhase: TCmdPhase); DEFAULT;
{the clipboard is already set up; you only have to load data into it in doPhase}
{PROCEDURE TCutCopyCommand. Perform(cmdPhase: TCmdPhase);}
END;
TPasteCommand = SUBCLASS OF TCommand
{Creation/Destruction}
FUNCTION {TPasteCommand.}CREATE(object: TObject; heap: THeap; itsCmdNumber: TCmdNumber;
itsImage: TImage): TPasteCommand;
{Command Execution}
PROCEDURE {TPasteCommand.}DoPaste(clipSelection: TSelection; pic: PicHandle;
cmdPhase: TCmdPhase); DEFAULT;
{the clipboard is already set up, except in undoPhase sel & pic are NIL}
{PROCEDURE TPasteCommand. Perform(cmdPhase: TCmdPhase);}
END;
TImage = SUBCLASS OF TObject
{Variables}
extentLRect:
LRect;
view:
allowMouseOutside:
{methods}
FUNCTION
FUNCTION
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
FUNCTION
PROCEDURE
FUNCTION
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
FUNCTION
TView;
BOOLEAN;
END;
TView = SUBCLASS OF TImage
{Variables}
panel:
clickLPt:
printManager:
res:
TPanel;
LPoint;
TPrintManager;
Point;
screenPad:
TPad;
{like noPad, but scales from view coords to screen coords if view
resolution and screen resolution differ
*** CAUTION -- Only for mapping coordinates-- DO NOT try to
Focus this pad or do Invals, etx ***}
fitPagesPerfectly:
BOOLEAN;
isPrintable:
isMainView:
BOOLEAN;
BOOLEAN;
stdScroll:
scrollPastEnd:
LPoint;
Point;
{Creation/Destruction}
FUNCTION {TView.}CREATE(object: TObject; heap: THeap; itsPanel: TPanel; itsExtent: LRect;
itsPrintManager: TPrintManager; itsDfltMargins: LRect; itsFitPagesPerfectly:BOOLEAN;
itsRes: Point; isMainView: BOOLEAN): TView;
{PROCEDURE TView. Free;}
{Attributes}
PROCEDURE {TView.}BeInPanel(panel: TPanel);
PROCEDURE {TView.}GetStdScroll(VAR deltaLStd: LPoint);
FUNCTION {TView.}MaxPageToPrint: LONGINT;
{Pagination}
PROCEDURE {TView.}AddStripOfPages(vhs: VHSelect); DEFAULT;
FUNCTION {TView.}ForceBreakAt(vhs: VHSelect; precedingLocation: LONGINT;
proposedLocation: LONGINT): LONGINT;
PROCEDURE {TView.}RedoBreaks; DEFAULT;
PROCEDURE {TView.}RemapManualBreaks(
FUNCTION NewBreakLocation(vhs: VHSelect; oldBreak: LONGINT): LONGINT);
{Cross-Panel Drag}
FUNCTION {TView.}DoReceive(selection: TSelection; lPtInView: LPoint): BOOLEAN;
{Direct Display Permission -- per panel}
FUNCTION {TView.}OKToDrawIn(lRectInView: LRect): BOOLEAN;
{Variables}
unpaginatedView:
pageSize:
TView;
ARRAY[VHSelect] OF LONGINT;
workingInMargins:
BOOLEAN;
{Creation/Destruction}
FUNCTION {TPaginatedView.}CREATE(object: TObject; heap: THeap;
itsUnpaginatedView: TView): TPaginatedView;
{PROCEDURE
PROCEDURE
{FUNCTION
PROCEDURE
PROCEDURE
{PROCEDURE
{PROCEDURE
PROCEDURE
{PROCEDURE
{PROCEDURE
END;
TPageView = SUBCLASS OF TView
FUNCTION
{a header/footer image}
TPrintManager;
TPageAlignment;
LPoint;
BOOLEAN;
BOOLEAN;
LONGINT;
LONGINT;
{Creation/Destruction}
FUNCTION {THeading.}CREATE(object: TObject; heap: THeap; itsPrintManager: TPrintManager;
itsExtentLRect: LRect; itsPageAlignment: TPageAlignment;
itsOffsetFromAlignment: LPoint): THeading;
{Attributes}
PROCEDURE {THeading.}ChangePageAlignment(newPageAlignment: TPageAlignment);
{Selective Use}
FUNCTION {THeading.}ShouldDraw(pageNumber: LONGINT): BOOLEAN;
FUNCTION {THeading.}ShouldFrame: BOOLEAN; DEFAULT;
{Display}
PROCEDURE {THeading.}AdjustForPage(pageNumber: LONGINT; editing: BOOLEAN); DEFAULT;
PROCEDURE {THeading.}LocateOnPage(editing: BOOLEAN);
{PROCEDURE THeading. Draw;}
END;
TPrintManager = SUBCLASS OF TObject
view:
TView;
pageView:
TView;
breaks:
pageMargins:
LRect;
headings:
canEditPages:
layoutDialogBox:
BOOLEAN;
TDialogBox;
frameBody:
paperLRect:
printableLRect:
BOOLEAN;
LRect;
LRect;
contentLRect:
LRect;
printerMetrics:
TPrinterMetrics;
{in view resolution; top and left are > 0 , bot & right < 0}
pageRiseDirection: VHSelect;
{if 'h', it means that page numbers rise from left to right fastest;
if 'v', it means that page numbers rise from top to bottom fastest;
default value is 'h'}
FUNCTION
{TPrintManager.}AddStripOfPages(vhs: VHSelect);
{TPrintManager.}ChangeMargins(margins: LRect);
{TPrintManager.}ClearPageBreaks(automatic: BOOLEAN);
{TPrintManager.}DrawBreaks(manualOnly: BOOLEAN);
{TPrintManager.}DrawOneBreak(pageBreak: LONGINT; vhs: vhSelect);
{TPrintManager.}DrawPage;
{TPrintManager.}EnterPageEditing;
{TPrintManager.}GetPageLimits(pageNumber: LONGINT; VAR viewLRect: LRect);
{TPrintManager.}NewPaginatedView(object: TObject): TPaginatedView;
{TPrintManager.}NewPageView(object: TObject): TView;
{TPrintManager.}PageWith(VAR lPtInView: LPoint; VAR strip: Point): LONGINT;
{TPrintManager.}Print(printPref: TPrReserve);
{TPrintManager.}ReactToPrinterChange;
{TPrintManager.}RedoBreaks;
{TPrintManager.}SetBreak(vhs: VHSelect; where: LONGINT; isAutomatic: BOOLEAN);
{TPrintManager.}SetDfltHeadings; DEFAULT;
{TPrintManager.}SkipPage(pageNumber: LONGINT);
TWindow;
TPanel;
TView;
INTEGER;
LPoint;
LPoint;
LRect;
TSelection;
BOOLEAN;
{Creation/Destruction}
FUNCTION {TSelection.}CREATE(object: TObject; heap: THeap; itsView: TView; itsKind: INTEGER;
itsAnchorLPt: LPoint): TSelection;
{FUNCTION
TSelection. Clone(heap: THeap): TObject;}
{clones coSelection}
FUNCTION {TSelection.}FreedAndReplacedBy(selection: TSelection): TSelection;
{Attributes}
PROCEDURE {TSelection.}GetHysteresis(VAR hysterPt: Point); DEFAULT; {rtns a delta from orig panel pt}
PROCEDURE {TSelection.}HaveView(view: TView);
{Files}
{Command Dispatch}
FUNCTION {TSelection.}CanDoCommand(cmdNumber: TCmdNumber; VAR checkIt: BOOLEAN): BOOLEAN; DEFAULT;
PROCEDURE {TSelection.}CantDoCmd(cmdNumber: TCmdNumber); DEFAULT;
PROCEDURE {TSelection.}CantDoIt; DEFAULT;
PROCEDURE {TSelection.}DoKey(ascii: CHAR; keycap: Byte; shiftKey, appleKey, optionKey: BOOLEAN);
FUNCTION {TSelection.}NewCommand(cmdNumber: TCmdNumber): TCommand; DEFAULT;
PROCEDURE {TSelection.}PerformCommand(command: TCommand; cmdPhase: TCmdPhase); DEFAULT;
{Idle}
PROCEDURE {TSelection.}IdleBegin(centiSeconds: LONGINT); DEFAULT;
PROCEDURE {TSelection.}IdleContinue(centiSeconds: LONGINT); DEFAULT;
PROCEDURE {TSelection.}IdleEnd(centiSeconds: LONGINT); DEFAULT;
{Editing -PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
to be overridden by applications}
{TSelection.}KeyBack(fWord: BOOLEAN); DEFAULT;
{TSelection.}KeyChar(ch: CHAR); DEFAULT;
{TSelection.}KeyClear; DEFAULT;
{TSelection.}KeyEnter(dh, dv: INTEGER); DEFAULT;
{TSelection.}KeyForward(fWord: BOOLEAN); DEFAULT;
{TSelection.}KeyPause; DEFAULT; {Pause in typing}
{TSelection.}KeyReturn; DEFAULT;
{TSelection.}KeyTab(fBackward: BOOLEAN); DEFAULT;
{TSelection.}SelectParagraphs;
{TSelection.}DeSelect; DEFAULT;
{TSelection.}DrawGhost; DEFAULT;
{TSelection.}MousePress(mouseLPt: LPoint); DEFAULT;
{TSelection.}MouseMove(mouseLPt: LPoint); DEFAULT;
{TSelection.}MouseRelease; DEFAULT;
{TSelection.}MoveBackToAnchor; DEFAULT;
{called when cross-panel drag has been refused}
{Undo Maintenance}
PROCEDURE {TSelection.}Restore; DEFAULT;
PROCEDURE {TSelection.}Save; DEFAULT;
{Scroll into view}
PROCEDURE {TSelection.}Reveal(asMuchAsPossible: BOOLEAN); DEFAULT;
END;
TWindow = SUBCLASS OF TArea
{Variables}
panels:
panelTree:
dialogBox:
selectPanel:
undoSelPanel:
clickPanel:
undoClickPanel:
selectWindow:
undoSelWindow:
wmgrID:
isResizable:
believeWmgr:
TWindow;
TWindowID;
BOOLEAN;
BOOLEAN;
maxInnerSize:
Point;
changes:
lastCmd:
printerMetrics:
pgSzOK:
LONGINT;
TCommand;
TPrinterMetrics;
BOOLEAN;
pgRgOK:
BOOLEAN;
panelToPrint:
TPanel;
objectToFree:
TObject;
{Creation/Destruction}
FUNCTION {TWindow.}CREATE(object: TObject; heap: THeap; itsWmgrID: TWindowID; itsResizability
: BOOLEAN): TWindow;
{PROCEDURE TWindow. Free;}
{$IFC fDbgABC}
{Debugging}
PROCEDURE {TWindow.}ToggleFlag(VAR flag: BOOLEAN); DEFAULT; {Toggle a debug flag in a menu}
{$ENDC}
{Attributes}
{PROCEDURE TWindow. GetMinExtent(VAR minExtent: Point; windowIsResizingIt: BOOLEAN);}
PROCEDURE {TWindow.}GetTitle(VAR title: S255); {Get the window title}
FUNCTION {TWindow.}IsActive: BOOLEAN;
FUNCTION {TWindow.}IsVisible: BOOLEAN;
PROCEDURE {TWindow.}SetWmgrId(itsWmgrId: TWindowID); {Also sets port fields of panes}
{Buttoning}
PROCEDURE {TWindow.}DownEventAt(mousePt: Point); DEFAULT;
{FUNCTION
TWindow. DownAt(mousePt: Point): BOOLEAN;}
{Dialog Box affairs}
PROCEDURE {TWindow.}PutUpDialogBox(dialogBox: TDialogBox); DEFAULT;
PROCEDURE {TWindow.}TakeDownDialogBox; DEFAULT;
{Display}
{PROCEDURE TWindow. Focus;}
{PROCEDURE TWindow. Frame;}
PROCEDURE {TWindow.}Highlight(highTransit: THighTransit); DEFAULT;
{PROCEDURE TWindow. Refresh(rActions: TActions; highTransit: THighTransit);}
PROCEDURE {TWindow.}Update(doHilite: BOOLEAN); DEFAULT;
{Resizing}
PROCEDURE {TWindow.}DownInSizeBox(mousePt: Point); DEFAULT;
PROCEDURE {TWindow.}Resize(moving: BOOLEAN); DEFAULT; {Reset size from portRect size (w. adjustments)}
PROCEDURE {TWindow.}ResizeTo(newSize: Point); DEFAULT; {callable from application}
{Command Dispatch and Menus}
FUNCTION {TWindow.}CanDoCommand(cmdNumber: TCmdNumber; VAR checkIt: BOOLEAN): BOOLEAN; DEFAULT;
FUNCTION {TWindow.}CanDoStdCommand(cmdNumber: TCmdNumber; VAR checkIt: BOOLEAN): BOOLEAN; DEFAULT;
PROCEDURE {TWindow.}CommitLast; DEFAULT;
PROCEDURE {TWindow.}DoCommand(cmdNumber: TCmdNumber); DEFAULT;
PROCEDURE {TWindow.}LoadMenuBar; DEFAULT;
PROCEDURE {TWindow.}MenuEventAt(mousePt: Point); DEFAULT;
FUNCTION {TWindow.}NewCommand(cmdNumber: TCmdNumber): TCommand; DEFAULT;
FUNCTION {TWindow.}NewStdCommand(cmdNumber: TCmdNumber): TCommand;
PROCEDURE {TWindow.}PerformCommand(newCommand: TCommand);
PROCEDURE {TWindow.}PerformLast(cmdPhase: TCmdPhase);
PROCEDURE {TWindow.}SaveCommand(command: TCommand); {NOTE: do not use the arg after calling this;
use window.lastCmd instead}
PROCEDURE {TWindow.}SetupMenus;
PROCEDURE {TWindow.}UndoLast;
FUNCTION {TWindow.}WantMenu(menuID: INTEGER; inClipboard: BOOLEAN): BOOLEAN;
{Miscellaneous}
PROCEDURE {TWindow.}AbortEvent; {only QuickPort should override this}
{Selection Maintenance during commands}
PROCEDURE {TWindow.}RestoreSelection;
PROCEDURE {TWindow.}RevealSelection(asMuchAsPossible, doHilite: BOOLEAN);
PROCEDURE {TWindow.}SaveSelection;
{Desktop}
{The following 2 methods assume that we are focused on the window before they are called}
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
{TWindow.}Activate;
{TWindow.}Deactivate;
{TWindow.}BlankStationery; DEFAULT;
{TWindow.}StashPicture(highTransit: THighTransit);
{$ENDC}
{Foci of Attention}
FUNCTION {TWindow.}CursorFeedback: TCursorNumber;
PROCEDURE {TWindow.}PickStdCursor;
{Printing}
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
{Filtering}
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
{Idle}
PROCEDURE {TWindow.}IdleBegin(centiSeconds: LONGINT);
PROCEDURE {TWindow.}IdleContinue(centiSeconds: LONGINT);
PROCEDURE {TWindow.}IdleEnd(centiSeconds: LONGINT);
END;
TDialogBox = SUBCLASS OF TWindow
{Variables}
keyResponse:
menuResponse:
downInMainWindowResponse:
freeOnDismissal:
TDiResponse;
TDiResponse;
TDiResponse;
BOOLEAN;
{Creation/Destruction}
FUNCTION {TDialogBox.}CREATE(object: TObject; heap: THeap; itsResizability: BOOLEAN;
itsHeight: INTEGER; itsKeyResponse, itsMenuResponse,
itsDownInMainWindowResponse: TDiResponse): TDialogBox;
{Attributes}
{PROCEDURE TDialogBox. GetMinExtent(VAR minExtent: Point; windowIsResizingIt: BOOLEAN);}
{Display}
PROCEDURE {TDialogBox.}Appear;
PROCEDURE {TDialogBox.}BeDismissed; DEFAULT;
PROCEDURE {TDialogBox.}Disappear; DEFAULT;
END;
TBand = SUBCLASS OF TArea
{Variables}
window:
panes:
panel:
scroller:
scrollDir:
TWindow;
TList {OF TPane};
TPanel;
TScroller;
VHSelect;
{Creation/Destruction}
FUNCTION {TBand.}CREATE(object: TObject; heap: THeap; itsPanel: TPanel; itsInnerRect: Rect;
itsScroller: TScroller; itsDir: VHSelect): TBand;
{PROCEDURE TBand. Free;}
{Attributes}
FUNCTION {TBand.}ViewLCd: LONGINT;
{Scrolling}
PROCEDURE {TBand.}OffsetPanes(deltaLPt: LPoint);
PROCEDURE {TBand.}ScrollBy(deltaLCd: LONGINT);
{A TBand can only scroll in one direction; this also moves the thumb}
PROCEDURE {TBand.}ScrollStep(icon: TEnumIcons; deltaLStd: LONGINT);
PROCEDURE {TBand.}ScrollTo(viewLCd: LONGINT);
{Attributes}
FUNCTION {TSideBand.}CoBand: TBand;
{returns the band adjacent to SELF}
END;
TPanel = SUBCLASS OF TArea
{Variables}
window:
panes:
currentView:
view:
paginatedView:
selection:
undoSelection:
bands:
scrollBars:
abilities:
minInnerDiagonal:
resizeBranch:
zoomed:
zoomFactor:
previewMode:
lastClick:
{panes
TWindow;
TList {OF TPane};
TView;
TView;
TPaginatedView;
TSelection;
TSelection;
ARRAY[VHSelect] OF TList;
ARRAY[VHSelect] OF TScrollBar;
ARRAY[VHSelect] OF TAbilities;
Point;
TBranchArea;
BOOLEAN;
TScaler;
TPreviewMode;
RECORD
CASE gotPane: BOOLEAN OF
TRUE: (clickPane: TPane);
FALSE: (clickPt: Point);
END;
contentRect:
Rect;
{part of the innerRect not containing side bands}
tlSideBandSize:
Point; {size of topLeft side bands}
brSideBandSize:
Point;
{NOTE: The sideband sizes refer to the size of the innerRect of the side band;
therefore a size of -1 means there is no side band on that side}
deletedSplits:
TArray; {If NIL, don't remember splits that go away because the panel
shrinks. Otherwise, this should be a TArray with recordBytes
2. This is initialized to NIL in TPanel.CREATE; clients can
allocate an array and change the field if they desire.}
{Creation/Destruction}
FUNCTION {TPanel.}CREATE(object: TObject; heap: THeap; itsWindow: TWindow;
minHeight, minWidth: INTEGER; itsVAbilities, itsHAbilities: TAbilities): TPanel;
{PROCEDURE TPanel. Free;}
PROCEDURE {TPanel.}HaveView(view: TView);
FUNCTION {TPanel.}NewView(object: TObject; itsExtent: LRect; itsPrintManager: TPrintManager;
itsDfltMargins: LRect; itsFitPerfectlyOnPages: BOOLEAN): TView;
FUNCTION {TPanel.}NewStatusView(object: TObject; itsExtent: LRect): TView;
{Attributes}
PROCEDURE {TPanel.}ComputeContentRect;
PROCEDURE {TPanel.}DecideAboutBars(newOuterRect: Rect); {Decide if to have scroll bars & resize icon}
{PROCEDURE TPanel. GetMinExtent(VAR minExtent: Point; windowIsResizingIt: BOOLEAN);}
{PROCEDURE TPanel. GetBorder(VAR border: Rect);}
FUNCTION {TPanel.}FindBranchThatIsResized: TBranchArea;
FUNCTION {TPanel.}PaneShowing(anLRect: LRect): TPane; {Returns first pane showing an part
of anLRect, else NIL}
PROCEDURE {TPanel.}SetInnerRect(newInnerRect: Rect); OVERRIDE;
PROCEDURE {TPanel.}SetOuterRect(newOuterRect: Rect); OVERRIDE;
{Paneling the window}
FUNCTION {TPanel.}Divide(vhs: VHSelect;
fromEdgeOfPanel: INTEGER; units: TUnitsFromEdge;
whoCanResizeIt: TResizability;
minSize: INTEGER; itsVAbilities, itsHAbilities: TAbilities): TPanel;
PROCEDURE {TPanel.}Insert(panel: TPanel; vhs: VHSelect;
fromEdgeOfPanel: INTEGER; units: TUnitsFromEdge;
whoCanResizeIt: TResizability);
{Resizes both to share my space}
PROCEDURE {TPanel.}Remove;
{Does not Free SELF; Expands sibling to fill my space}
PROCEDURE {TPanel.}Replace(panel: TPanel); {Does not Free SELF; Resizes panel to fit my old space}
{Buttoning}
{FUNCTION
TPanel. DownAt(mousePt: Point): BOOLEAN;}
PROCEDURE {TPanel.}DownInSizeBox(mousePt: Point);
PROCEDURE {TPanel.}HitScroller(vhs: VHSelect; mousePt: Point; scroller: TScroller; icon: TEnumIcons);
(*
{Selecting}
PROCEDURE {TPanel.}BeginSelection;
PROCEDURE {TPanel.}BeSelectPanel(inSelectWindow: BOOLEAN);
FUNCTION {TPanel.}NoSelection: TSelection; *)
{Cursor tracking}
FUNCTION {TPanel.}CursorAt(mousePt: Point): TCursorNumber;
{Display}
{PROCEDURE TPanel. Frame;}
PROCEDURE {TPanel.}Highlight(selection: TSelection; highTransit: THighTransit);
{ this highlights the selection on all pads }
PROCEDURE {TPanel.}Invalidate;
{ this invalidates the whole panel }
PROCEDURE {TPanel.}InvalLRect(lRectInView: LRect);
{ this invalidates the given LRect on all pads }
FUNCTION {TPanel.}OKToDrawIn(lRectInView: LRect): BOOLEAN;
{ If this returns FALSE, commands must InvalLRect or XOR, not Draw or Erase }
PROCEDURE {TPanel.}OnAllPadsDo(PROCEDURE DoOnThePad);
{PROCEDURE TPanel. Refresh(rActions: TActions; highTransit: THighTransit);}
PROCEDURE {TPanel.}Rescroll;
PROCEDURE {TPanel.}SetZoomFactor(zoomNumerator, zoomDenominator: Point);
{Page-Previewing}
PROCEDURE {TPanel.}Preview(newMode: TPreviewMode);
{Printing}
PROCEDURE {TPanel.}PrintView(printPref: TPrReserve);
{Scrolling}
PROCEDURE {TPanel.}AutoScroll(mousePt: Point);
PROCEDURE {TPanel.}DoScrolling(inArea: TArea; itsPane: TPane;
hOk, vOk: BOOLEAN; VAR deltaLPt: LPoint);
{inArea must be a TBand or a TPane; if a TPane then inArea=itsPane;
if a TBand then itsPane is any one of the band's panes}
FUNCTION {TPanel.}PaneToScroll(VAR anLRect: LRect; hMinToSee, vMinToSee: INTEGER): TPane;
{Returns the pane to scroll for showing the minimum desired part ofLRect;
if that part is already showing, it returns NIL;
NOTE: anLRect is NOT changed}
PROCEDURE {TPanel.}RevealLRect(VAR anLRect: LRect; hMinToSee, vMinToSee: INTEGER);
{Show at least the desired part of the LRect in the pane returned by PaneToShow;
NOTE: anLRect is NOT changed}
{Splitting}
PROCEDURE {TPanel.}CleanUpPanes(deleteList: TList);
PROCEDURE {TPanel.}MakeBand(vhs: VHSelect; scroller, prevScroller: TScroller);
PROCEDURE {TPanel.}MoveSplitBefore(scroller: TScroller; newSkwrCd: INTEGER);
FUNCTION
FUNCTION
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
{Side Bands}
PROCEDURE {TPanel.}ShowSideBand(vhs: VHSelect; topOrLeft: BOOLEAN; size: INTEGER; viewLCd: LONGINT);
PROCEDURE {TPanel.}SideBandRect(vhs: VHSelect; topOrLeft: BOOLEAN; VAR bandRect: Rect);
{returns the innerRect of the side band, given SELF.contentRect}
{Resizing}
PROCEDURE {TPanel.}ResizeBand(vhs: VHSelect; band: TBand; newViewLCd: LONGINT;
fInvalidate: BOOLEAN);
{PROCEDURE TPanel. ResizeInside(newInnerRect: Rect);}
{PROCEDURE TPanel. ResizeOutside(newOuterRect: Rect);}
END;
TPane = SUBCLASS OF TPad
{Variables}
currentView:
panel:
TView;
TPanel;
{Creation/Destruction}
FUNCTION {TPane.}CREATE(object: TObject; heap: THeap; itsPanel: TPanel; itsInnerRect: Rect;
itsViewedLRect: LRect): TPane;
PROCEDURE {TPane.}HaveView(view: TView);
{Attributes}
PROCEDURE {TPane.}GetScrollLimits(VAR viewedLRect, scrollableLRect: LRect);
{PROCEDURE TPane. SetZoomFactor(zoomNumerator, zoomDenominator: Point);}
{Selecting}
PROCEDURE {TPane.}MouseTrack(mPhase: TMousePhase; mousePt: Point);
{assumes mousePt is in the pane's innerRect}
{Cursor tracking}
FUNCTION {TPane.}CursorAt(mousePt: Point): TCursorNumber;
{Display}
{PROCEDURE
{Resizing}
TView;
{The view seen on the BODY of this page}
LONGINT;
TBodyPad;
{Creation/Destruction}
FUNCTION {TMarginPad.}CREATE(object: TObject; heap: THeap): TMarginPad;
PROCEDURE {TMarginPad.}Rework(itsView: TView; itsOrigin: Point; itsRes: Point;
itsPageNumber: LONGINT; itsZoomFactor: TScaler; itsPort: GrafPtr);
PROCEDURE {TMarginPad.}SetForPage(itsPageNumber: LONGINT; itsOrigin: Point);
{Display}
{PROCEDURE
TMarginPad. Focus;}
{PROCEDURE
TBodyPad. Focus;}
END;
TScroller = SUBCLASS OF TObject
{Variables}
scrollBar:
band:
sBoxID:
TScrollBar;
TBand;
TSBoxID;
{Creation/Destruction}
FUNCTION {TScroller.}CREATE(object: TObject; heap: THeap; itsScrollBar: TScrollBar; itsId: TSBoxID)
: TScroller;
{PROCEDURE TScroller. Free;}
{Attributes}
PROCEDURE {TScroller.}GetSize(VAR boxRect: Rect);
FUNCTION {TScroller.}ScrollDir: VHSelect;
PROCEDURE {TScroller.}SetSize(ownerRect: Rect);
FUNCTION {TScroller.}ThumbRange: INTEGER;
{Buttoning}
PROCEDURE {TScroller.}TrackSkewer(mousePt: Point; VAR newSkwrCd: INTEGER;
VAR scroller, prevScroller: TScroller);
PROCEDURE {TScroller.}TrackThumb(mousePt: Point; VAR oldThumbPos, newThumbPos: INTEGER);
{Display}
PROCEDURE {TScroller.}FillIcon(icon: TEnumIcons; fBlack: BOOLEAN);
PROCEDURE {TScroller.}MoveThumb(newThumbPos: INTEGER);
{Splitting}
PROCEDURE {TScroller.}ResplitAt(newSkwrCd: INTEGER; prevScroller: TScroller);
PROCEDURE {TScroller.}SplitAt(newSkwrCd: INTEGER; VAR nextScroller: TScroller);
END;
TScrollBar = SUBCLASS OF TObject
{Variables}
firstBox:
isVisible:
TScroller;
BOOLEAN;
{Creation/Destruction}
FUNCTION {TScrollBar.}CREATE(object: TObject; heap: THeap; vhs: VHSelect; outerRect: Rect;
itsVisibility: BOOLEAN): TScrollBar;
{Creation/Destruction}
FUNCTION {TMenuBar.}CREATE(object: TObject; heap: THeap; itsScanner: TFileScanner): TMenuBar;
{Attributes}
PROCEDURE {TMenuBar.}Check(cmdNumber: TCmdNumber; checked: BOOLEAN);
PROCEDURE {TMenuBar.}Enable(cmdNumber: TCmdNumber; canBeChosen: BOOLEAN);
PROCEDURE {TMenuBar.}BuildCmdName(destCmd, templateCmd: TCmdNumber; param: TPString);
{if param is NIL, use the default}
FUNCTION {TMenuBar.}GetCmdName(cmdNumber: TCmdNumber; pName: TPString): BOOLEAN;
{returns TRUE iff cmdNumber is found (pName will be empty);
pName can be NIL, which will save the overhead of returning the
menu item, for case where you just want to see if it exists}
PROCEDURE {TMenuBar.}PutCmdName(cmdNumber: TCmdNumber; pName: TPString);
{Buttoning}
FUNCTION {TMenuBar.}CmdKey(ch: CHAR): TCmdNumber;
FUNCTION {TMenuBar.}DownAt(mousePt: Point): TCmdNumber;
{Display}
PROCEDURE {TMenuBar.}Draw;
PROCEDURE {TMenuBar.}EndCmd;
PROCEDURE {TMenuBar.}HighlightMenu(withCmd: TCmdNumber);
{call this when the user presses the CLEAR key for example, to highlight
the appropriate menu title; you should then call window.DoCommand with
an apropriate command number.}
{Loading}
INTEGER;
{Creation/Destruction}
FUNCTION {TFont.}CREATE(object: TObject; heap: THeap; itsFamily: INTEGER): TFont;
{$ENDC}
END;
TWindowID;
BOOLEAN;
PenState;
LONGINT;
LONGINT;
TClipboard;
TDocManager;
STRING[20];
TClickState;
TClipboard;
TPrReserve;
BOOLEAN;
TDocManager;
TTypeStyle;
INTEGER;
TDocManager;
currentWindow:
cursorShape:
deferUpdate:
dfltNewHeading:
docList:
eventTime:
TWindow;
TCursorNumber;
BOOLEAN;
STRING[20]; {+SW+}
TList {OF TDocManager};
LONGINT;
eventType:
INTEGER;
{The type number of the most recent WM event}
{$IFC fDbgABC}
fExperimenting:
BOOLEAN;
{IF TRUE, enable zoom experimentation etc.}
fCountHeap:
BOOLEAN;
{Iff TRUE and IFC fCheckHeap, count objects once per cmd}
{$ENDC}
{$IFC LibraryVersion <= 20 AND FALSE} {do it this way in case we need it back for the Pepsi version}
fonts:
ARRAY [0..maxFonts] OF TFont;
{$ENDC}
genClipPic:
BOOLEAN;
{Iff TRUE, we are generating the Clipboard picture}
highLevel:
ARRAY [BOOLEAN] OF THighTransit;
{TRUE=>hOffToOn, FALSE=>hOffToDim}
highToggle:
ARRAY [BOOLEAN] OF THighTransit;
{TRUE=>hOffToOn, FALSE=>hOnToOff}
idleTime:
LONGINT;
{The time we finished processing the last user input}
inBackground:
BOOLEAN;
{Iff TRUE, currently running in background}
limboPen:
PenState;
{pen to use to fill limbo area in paginated view}
manualBreakPen:
PenState;
{pen to use to draw manual page breaks}
marginPattern:
LPattern;
{pattern to use to fill margins in paginated view}
menuBar:
TMenuBar;
{The menus of the application and the Clipboard}
myProcessID:
LONGINT;
{The OS ID of this process}
myTool:
LONGINT;
{The tool number of this tool}
normalPen:
PenState;
{pen state resulting from PenNormal}
okString:
STRING[20];
{The word "OK" for use in buttons}
phraseFile:
TFileScanner;
{The Main Phrase File TFileScanner}
process:
TProcess;
{The process object of this process}
screenRightEdge:
scrollRgn:
stdMargins:
suspendSuffix:
theBodyPad:
theMarginPad:
toolName:
toolPrefix:
toolVolume:
varPage:
varTitle:
wordDelimiters:
INTEGER;
{720 for Lisa 1.0 screen}
RgnHandle;
{what needs to be refreshed because of scroll}
LRect;
{standard page-margins, in screen pixels}
ARRAY [1..maxSegments] OF STRING[3];
TBodyPad;
{current BodyPad being written to}
TMarginPad;
{current MarginPad being written to}
STRING[67];
{The name of the tool}
TFilePath;
(*The prefix '{Tnn}' of the OS path name of the tool*)
TFilePath;
{The volume '-name-' on which the tool resides}
STRING[20]; {+SW+}
{The string 'PAGE', for use in heading variables}
STRING[20]; {+SW+}
{The string 'TITLE' for use in heading variables}
STRING[67];
{The delimiters of a Lisa "word" in this language}
PROCEDURE PicGrpEnd;
{ end of series }
PROCEDURE InitProcess;
FUNCTION GetTime: LONGINT;
{This function returns the same "time" as is used in events (see global variable eventTime),
and in the idle loop}
IMPLEMENTATION
{$I LIBTK/UABC2.TEXT}
{$I LIBTK/UABC3.TEXT}
{$I LIBTK/UABC4.TEXT}
{$I LIBTK/UABC5.TEXT}
(**********
{$I UABC2.TEXT}
{$I UABC3.TEXT}
{$I UABC4.TEXT}
{$I UABC5.TEXT}
**********)
{TProcess-TDocDirectory-TDocManager-TClipboard-TCommand-TCutCopyCommandTPasteCommand}
{TImage-TView-TPaginatedView-TPageView-TPrintManager-THeading-TSelection}
{TWindow-TDialogBox-TMenuBar-TFont}
{TPanel-TBand-TPane-TMarginPad-TBodyPad-TScroller-TScrollBar}
{TProcess-TDocDirectory-TDocManager-TClipboard-TCommand-TCutCopyCommand-TPasteCommand}
{TImage-TView-TPaginatedView-TPageView-TPrintManager-THeading-TSelection}
{TWindow-TDialogBox-TMenuBar-TFont}
{TPanel-TBand-TPane-TMarginPad-TBodyPad-TScroller-TScrollBar}
END.
TMapPtr = ^TMapTable;
TMapHandle = ^TMapPtr;
VAR
alerts:
event:
{$IFC fDbgABC}
hadToBindClip:
{$ENDC}
scrRgn1ForDrawHdgs:
scrRgn2ForDrawHdgs:
wmgrMenus:
cSelection:
picData:
TAlertFile;
EventRecord;
{The Alert Manager alert handle for the Main Phrase File}
{The last event received by this process}
BOOLEAN;
RgnHandle;
{Reserved for use dy TPaginatedView.AdornPageOnScreen}
RgnHandle;
{Reserved for use dy TPaginatedView.AdornPageOnScreen}
ARRAY [1..maxMenus] OF MenuInfo;
TClass;
{The TClass of TSelection, used by TPasteCmd.Perform}
TH;
{Pre-allocated handle on MainHeap used for picture
comments}
{$S sStartup}
PROCEDURE GetPrefixPart{(wholeName: S255; VAR filePart: TFilePath)}; (*'{prefix}'*)
(* This works ONLY on Desktop Manager file names of the form '-volname-{prefix}suffix' *)
VAR centerHyphen: INTEGER;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
centerHyphen := Pos('-{', wholeName);
filePart := Copy(wholeName, centerHyphen+1, Pos('}',wholeName) - centerHyphen);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCldInit}
FUNCTION ToolOfFile{(wholeName: S255): LONGINT};
VAR toolNumber: LONGINT;
toolPrefix: TFilePath;
cvResult:
TConvResult;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
GetPrefixPart(wholeName, toolPrefix);
Delete(toolPrefix, 1, 2); (* The '{T' *)
Delete(toolPrefix, Length(toolPrefix), 1); (* The final '}' *)
StrToLInt(@toolPrefix, toolNumber, cvResult);
IF cvResult <> cvValid THEN
ToolOfFile := 0
ELSE
ToolOfFile := toolNumber;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCldInit}
FUNCTION ToolOfProcess{(processId: LONGINT): LONGINT};
VAR prcsInfo:
ProcInfoRec;
error:
INTEGER;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
Info_Process(error, processID, prcsInfo);
IF error > 0 THEN
ToolOfProcess := 0
ELSE
ToolOfProcess := ToolOfFile(prcsInfo.progPathname);
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDbgABC}
{$S SgABCdbg}
PROCEDURE ReportEvent;
VAR winTitle:
Str255;
BEGIN
Write(toolName, ' P=#', myProcessId:1, ' received ');
WITH event DO
BEGIN
CASE what OF
buttonDown:
Write('Button-down');
buttonUp:
Write('Button-up');
folderActivate:
Write('Activate');
folderDeactivate:
Write('Deactivate');
folderMoved:
Write('Window-moved');
folderUpdate:
Write('Update');
keyDown:
Write('Key-press');
filerEvent:
Write('Desktop');
OTHERWISE
Write('Miscellaneous');
END;
Write(' event for the ');
IF who = alertFolder THEN
WriteLn('Alert Box')
ELSE
IF who = dialogFolder THEN
WriteLn('Dialog Box')
ELSE
IF who = scrapFolder THEN
WriteLn('Clipboard')
ELSE
IF who = menuFolder THEN
WriteLn('Menu Bar')
ELSE
BEGIN
GetFldrTitle(who, winTitle);
WriteLn('window titled "', winTitle, '"');
END;
END;
END;
{$S SgABCdbg}
PROCEDURE ReportFilerEvent(flrParams: FilerExt);
BEGIN
Write('
');
WITH flrParams DO
BEGIN
CASE theFlrOp OF
fcClose:
fcCopy:
Write('Close
Write('Copy
');
');
END;
{$ENDC}
fcDfClose:
Write('Doc File Close');
fcNone:
Write('Open Tool
');
fcPut:
Write('Put
');
fcResume:
Write('Open Doc
');
fcShred:
Write('Shred
');
fcSuspend:
Write('Suspend
');
fcTerminate:
Write('Terminate
');
OTHERWISE
Write('Unknown!!!
');
END;
{$IFC LibraryVersion <= 20}
WriteLn(' theErr=', theErr:1, ' theDF=', theDF:1);
WriteLn(' thePrefix="', thePrefix, '"');
{$ELSEC}
WriteLn(' theErr=', theErr:1, ' theOffset=', theOffset:1, '
WriteLn(' thePassword="', thePassword, '"');
WriteLn(' thePrefix="', thePrefix, '"');
WriteLn(' theResult="', theResult, '"');
{$ENDC}
END;
theDF=', theDF:1);
{$S sError}
PROCEDURE AlErrProc;
BEGIN
StopAlert(alerts, 2);
process.Complete(FALSE);
END;
{$S sCldInit}
FUNCTION ExpandHeap(heap: THeap; bytesNeeded: INTEGER): INTEGER;
VAR alias:
RECORD CASE INTEGER OF 1: (address: TPPrelude); 2: (high, low: INTEGER) END;
preludePtr:
TPPrelude;
oldHeapSize:
LONGINT;
newHeapSize:
LONGINT;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
alias.address := POINTER(ORD(heap));
alias.low := 0;
preludePtr := alias.address;
{$IFC fDbgABC}
IF boundDocument.dataSegment.preludePtr <> preludePtr THEN
ABCBreak('boundDocument''s preludePtr <> preludePtr in ExpandHeap', ORD(heap));
{$ENDC}
oldHeapSize := CbOfHz(POINTER(ORD(heap)));
boundDocument.ExpandMemory(bytesNeeded);
WITH boundDocument.dataSegment.preludePtr^ DO
newHeapSize := docSize - preludeSize;
ExpandHeap := newHeapSize - oldHeapSize;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCcld}
PROCEDURE PicTextBegin{(alignment: TAlignment)};
TYPE
TpByte = ^Byte;
ThByte = ^TpByte;
VAR
FEalign:
Byte;
BEGIN
IF genClipPic THEN
BEGIN
FEalign := ORD(alignment) + 1;
IF FEalign > 3 THEN
FEalign := 1; {aLeft}
ThByte(picData)^^ := FEalign; {currently, picData is always a handle to 1 byte}
{$IFC LibraryVersion <= 20}
PicComment(cPicTxtBegin, SIZEOF(FEalign), Handle(picData));
{$ELSEC}
PicComment(cPicTxtBegin, SIZEOF(FEalign), QDHandle(picData));
{$ENDC}
END;
END;
{$S SgABCcld}
PROCEDURE PicTextEnd;
{ end of series }
BEGIN
IF genClipPic THEN
PicComment(cPicTxtEnd, 0, NIL);
END;
{$S SgABCcld}
PROCEDURE PicGrpBegin;
{ beginning of a series of grouped objects }
BEGIN
IF genClipPic THEN
PicComment(cPicGrpBegin, 0, NIL);
END;
{$S SgABCcld}
PROCEDURE PicGrpEnd;
{ end of series }
BEGIN
IF genClipPic THEN
PicComment(cPicGrpEnd, 0, NIL);
END;
{$S sError}
FUNCTION FilerReason(error: INTEGER): FReason;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
FilerReason := allOk;
IF error > 0 THEN
CASE error OF
309, erNoDiskSpace:
FilerReason := noDiskSpace;
306, 311, 315, erNoMemory:
FilerReason := noMemory;
{$IFC LibraryVersion > 20}
1294, erWrongPassword:
FilerReason := wrongPassword;
{$ENDC}
erBadData:
FilerReason := badData;
erPassword, erVersion,
955, 957, 958, erCantRead:
FilerReason := cantRead;
961, 962, erCantWrite:
FilerReason := cantWrite;
erDirtyDoc:
FilerReason := dirtyDoc;
erNoMoreDocs:
FilerReason := noMoreDocs;
erAborted:
FilerReason := aUserAbort;
OTHERWISE
FilerReason := internalError;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCini}
PROCEDURE InitProcess;
CONST
maxNameLen =
TYPE
TDeskLabel
=
63;
RECORD
version:
name:
TPPathName
AbortRequest := FALSE;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCcld}
{ If allowAbort is FALSE, simply calls fs.XferSequential.
Otherwise, transfers in increments of chunksize and sets fs.Error to erAborted IF command period
is pressed during the transfer. Returns with an incomplete transfer IF command period or any other
error occurs during the transfer. }
PROCEDURE {TProcess.}AbortXferSequential{(whichWay: xReadWrite; pFirst: Ptr;
numBytes, chunksize: LONGINT; fs: TFileScanner)};
VAR xferAmount:
LONGINT;
actual:
LONGINT;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF allowAbort THEN
BEGIN
actual := 0;
WHILE (numBytes > 0) AND (fs.error <= 0) AND
NOT (fs.atEnd AND (whichWay = xRead)) DO
BEGIN
IF numbytes > chunksize THEN
xferAmount := chunksize
ELSE
xferAmount := numbytes;
IF process.AbortRequest THEN
fs.error := erAborted
ELSE
BEGIN
fs.XferSequential(whichWay, pFirst, xferAmount);
xferAmount := fs.actual;
{$IFC fDbgABC}
IF (xferAmount <= 0) AND (fs.error <= 0) THEN
ABCbreak('In TProcess.AbortXferSequential, fs.actual <= 0', xferAmount);
{$ENDC}
actual := actual + xferAmount;
numbytes := numBytes - xferAmount;
pFirst := POINTER(ORD(pFirst) + xferAmount);
END;
END;
fs.actual := actual; {make believe we xferred it all at once}
END
ELSE
fs.XferSequential(whichWay, pFirst, numBytes);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sAlert}
PROCEDURE {TProcess.}ArgAlert{(whichArg: TArgAlert; argText: S255)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
ArgAlert(whichArg, argText);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sAlert}
FUNCTION {TProcess.}Ask{(phraseNumber: INTEGER): INTEGER};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
ArgAlert(0, toolName);
{$IFC LibraryVersion > 20}
IF activeWindowID = 0 THEN
Ask := BackgroundAlert(alerts, phraseNumber, AskProc)
ELSE
{$ENDC}
Ask := AskAlert(alerts, phraseNumber);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sAlert}
PROCEDURE {TProcess.}BeginWait{(phraseNumber: INTEGER)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
ArgAlert(0, toolName);
WaitAlert(alerts, phraseNumber);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sStartup}
PROCEDURE {TProcess.}BindCurrentDocument;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF (boundDocument <> currentDocument) AND (boundDocument <> NIL) THEN
boundDocument.Unbind;
error:
prPrfAlias:
str:
convResult:
INTEGER;
TPrPrfAlias;
S255;
TConvResult;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
****)
IF onDesktop THEN
BEGIN
{Initialize Print Manager, while Alert Segment is still Resident}
{$IFC LibraryVersion <= 20}
PrMgrInit(error);
InitErrorAbort(error);
{$ELSEC}
PrMgrInit;
{$ENDC}
END;
{Initialize Scroll Bar and Cursor Library}
InitWmlSb;
InitWmlCrs(error);
InitErrorAbort(error);
{$IFC LibraryVersion <= 20 AND FALSE} {do it this way in case we need it back for the Pepsi version}
{Create fonts}
fonts[ 0] := TFont.CREATE(NIL, mainHeap, sysText);
{System Font
}
fonts[ 1] := TFont.CREATE(NIL, mainHeap, p15Tile);
{15 pitch Gothic }
fonts[ 2] := TFont.CREATE(NIL, mainHeap, p12tile);
{12 pitch Modern }
fonts[ 3] := TFont.CREATE(NIL, mainHeap, elite);
{12 pitch Elite }
fonts[ 4] := TFont.CREATE(NIL, mainHeap, p10tile);
{10 pitch Modern }
fonts[ 5] := TFont.CREATE(NIL, mainHeap, p10cent);
{10 pitch Courier}
fonts[ 6] := TFont.CREATE(NIL, mainHeap, tile12 );
{PS Modern
}
fonts[ 7] := TFont.CREATE(NIL, mainHeap, cent12 );
{PS Executive
}
fonts[ 8] := TFont.CREATE(NIL, mainHeap, tile18 );
{1/4 inch Modern }
fonts[ 9] := TFont.CREATE(NIL, mainHeap, cent18 );
{1/4 inch Classic}
fonts[10] := TFont.CREATE(NIL, mainHeap, tile24 );
{1/3 inch Modern }
fonts[11] := TFont.CREATE(NIL, mainHeap, cent24 );
{1/3 inch Classic}
{$ENDC}
{Specify suspend-file suffixes}
oneChar := '0';
FOR i := 1 TO maxSegments DO
BEGIN
oneChar[1] := CHR(48+i);
suspendSuffix[i] := CONCAT('$S', oneChar);
END;
{Initialize other globals}
SetPt(zeroPt, 0, 0);
SetRect(zeroRect, 0, 0, 0, 0);
SetRect(hugeRect, 0, 0, $3FFF, $3FFF);
SetLPt(zeroLPt, 0, 0);
SetLRect(zeroLRect, 0, 0, 0, 0);
SetLRect(hugeLRect, 0, 0, $3FFFFFFF, $3FFFFFFF);
orthogonal[v] := h;
orthogonal[h] := v;
docList := TList.CREATE(NIL, mainHeap, 1);
highToggle[FALSE] := hOnToOff;
highToggle[TRUE] := hOffToOn;
highLevel[FALSE] := hOffToDim;
highLevel[TRUE] := hOffToOn;
PenNormal;
GetPenState(normalPen);
PenSize(2, 2);
PenMode(patXor);
PenPat(gray);
GetPenState(highPen[hDimToOff]);
GetPenState(highPen[hOffToDim]);
PenMode(notPatXor);
PenPat(gray);
GetPenState(highPen[hOnToDim]);
GetPenState(highPen[hDimToOn]);
PenMode(patXor);
PenPat(black);
GetPenState(highPen[hOffToOn]);
GetPenState(highPen[hOnToOff]);
PenSize(3, 2);
PenMode(patXOr);
PenPat(gray);
GetPenState(autoBreakPen);
StuffHex(@manualPat, 'CC663399CC663399');
PenPat(manualPat);
GetPenState(manualBreakPen);
StuffHex(@marginPattern, '8000000008000000');
PenNormal;
PenPat(manualPat);
GetPenState(limboPen);
SetPt(screenRes, 90, 60); {Lisa 1.0 screen}
{better--get from phrase file}
screenRightEdge := 720; {redundant -- screenBits.bounds.right shd be the same}
SetLRect(stdMargins, screenRes.h, screenRes.v, - screenRes.h, -screenRes.v);
PenNormal;
noPad := TPad.CREATE(NIL, mainHeap, zeroRect, hugeLRect, screenRes, screenRes, NIL);
(***** Do this in TPad creation block, via coercion
noPad.PatToLPat(white, lPatWhite);
noPad.PatToLPat(black, lPatBlack);
noPad.PatToLPat(gray, lPatGray);
noPad.PatToLPat(ltGray, lPatLtGray);
noPad.PatToLPat(dkGray, lPatDkGray);
*****)
MakeTypeStyle(famClassic, size18Point, [], cornerNumberStyle);
theMarginPad := TMarginPad.CREATE(NIL, mainHeap);
theBodyPad := theMarginPad.bodyPad;
IF crashPad = NIL THEN
crashPad := theMarginPad;
clipboard := TClipboard.CREATE(NIL, mainHeap);
padRgn := NewRgn;
focusRgn := thePort^.visRgn;
focusStkPtr := 0;
focusArea := NIL;
genClipPic := FALSE;
amPrinting := FALSE;
useAltVisRgn := FALSE;
altVisRgn := NewRgn;
scrollRgn := NewRgn;
scrRgn1ForDrawHdgs := NewRgn;
scrRgn2ForDrawHdgs := NewRgn;
blinkOnCentiSecs := caretOnTime;
blinkOffCentiSecs := caretOffTime;
PrPrfDefault(prPrfAlias.prPrf);
clipPrintPref := prPrfAlias.reserve;
{ Final check for Abort in init }
InitErrorAbort(0);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCini}
PROCEDURE {TProcess.}Complete{(allIsWell: BOOLEAN)};
VAR s:
TListScanner;
document:
TDocManager;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF NOT (allIsWell OR amDying) THEN
BEGIN
ImDying; {Do this first}
IF (boundClipboard <> NIL) AND (scrapProcess = myProcess) THEN {*** Sufficient & necessary? ***}
BackOutOfScrap;
amDying := TRUE;
END;
{$IFC fDbgABC}
IF NOT allIsWell THEN
ABCBreak('Process.Complete(FALSE)', 0);
{$ENDC}
IF docList <> NIL THEN
BEGIN
s := docList.Scanner;
docList := NIL;
WHILE s.Scan(document) DO
document.Complete(allIsWell);
END;
HALT;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCcld}
PROCEDURE {TProcess.}CopyExternalDoc(VAR error: INTEGER; externalName, volumePrefix: TFilePath);
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
{$IFC fDbgABC}
ABCbreak('TProcess.CopyExternalDoc was not overridden', 0);
{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S sAlert}
PROCEDURE {TProcess.}CountAlert{(whichCtr: TAlertCounter; counter: INTEGER)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
CountAlert(whichCtr, counter);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sStartup}
PROCEDURE {TProcess.}DoCursorChange{(cursorNumber: TCursorNumber)};
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
SetStdCursor(cursorNumber);
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S SgABCini}
PROCEDURE {TProcess.}DontDebug;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
fCheckIndices := FALSE;
{$IFC fDbgABC}
eventDebug := FALSE;
fCountHeap := FALSE;
fExperimenting := FALSE;
{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$ENDC}
{$S sAlert}
PROCEDURE {TProcess.}DrawAlert(phraseNumber: INTEGER; marginLRect: LRect);
VAR rectInWindow:
Rect;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
ArgAlert(0, toolName);
thePad.LRectToRect(marginLRect, rectInWindow);
DrawAlert(alerts, phraseNumber, rectInWindow);
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDbgABC}
{$S SgABCdbg}
PROCEDURE {TProcess.}DumpGlobals;
VAR str: S8;
PROCEDURE AbortDumpVar(pVariable: Ptr; nameAndType: S255);
BEGIN
IF CheckKeyPress('Process global variable dump') THEN
BEGIN
WriteLn;
WriteLn;
Exit(DumpGlobals);
END;
DumpVar(pVariable, nameAndType);
END;
BEGIN
WriteLn;
WriteLn('--- IMPORTANT GLOBAL VARIABLES OF THE PROCESS ---');
WriteLn;
AbortDumpVar(@activeWindowID, 'activeWindowID: Ptr');
AbortDumpVar(@allowAbort, 'allowAbort: BOOLEAN');
AbortDumpVar(@boundClipboard, 'boundClipboard: TClipboard');
AbortDumpVar(@boundDocument, 'boundDocument: TDocManager');
AbortDumpVar(@clickState, Concat('clickState: RECORD where: Point; when: LONGINT;',
'clickCount: INTEGER; fShift: BOOLEAN; fOption: BOOLEAN; fApple: BOOLEAN END'));
AbortDumpVar(@clipboard, 'clipboard: TClipboard');
AbortDumpVar(@closedBySuspend, 'closedBySuspend: BOOLEAN');
AbortDumpVar(@closedDocument, 'closedDocument: TDocManager');
AbortDumpVar(@currentDocument, 'currentDocument: TDocManager');
AbortDumpVar(@currentWindow, 'currentWindow: TWindow');
AbortDumpVar(@cursorShape, 'cursorShape: INTEGER');
AbortDumpVar(@deferUpdate, 'deferUpdate: BOOLEAN');
AbortDumpVar(@docList, 'docList: TList');
AbortDumpVar(@genClipPic, 'genClipPic: BOOLEAN');
AbortDumpVar(@idleTime, 'idleTime: LONGINT');
AbortDumpVar(@inBackground, 'inBackground: BOOLEAN');
AbortDumpVar(@menuBar, 'menuBar: TMenuBar');
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
ArgAlert(0, toolName);
{$IFC LibraryVersion > 20}
IF activeWindowID = 0 THEN
dummy := BackgroundAlert(alerts, phraseNumber, NoteProc)
ELSE
{$ENDC}
NoteAlert(alerts, phraseNumber);
{$IFC fTrace}EP;{$ENDC}
END;
{ NOTE: StopCondition is checked only when no events are available.
NOTE: StopCondition should not assume that a document is bound. If all the process' windows are
inactive, StopCondition will be called before the process is suspended (to give you
a chance to regain control), but all the process' documents will be unbound. You can
check for this situation by testing currentDocument for NIL.}
{$S sStartup}
PROCEDURE {TProcess.}ObeyEvents{(FUNCTION StopCondition: BOOLEAN)};
LABEL 9;
VAR selection:
TSelection;
PROCEDURE StopTest;
BEGIN
IF StopCondition THEN
BEGIN
LetOthersRun;
GOTO 9;
END;
END;
PROCEDURE GetAndObeyEvent;
LABEL
1;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
GetEvent(event);
{$IFC fDbgABC}
IF fExperimenting and eventDebug THEN
WITH event.who^.portRect DO
BEGIN
WriteLn('GetAndObeyEvent (event.who):', ORD(event.who));
WriteLn(left, top, right, bottom);
WriteLn(event.where.h, event.where.v);
END;
{$ENDC}
1:
IF ImActive THEN
IF SELF.AbortRequest THEN
IF event.what IN [keyDown, buttonDown, buttonUp] THEN
GOTO 1;
SELF.ObeyTheEvent;
{$IFC fTrace}EP;{$ENDC}
END;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
{Shouldn't tell Filer initFailed after this}
isInitialized := TRUE;
{Main event loop}
{NOTE: currentWindow <> NIL implies
REPEAT
WHILE NOT (ImActive OR amDying OR (currentWindow <> NIL)) DO
BEGIN
IF NOT EventAvail THEN
StopTest;
GetAndObeyEvent; {may suspend me}
END;
WHILE (ImActive OR (currentWindow <> NIL)) AND NOT amDying DO
IF EventAvail THEN
GetAndObeyEvent
ELSE
BEGIN
StopTest;
currentWindow.Update(TRUE);
IF currentWindow.dialogBox <> NIL THEN
currentWindow.dialogBox.Update(TRUE);
IF NOT (amDying OR eventAvail) THEN
BEGIN
selection := currentWindow.selectWindow.selectPanel.selection;
idleTime := Time;
selection.IdleBegin(idleTime);
WHILE NOT (amDying OR eventAvail) DO
selection.IdleContinue(Time);
IF NOT amDying THEN
selection.IdleEnd(Time);
END;
END;
UNTIL amDying;
9:
{$IFC fTrace}EP;{$ENDC}
END;
{$S sStartup}
PROCEDURE {TProcess.}ObeyFilerEvent;
LABEL 1;
TYPE
{$IFC LibraryVersion <= 20}
TFileOpKind = (fopNone, fopSuspend, fopSaveVersion);
{$ELSEC}
TFileOpKind = (fopNone, fopSuspend, fopSaveVersion, fopCopyDoc);
{$ENDC}
VAR reply:
badReply:
reason:
window:
openAsTool:
document:
flrParams:
flrOp:
volumePrefix:
wasSuspended:
fileOpKind:
doSuspend:
doSave:
error:
FReply;
FReply;
FReason;
TWindow;
BOOLEAN;
TDocManager;
FilerExt;
FilerOp;
TFilePath;
BOOLEAN;
TFileOpKind;
BOOLEAN;
BOOLEAN;
INTEGER;
BEGIN
WriteLn('--------------------');
ReportFilerEvent(flrParams);
ABCbreak('TProcess.ObeyFilerEvent got an error (event listed above)', abortReason);
END;
{$ENDC}
IF (flrOp = fcResume) OR (flrOp = fcNone) THEN
BEGIN
IF window <> NIL THEN
PopFocus;
IF wasSuspended THEN
{ Close but don't kill the datasegs }
BEGIN
FOR i := 1 TO maxSegments DO
IF document.dataSegment.refnum[i] >= 0 THEN
BEGIN
dsPathName := Concat(document.files.volumePrefix, suspendSuffix[i]);
Close_DataSeg(error, document.dataSegment.refnum[i]);
document.dataSegment.refnum[i] := -1;
END
END
ELSE
BEGIN
{ In case the BlankStationery method was called and opened any files }
document.CloseFiles;
{ kill any data segments that were created }
document.KillSegments(1, maxSegments);
END;
{ delete from docList, IF there, and free regardless }
docList.DelObject(document, TRUE);
boundDocument := NIL;
END;
TellFiler(error, badReply, FilerReason(abortReason), event.who);
GOTO 1;
END;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
wasSuspended := FALSE;
GetAddParams(error, event, flrParams);
IF error > 0 THEN
ABCBreak('GetAddParams', error);
flrOp := flrParams.theFlrOp;
allowAbort := TRUE; {??? should we assume this ???}
{$IFC fDbgABC}
{$ENDC}
IF eventDebug THEN
ReportFilerEvent(flrParams);
CASE flrOp OF
fcNone, fcResume:
BEGIN
{ The assumption for aborting here is things will, where possible, be cleaned up along the way
by anyone detecting the abort. Things that have already happened after the abort is
detected will be cleaned up in CheckAbort. The process will of course continue after the
abort. }
IF (inBackground) AND (doclist.size > 0) THEN
TellFiler(error, docClosd, noMoreDocs, event.who)
ELSE
BEGIN
{ Set badReply in case Abort is detected }
badReply := docClosd;
TakeWindow(event.who);
WITH flrParams DO
BEGIN
openAsTool := flrOp = fcNone;
IF openAsTool THEN
thePrefix := CONCAT(toolVolume, toolPrefix);
document := SELF.NewDocManager(thePrefix, openAsTool);
{$IFC LibraryVersion > 20}
document.files.password := thePassword;
{$ENDC}
END;
IF document = NIL THEN {application refused the request}
TellFiler(error, docClosd, noMoreDocs, event.who)
ELSE
BEGIN
document.openedAsTool := openAsTool;
SetPort(event.who); {so things like InvalRect in BlankStationery will work}
{ Returns Abort as error = erAborted }
document.Open(error, ORD(event.who), wasSuspended);
window := NIL; {so CheckAbort will not PopFocus}
CheckAbort(error);
PushFocus;
window := document.window;
window.Focus;
window.Resize(FALSE);
CheckAbort(0);
InvalRect(window.innerRect);
window.Update(TRUE);
CheckAbort(0);
PopFocus;
IF event.who = activeFolder THEN {already active so we don't get a folderActivate}
BEGIN
PushFocus;
window.Focus; {window.Activate assumes focused}
currentDocument := document; {this must be set before calling TWindow.Activate}
window.Activate;
PopFocus;
END
ELSE
window.StashPicture(hOffToDim);
END;
END;
END; {fcNone/fcResume case}
{ The assumption for aborting here is things will be cleaned up along the way by anyone
detecting the abort. The process will of course continue after the abort. }
fcClose, fcSuspend, fcCopy, fcPut, fcShred:
BEGIN
{$IFC LibraryVersion <= 20}
fileOpKind := fopNone;
document := POINTER(GetFldrRefCon(event.who));
document.Bind;
{$ELSEC}
IF (flrOp = fcCopy) AND (Length(flrParams.theResult) > 0) THEN
BEGIN
fileOpKind := fopCopyDoc;
document := NIL;
END
ELSE
BEGIN
fileOpKind := fopNone;
document := POINTER(GetFldrRefCon(event.who));
document.Bind;
END;
{$ENDC}
CASE flrOp OF
fcClose, fcSuspend, fcShred:
BEGIN
IF flrOp = fcClose THEN
BEGIN
IF document.window.changes <> 0 THEN
fileOpKind := fopSaveVersion;
END
ELSE
fileOpKind := fopSuspend;
volumePrefix := document.files.volumePrefix;
reply := docClosd;
badReply := docNotClosd;
END;
OTHERWISE {fcCopy, fcPut}
BEGIN
{$IFC LibraryVersion <= 20}
fileOpKind := fopSaveVersion;
{$ELSEC}
IF fileOpKind <> fopCopyDoc THEN
fileOpKind := fopSaveVersion;
{$ENDC}
volumePrefix := flrParams.thePrefix;
reply := docXfered;
badReply := docNotXfered;
END;
END;
allowAbort := NOT doSuspend; {for now all ops can be aborted except fcSuspend and fcShred}
CheckAbort(0);
IF document <> NIL THEN
document.ConserveMemory(0, TRUE {GC});
CheckAbort(0);
CASE fileOpKind OF
fopSuspend:
IF document.files.shouldSuspend THEN
document.Suspend(error);
{*** we ignore the volumePrefix !!! ***}
fopSaveVersion:
IF document.files.shouldToolSave OR NOT document.openedAsTool THEN
document.SaveVersion(error, volumePrefix, FALSE);
{$IFC LibraryVersion > 20}
fopCopyDoc:
{$ENDC}
1: {$IFC fTrace}EP;{$ENDC}
END;
{$S sStartup}
PROCEDURE {TProcess.}ObeyTheEvent;
{NOTE: For the duration of the event, we are focused on the eventWindow}
VAR eventDocument: TDocManager;
eventWindow:
TWindow;
dialogBox:
paused:
pkEvent:
{$IFC fCheckHeap}
numObjects:
docHeap:
{$ENDC}
TDialogBox;
BOOLEAN;
EventRecord;
INTEGER;
THeap;
PushFocus;
IF who = menuFolder THEN
eventWindow.Focus
ELSE
BEGIN
SetPort(event.who);
{$IFC fDbgABC}
IF fExperimenting and eventDebug THEN
WITH thePort^.portRect DO
BEGIN
WriteLn('Before LocalToGlobal (thePort):', ORD(thePort));
WriteLn(left, top, right, bottom);
WriteLn(where.h, where.v);
END;
{$ENDC}
LocalToGlobal(where);
eventWindow.Focus;
{$IFC fDbgABC}
IF fExperimenting and eventDebug THEN
WITH thePort^.portRect DO
BEGIN
WriteLn('Before GlobalToLocal (thePort):', ORD(thePort));
WriteLn(left, top, right, bottom);
WriteLn(where.h, where.v);
END;
{$ENDC}
GlobalToLocal(where);
{$IFC fDbgABC}
IF fExperimenting and eventDebug THEN
WITH thePort^.portRect DO
BEGIN
WriteLn('After GlobalToLocal (thePort):', ORD(thePort));
WriteLn(left, top, right, bottom);
WriteLn(where.h, where.v);
END;
{$ENDC}
END;
IF deferUpdate THEN
IF (what <> keyDown) OR appleKey THEN
eventWindow.Update(TRUE);
deferUpdate := FALSE;
CASE what OF
abortEvent:
eventWindow.AbortEvent;
buttonDown:
IF who = menuFolder THEN
eventWindow.MenuEventAt(where)
ELSE
eventWindow.DownEventAt(where);
folderActivate:
BEGIN
currentDocument := eventDocument;
eventWindow.Activate;
END;
folderDeactivate:
eventWindow.Deactivate;
folderMoved:
BEGIN
eventWindow.Resize(TRUE);
process.RememberCommand(uMoveWindow);
END;
folderUpdate:
eventWindow.Update(TRUE);
keyDown:
IF eventWindow.selectPanel = NIL THEN
{$IFC fDbgABC} ABCBreak('ObeyTheEvent: selectPanel=NIL', 0) {$ENDC}
ELSE
REPEAT
eventWindow.selectPanel.selection.DoKey(ascii,
keyCap, shiftKey, appleKey, codeKey);
IF PeekEvent(pkEvent) THEN
paused := (ImActive AND SELF.AbortRequest) OR
(eventWindow <> EvtWindow(pkEvent)) OR
(pkEvent.what <> keyDown) OR
((pkEvent.what = keyDown) AND (pkEvent.AppleKey)) {LSR}
ELSE
paused := TRUE;
IF NOT paused THEN
BEGIN
GetEvent(event);
eventTime := event.when;
eventType := event.what;
{$IFC fDbgABC}
IF eventDebug THEN
ReportEvent;
{$ENDC}
END
END;
ELSE
IF eventWindow.selectPanel <> NIL THEN
eventWindow.selectPanel.selection.KeyPause;
UNTIL paused;
SweepHeap(docHeap, TRUE);
END;
END;
IF boundClipboard <> NIL THEN
BEGIN
docHeap := boundClipboard.docHeap;
IF docHeap <> NIL THEN
BEGIN
numObjects := CountHeap(docHeap);
Write('; boundClipboard heap has ', numObjects:1, ' objects');
END;
END;
WriteLn;
END;
{$ENDC}
{$IFC fDebugMethods}
IF docList.Size = 0 THEN
SELF.DontDebug;
{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S sError}
FUNCTION {TProcess.}Phrase{(error: INTEGER)};
VAR erStr: S255;
BEGIN
{$IFC fTrace}BP(5);{$ENDC}
{client can override}
{also, I should case on os error codes}
CASE error OF
erAborted : Phrase := phTerminated;
OTHERWISE
BEGIN
{$IFC fTrace}
(** SuErrText('OSERRS.ERR', error, @erStr); **)
Writeln;
Writeln('Error # ', error, '; ', erStr);
{$ENDC}
Phrase := phUnknown;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCcld}
BEGIN
{$IFC fDbgABC}
ABCbreak('Invalid event type passed to TProcess.SendEvent', typeOfEvent);
{$ENDC}
END
ELSE
BEGIN
WITH er DO
BEGIN
who := NIL; {can't tell what window we are sending to}
what := typeOfEvent;
when := Time;
toProcess := targetProcess;
fromProcess := myProcessID;
userData := otherData;
END;
SendEvent(er, targetProcess);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sAlert}
PROCEDURE {TProcess.}Stop{(phraseNumber: INTEGER)};
{$IFC LibraryVersion > 20}
VAR dummy: INTEGER;
{$ENDC}
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
ArgAlert(0, toolName);
{$IFC LibraryVersion > 20}
IF activeWindowID = 0 THEN
dummy := BackgroundAlert(alerts, phraseNumber, StopProc)
ELSE
{$ENDC}
StopAlert(alerts, phraseNumber);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sStartup}
PROCEDURE {TProcess.}TrackCursor;
{ assumes we are active; can't track the cursor if not }
VAR cursorNumber:
TCursorNumber;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
cursorNumber := noCursor;
IF currentWindow.dialogBox <> NIL THEN
BEGIN
cursorNumber := currentWindow.dialogBox.CursorFeedback;
{was cantDown}
{$S SgABCini}
BEGIN
UnitAuthor('Apple');
InitProcess;
END;
METHODS OF TDocDirectory;
{$S SgABCini}
FUNCTION {TDocDirectory.}CREATE{(object: TObject; heap: THeap; itsWindow: TWindow;
itsClassWorld: TClassWorld): TDocDirectory};
VAR world: TClassWorld;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TDocDirectory(object);
WITH world DO
BEGIN
infRecs := TArray(itsClassWorld.infRecs.Clone(heap));
classes := TArray(itsClassWorld.classes.Clone(heap)); (*^*)
authors := TArray(itsClassWorld.authors.Clone(heap)); (*^*)
aliases := TArray(itsClassWorld.aliases.Clone(heap)); (*^*)
END;
WITH SELF DO
BEGIN
window := itsWindow;
classWorld := world;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TDocDirectory.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
Field('window: TWindow');
Field('classList: TList');
END;
{$ENDC}
{$S SgABCcld}
PROCEDURE {TDocDirectory.}Adopt; (*^*)
VAR world: TClassWorld;
heap:
THeap;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
heap := SELF.Heap;
world := SELF.classWorld;
WITH world DO
BEGIN
infRecs.Free;
classes.Free;
authors.Free;
aliases.Free;
infRecs := TArray(myWorld.infRecs.Clone(heap));
classes := TArray(myWorld.classes.Clone(heap));
authors := TArray(myWorld.authors.Clone(heap));
aliases := TArray(myWorld.aliases.Clone(heap));
END;
SELF.classWorld := world;
END;
{$S SgABCini}
END;
METHODS OF TDocManager;
{$S SgABCini}
FUNCTION {TDocManager.}CREATE{(object: TObject; heap: THeap; itsPathPrefix: TFilePath): TDocManager};
VAR itsVolume: TFilePath;
itsFile:
TFilePath;
i:
INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TDocManager(object);
SplitFilePath(itsPathPrefix, itsVolume, itsFile);
WITH SELF.files DO
BEGIN
volumePrefix := itsPathPrefix;
volume := itsVolume;
{$IFC LibraryVersion > 20}
password := '';
{$ENDC}
shouldSuspend := TRUE;
shouldToolSave := FALSE;
END;
WITH SELF.dataSegment DO
BEGIN
preludePtr := NIL;
FOR i := 1 TO maxSegments DO
refnum[i] := -1;
changes := 0;
END;
WITH SELF DO
BEGIN
window := NIL;
pendingNote := 0;
docHeap := NIL;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TDocManager.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN (* TFilePath = STRING[255]; maxSegments = 6 *)
Field(CONCAT('files: RECORD volumePrefix: STRING[255]; volume: STRING[255]; password: STRING[32];',
'saveExists: BOOLEAN; shouldSuspend: BOOLEAN; shouldToolSave: BOOLEAN; END'));
Field('dataSegment: RECORD refnum: ARRAY [1..6] OF INTEGER; preludePtr: Ptr; changes: LONGINT; END');
Field('docHeap: Ptr');
Field('window: TWindow');
Field('pendingNote: INTEGER');
Field('openedAsTool: BOOLEAN');
Field('');
END;
{$S SgABCres}
{$ENDC}
{$S SgABCcld}
PROCEDURE {TDocManager.}Assimilate{(VAR error: INTEGER)};
VAR hz:
THz;
exDocDirectory: TDocDirectory;
exClasses:
TClassWorld;
doConvert:
BOOLEAN;
olderVersion:
BOOLEAN;
newerVersion:
BOOLEAN;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
hz := POINTER(ORD(SELF.docHeap));
hz^.procCbMore := @ExpandHeap; {The code address may have changed}
error := 0;
WITH SELF.dataSegment.preludePtr^ DO
BEGIN
exDocDirectory := docDirectory;
exClasses := exDocDirectory.classWorld;
IF password <> 25376 THEN {***temporary***}
error := erPassword;
END;
(**)
error := erVersion;
END;
{$IFC fTrace}EP;{$ENDC}
END;
(**)
{$S sStartup}
PROCEDURE {TDocManager.}Bind;
VAR i:
INTEGER;
error:
INTEGER;
sched_err: INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF boundDocument <> SELF THEN
BEGIN
IF boundDocument <> NIL THEN
boundDocument.Unbind;
i := 1;
{We must bind segment #1 before we can find out numSegments}
REPEAT
Sched_Class(sched_err, FALSE);
Bind_DataSeg(error, SELF.dataSegment.refnum[i]);
Sched_Class(sched_err, TRUE);
IF error > 0 THEN
ABCBreak('Bind_DataSeg', error);
i := i + 1;
UNTIL i > SELF.dataSegment.preludePtr^.numSegments;
boundDocument := SELF;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCcld}
PROCEDURE {TDocManager.}Close{(afterSuspend: BOOLEAN)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF = currentDocument THEN
BEGIN
currentDocument := NIL;
currentWindow := NIL;
activeWindowID := 0;
END;
IF NOT afterSuspend THEN
SELF.KillSegments(1, maxSegments);
docList.DelObject(SELF, FALSE);
IF SELF = boundDocument THEN
boundDocument := NIL;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
PROCEDURE {TDocManager.}CloseFiles;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
{ For the application to override IF it needs to close any of its own files }
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCini}
PROCEDURE {TDocManager.}Complete{(allIsWell: BOOLEAN)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
{**** Try to save the document, code needed here. ****}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
PROCEDURE {TDocManager.}ConserveMemory{(maxExcess: LONGINT; fGC: BOOLEAN)};
VAR heap:
THeap;
hz:
THz;
bytesReduced:
LONGINT;
error:
INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF <> clipboard THEN
BEGIN
heap := SELF.docHeap;
IF fGC THEN
BEGIN
MarkHeap(heap, ORD(SELF.dataSegment.preludePtr^.docDirectory));
{$IFC fDbgABC}
SweepHeap(heap, TRUE);
{Report garbage}
{$ELSEC}
SweepHeap(heap, FALSE);
{Free garbage}
{$ENDC}
END;
hz := POINTER(ORD(heap));
REPEAT
bytesReduced := CbShrinkHz(hz, maxSegSize)
UNTIL bytesReduced < maxSegSize;
SELF.SetSegSize(error, CbOfHz(hz) + SELF.dataSegment.preludePtr^.preludeSize, maxExcess);
IF error > 0 THEN
process.Complete(FALSE);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
PROCEDURE {TDocManager.}Deactivate;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF = currentDocument THEN
BEGIN
currentWindow := NIL;
currentDocument := NIL; {so we can unbind the document}
END;
allowAbort := FALSE;
SELF.ConserveMemory(docExcess, FALSE {no GC});
allowAbort := TRUE;
SELF.Unbind;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCini}
FUNCTION {TDocManager.}DfltHeapSize{: LONGINT};
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
DfltHeapSize := docDsBytes;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$IFC fDbgABC}
{$S SgABCdbg}
PROCEDURE {TDocManager.}DumpPrelude;
VAR preludePtr: TPPrelude; {needed so WITH doesn't complain about $H+}
PROCEDURE AbortDumpVar(pVariable: Ptr; nameAndType: S255);
BEGIN
IF CheckKeyPress('Document prelude dump') THEN
BEGIN
WriteLn;
WriteLn;
Exit(DumpPrelude);
END;
DumpVar(pVariable, nameAndType);
END;
BEGIN
WriteLn;
WriteLn('--- PRELUDE OF THE DOCUMENT ---');
WriteLn;
preludePtr := SELF.dataSegment.preludePtr;
WITH preludePtr^ DO
BEGIN
AbortDumpVar(@password, 'password: INTEGER');
AbortDumpVar(@version, 'version: INTEGER');
AbortDumpVar(@country, 'country: INTEGER');
AbortDumpVar(@language, 'language: INTEGER');
AbortDumpVar(@preludeSize, 'preludeSize: INTEGER');
AbortDumpVar(@docSize, 'docSize: LONGINT');
AbortDumpVar(@numSegments, 'numSegments: INTEGER');
AbortDumpVar(@docDirectory, 'docDirectory: TDocDirectory');
END;
WriteLn;
WriteLn;
END;
{$S SgABCres}
{$ENDC}
{$S sCldInit}
PROCEDURE {TDocManager.}ExpandMemory{(bytesNeeded: LONGINT)};
VAR error:
INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.SetSegSize(error, SELF.dataSegment.preludePtr^.docSize + bytesNeeded, docExcess);
IF error > 0 THEN
process.Complete(FALSE);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
PROCEDURE {TDocManager.}KillSegments{(first, last: INTEGER)};
VAR i:
INTEGER;
dsPathname:
PathName;
{$IFC LibraryVersion > 20}
dsPassword:
E_Name;
blankPasswd:
E_Name;
{$ENDC}
error:
INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
error := 0;
{$IFC LibraryVersion > 20}
dsPassword := SELF.files.password;
blankPasswd := '';
{$ENDC}
FOR i := first TO last DO
IF SELF.dataSegment.refnum[i] >= 0 THEN
BEGIN
dsPathName := CONCAT(SELF.files.volumePrefix, suspendSuffix[i]);
{$IFC LibraryVersion > 20}
Change_Password(error, dsPathname, dsPassword, blankPasswd);
{$ENDC}
Kill_DataSeg(error, dsPathname);
Close_DataSeg(error, SELF.dataSegment.refnum[i]);
SELF.dataSegment.refnum[i] := -1;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sCldInit}
PROCEDURE {TDocManager.}MakeSegments{(VAR error: INTEGER; oldSegments: INTEGER; newDocSize: LONGINT)};
TYPE
TempType
= ARRAY [1..MAXINT] OF Byte;
PTempType
= ^TempType;
VAR currDocSize:
LONGINT;
newSegments:
INTEGER;
i:
INTEGER;
ldsn:
INTEGER;
thisSegSize:
LONGINT;
dsPathname:
PathName;
dsRefnum:
INTEGER;
memOrd:
LONGINT;
dsInfo:
DsInfoRec;
newSize:
LONGINT;
p:
PTempType;
{$IFC LibraryVersion > 20}
dsPassword:
E_Name;
blankPasswd:
E_Name;
{$ENDC}
sched_err:
INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF (boundDocument <> NIL) AND ((boundDocument <> SELF) OR (oldSegments = 0)) THEN
boundDocument.Unbind;
{*** This may be dispensable ***}
error := 0;
IF (oldSegments > 0) THEN
BEGIN
{expand the current last data segment out to maxSegSize;
we assume that the caller has already checked that a new segment is actually needed}
dsRefnum := SELF.dataSegment.refnum[oldSegments];
Info_DataSeg(error, dsRefnum, dsInfo);
IF error <= 0 THEN
BEGIN
Sched_Class(sched_err, FALSE);
Size_DataSeg(error, dsRefnum, maxSegSize - dsInfo.mem_size, newSize,
maxSegSize - dsInfo.disc_size, newSize);
Sched_Class(sched_err, TRUE);
END
ELSE
ABCbreak('In MakeSegments, error from Info_Dataseg', error);
END;
currDocSize := oldSegments*maxSegSize;
newSegments := oldSegments;
{$IFC LibraryVersion > 20}
dsPassword := SELF.files.password;
blankPasswd := '';
{$ENDC}
WHILE (currDocSize < newDocSize) AND (error <= 0) DO
BEGIN
newSegments := newSegments + 1;
ldsn := newSegments + docLdsn-1;
thisSegSize := Min(newDocSize - currDocSize, maxSegSize);
thisSegSize := LIntMulInt(LIntDivInt(thisSegSize + 511, 512), 512);
END;
currDocSize := currDocSize + thisSegSize;
IF process.AbortRequest THEN
error := erAborted;
END;
IF error <= 0 THEN
WITH SELF.dataSegment DO
BEGIN
IF oldSegments = 0 THEN
BEGIN
boundDocument := SELF;
FOR i := 1 TO SIZEOF(TPrelude) DO
p^[i] := 0;
preludePtr := POINTER(ORD(p));
END;
preludePtr^.docSize := currDocSize;
preludePtr^.numSegments := newSegments;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S Override}
FUNCTION {TDocManager.}NewWindow{(heap: THeap; wmgrID: TWindowID): TWindow};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
NewWindow := TWindow.CREATE(NIL, heap, wmgrID, TRUE);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCldInit}
PROCEDURE {TDocManager.}Open{(VAR error: INTEGER; wmgrID: TWindowID; VAR openedSuspended: BOOLEAN)};
LABEL
1;
VAR aFile:
TFile;
volumePrefix:
TFilePath;
pWindow:
WindowPtr;
window:
TWindow;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
openedSuspended := FALSE;
volumePrefix := SELF.files.volumePrefix;
IF SELF.files.shouldToolSave OR NOT SELF.openedAsTool THEN
BEGIN
pWindow := POINTER(wmgrID);
SetFldrRefCon(pWindow, ORD(SELF));
1:
docList.InsLast(SELF);
END
ELSE
IF NOT openedSuspended THEN
SELF.KillSegments(1, maxSegments);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sCldInit}
PROCEDURE {TDocManager.}OpenBlank{(VAR error: INTEGER; wmgrID: TWindowID)};
LABEL 1;
VAR heapSize:
LONGINT;
heapStart:
LONGINT;
docHeap:
THeap;
prPrfAlias:
TPrPrfAlias;
objCount:
INTEGER;
docWindow:
TWindow;
docDirectory:
TDocDirectory;
PROCEDURE CheckAbort;
BEGIN
IF process.AbortRequest THEN
BEGIN
error := erAborted;
GOTO 1;
END;
END;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
heapSize := SELF.DfltHeapSize;
SELF.MakeSegments(error, 0, heapSize + SIZEOF(TPrelude));
IF error <= 0 THEN
BEGIN
heapStart := ORD(SELF.dataSegment.preludePtr) + SIZEOF(TPrelude);
docHeap := POINTER(ORD(HzInit(POINTER(heapStart), POINTER(heapStart+heapSize),
NIL, LIntDivInt(heapSize, 10), 0, @ExpandHeap,
POINTER(procNil), POINTER(procNil), POINTER(procNil))));
{*** DANGER ***}
REPEAT
ldsn := i + docLdsn-1;
dsPathname := CONCAT(volumePrefix, suspendSuffix[i]);
IF currentDocument <> NIL THEN
{*** Get around OS anomaly ***}
error := 313
{*** What it should return for Revert ***}
ELSE
{*** Remove these lines when fixed ***}
BEGIN
{$IFC LibraryVersion > 20}
Change_Password(error, dsPathname, dsPassword, blankPasswd);
{$ENDC}
Open_DataSeg(error, dsPathname, dsRefnum, memOrd, ldsn);
END;
IF error <= 0 THEN
BEGIN
SELF.dataSegment.refnum[i] := dsRefnum;
IF ldsn = docLdsn THEN
preludePtr := POINTER(memOrd);
SetAccess_DataSeg(error, dsRefnum, FALSE); {Make writeable}
IF error > 0 THEN
ABCBreak('In TDocManager.OpenSuspended: SetAccess_DataSeg', error);
{$IFC LibraryVersion > 20}
Change_Password(error, dsPathname, blankPasswd, dsPassword);
IF error > 0 THEN
ABCBreak('In TDocManager.OpenSuspended: Change_Password', error);
{$ENDC}
i := i + 1;
END;
IF process.AbortRequest THEN
error := erAborted;
IF error > 0 THEN
cease := TRUE
ELSE
cease := i > preludePtr^.numSegments;
UNTIL cease;
IF error <= 0 THEN
BEGIN
SELF.dataSegment.preludePtr := preludePtr;
boundDocument := SELF;
SELF.ResumeAfterOpen(error, wmgrID);
END
ELSE
WHILE i > 1 DO {back out by unbinding the datasegs}
BEGIN
i := i - 1;
Unbind_Dataseg(otherError, SELF.dataSegment.refnum[i]);
{$IFC fDbgABC}
IF otherError > 0 THEN
WriteLn(CHR(7), 'Error unbinding dataseg=', otherError:1);
{$ENDC}
SELF.dataSegment.refnum[i] := -1;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
PROCEDURE {TDocManager.}ResumeAfterOpen{(VAR error: INTEGER; wmgrID: TWindowID)};
VAR preludePtr:
TPPrelude;
docHeap:
THeap;
objCount:
INTEGER;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
error := 0;
(*****
*****)
preludePtr := SELF.dataSegment.preludePtr;
docHeap := POINTER(ORD(preludePtr) + preludePtr^.preludeSize);
SELF.docHeap := docHeap;
SELF.Assimilate(error);
IF NOT fCheckHzOK(POINTER(ORD(docHeap)), objCount) THEN
BEGIN
ABCBreak('fCheckHzOK failed on suspend file: objCount', objCount);
error := erInternal;
END
ELSE
BEGIN
SELF.docHeap := docHeap;
SELF.Assimilate(error);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
PROCEDURE {TDocManager.}RevertVersion{(VAR error: INTEGER; wmgrID: TWindowID)};
{ for now, must be the active window to do this }
VAR dontCare:
BOOLEAN;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
error := 0;
SELF.Close(FALSE);
{ active/current Window/Document should have been made NIL by SELF.Close }
currentDocument := SELF;
{We could be cleverer and reuse the old data segments, later****}
allowAbort := FALSE; {no abort allowed during revert}
SELF.Open(error, wmgrID, dontCare);
allowAbort := TRUE;
IF error > 0 THEN
BEGIN
{$IFC fDbgABC}
ABCBreak('RevertVersion error opening document', error);
{$ENDC}
END
ELSE
BEGIN
PushFocus;
currentWindow := SELF.window;
activeWindowID := currentWindow.wmgrID;
currentWindow.Focus;
currentWindow.Resize(FALSE);
InvalRect(currentWindow.innerRect);
currentWindow.Update(TRUE);
PopFocus;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
PROCEDURE {TDocManager.}SaveVersion{(VAR error: INTEGER; volumePrefix: TFilePath; andContinue: BOOLEAN)};
VAR tmpFile:
TFile;
fs:
TFileScanner;
saveFile:
TFile;
localError:
INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
error := 0;
SELF.dataSegment.preludePtr^.docDirectory.window := SELF.window;
{Just in case it somehow changed}
IF NOT andContinue THEN
{*** Revert to one pane per panel scrolled to the beginning & no (or standard) selection***};
IF process.AbortRequest THEN
error := erAborted
ELSE
BEGIN
{SELF.ReleaseDiskSpace...;
*** TO DO **ONLY IF** WE CAN'T GET ENOUGH SPACE WITHOUT ***}
IF process.AbortRequest THEN
error := erAborted
ELSE
BEGIN
{$IFC LibraryVersion <= 20}
tmpFile := TFile.CREATE(NIL, mainHeap, CONCAT(volumePrefix, '$T'), '');
{$ELSEC}
tmpFile := TFile.CREATE(NIL, mainHeap, CONCAT(volumePrefix, '$T'), SELF.files.password);
{$ENDC}
fs := tmpFile.ScannerFrom(0, [fWrite]);
error := fs.error;
IF error <= 0 THEN
IF process.AbortRequest THEN
error := erAborted;
IF error > 0 THEN
BEGIN
tmpFile.Delete(localError);
fs.Free;
END
ELSE
BEGIN
process.AbortXferSequential(xWrite, POINTER(ORD(SELF.dataSegment.preludePtr)),
SELF.dataSegment.preludePtr^.docSize, abortChunkSize, fs);
fs.Compact;
{*** we should set the logical file size to the logical EOF ***}
error := fs.error;
{*** Be sure buffers are flushed ***}
IF error <= 0 THEN
IF process.AbortRequest THEN
error := erAborted;
IF error > 0 THEN
BEGIN
{$IFC fDbgABC}
ABCbreak('In TDocManager.SaveVersion, error saving file=', error);
{$ENDC}
{this is after we wrote out the file, need a wait alert if user aborted}
IF error = erAborted THEN
process.BeginWait(phAborting);
tmpFile.Delete(localError);
{$IFC fDbgABC}
IF localError > 0 THEN
ABCbreak('In TDocManager.SaveVersion, error deleting file=', localError);
{$ENDC}
process.EndWait;
fs.Free;
END
ELSE
BEGIN
fs.FreeObject; {don't free tmpFile yet}
IF SELF.files.saveExists THEN
BEGIN
{$IFC LibraryVersion <= 20}
saveFile := TFile.CREATE(NIL, mainHeap, volumePrefix, '');
{$ELSEC}
saveFile := TFile.CREATE(NIL, mainHeap, volumePrefix, SELF.files.password);
{$ENDC}
saveFile.Delete(localError);
saveFile.Free;
END;
SELF.files.saveExists := TRUE;
tmpFile.Rename(localError, volumePrefix);
{$IFC fDbgABC}
IF localError > 0 THEN
ABCbreak('In TDocManager.SaveVersion, error renaming file=', localError);
{$ENDC}
tmpFile.Free;
SELF.window.changes := 0;
END;
END;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sStartup}
PROCEDURE {TDocManager.}SetSegSize{(VAR error: INTEGER; minSize, maxExcess: LONGINT)};
{Make the memory and disk size of the virtual data segment be at least as indicated, and leave
some excess, but no more than the maximum indicated. Update docSize, numSegments, and the
refnum table. Assumptions:
The virtual data segment exists and is open and bound.
It has at least one real data segment, and has a valid heap that fits in the
lesser of the current diskSize and the new diskSize.
All LONG parameters are rounded up IF necessary to a multiple of 512 before they are used.}
VAR preludePtr:
TPPrelude;
dsInfo:
DsInfoRec;
oldMemSize:
LONGINT;
newSize:
LONGINT;
newSegments:
INTEGER;
newSegSize:
LONGINT;
temp:
LONGINT;
sched_err:
INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
error := 0;
minSize := LIntMulInt(LIntDivInt(minSize + 511, 512), 512);
maxExcess := LIntMulInt(LIntDivInt(maxExcess + 511, 512), 512);
preludePtr := SELF.dataSegment.preludePtr;
WITH preludePtr^ DO
BEGIN
Info_DataSeg(error, SELF.dataSegment.refNum[numSegments], dsInfo);
IF error > 0 THEN
ABCBreak('SetSegSize: Info_Dataseg', error);
oldMemSize := dsInfo.mem_size + (maxSegSize*(numSegments-1));
IF (oldMemSize < minSize) OR (oldMemSize > minSize + maxExcess) THEN
{need to adjust the segment size}
BEGIN
newSize := minSize + maxExcess;
newSegments := LIntDivLInt(newSize + maxSegSize - 1, maxSegSize);
{$IFC fDbgABC}
IF (numSegments < 1) OR (numSegments > maxSegments) THEN
ABCBreak('SetSegSize: numSegments NOT IN 1..maxSegments', numSegments);
IF (newSegments < 1) OR (newSegments > maxSegments) THEN
ABCBreak('SetSegSize: newSegments NOT IN 1..maxSegments', newSegments);
{$ENDC}
IF numSegments > newSegments THEN
{kill off whole segments we don't need anymore}
SELF.KillSegments(newSegments + 1, numSegments)
ELSE
IF numSegments < newSegments THEN
SELF.MakeSegments(error, numSegments, newSize);
{this sets all the segment sizes correctly}
{$S SgABCcld}
PROCEDURE {TDocManager.}Suspend{(VAR error: INTEGER)};
LABEL 1;
VAR lastSegClosed: INTEGER;
osErr:
INTEGER;
(*********** THESE VARIABLES ARE NEEDED ONLY IF SUSPEND IS ABORTABLE
volumePrefix:
TFilePath;
ldsn:
INTEGER;
dsPathname:
PathName;
dsRefnum:
INTEGER;
memOrd:
LONGINT;
reopenedSeg:
INTEGER;
**********)
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
{$IFC fDbgABC}
IF SELF <> boundDocument THEN
ABCBreak('Suspend not-bound document', error);
{$ENDC}
SELF.dataSegment.preludePtr^.docDirectory.window := SELF.window; {In case it somehow changed}
error := 0;
**********)
GOTO 1;
END;
IF error <= 0 THEN
error := erAborted;
GOTO 1;
END;
END;
SELF.dataSegment.changes := 0;
boundDocument := NIL;
1: {$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
PROCEDURE {TDocManager.}Unbind;
VAR error: INTEGER;
i:
INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF = boundDocument THEN
BEGIN
(***** See how things work without this check
{$IFC fDbgABC}
IF SELF = currentDocument THEN
ABCBreak('Unbind currentDocument', ORD(SELF));
{$ENDC}
*****)
FOR i := 1 TO SELF.dataSegment.preludePtr^.numSegments DO
BEGIN
Unbind_DataSeg(error, SELF.dataSegment.refnum[i]);
IF error > 0 THEN
ABCBreak('Unbind_DataSeg', error);
END;
boundDocument := NIL;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
FUNCTION {TDocManager.}WindowWithId{(wmgrID: TWindowID): TWindow};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.window.wmgrID = wmgrID THEN
WindowWithId := SELF.window
ELSE
WindowWithId := NIL;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCini}
END;
METHODS OF TClipboard;
{$S SgABCini}
FUNCTION {TClipboard.}CREATE{(object: TObject; heap: THeap): TClipboard};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TClipboard(TDocManager.CREATE(object, heap, '--CLIPBOARD'));
WITH SELF DO
BEGIN
hasView := FALSE;
hasPicture := FALSE;
hasUniversalText := FALSE;
hasIcon := FALSE;
cuttingTool := 0;
cuttingProcessID := 0;
clipCopy := NIL;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TClipboard.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
TDocManager.Fields(Field);
Field('hasView: BOOLEAN');
Field('hasPicture: BOOLEAN');
Field('hasUniversalText: BOOLEAN');
Field('hasIcon: BOOLEAN');
Field('cuttingTool: LONGINT');
Field('cuttingProcessID: LONGINT');
Field('clipCopy: TFileScanner;');
END;
{$S SgABCres}
{$ENDC}
{$S sCut}
PROCEDURE {TClipboard.}AboutToCut;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
InheritScrap(TRUE);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCut}
PROCEDURE {TClipboard.}BeginCut;
LABEL
1;
VAR heap:
THeap;
window:
TWindow;
panel:
TPanel;
view:
TView;
selection: TSelection;
error:
INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF boundClipboard = NIL THEN
boundClipboard := SELF
ELSE
ABCBreak('BeginCut: Clipboard already bound', 0);
EraseScrapData(error);
IF error > 0 THEN
BEGIN
ABCBreak('EraseScrapData', error);
BackOutOfScrap;
{need to put up alert that cut was not put into scrap and pass this info back up the ladder}
GOTO 1;
END;
{Obtain write access}
StartPutScrap(error);
IF error > 0 THEN
BEGIN
ABCBreak('StartPutScrap', error);
BackOutOfScrap;
{need to put up alert that cut was not put into scrap and pass this info back up the ladder}
GOTO 1;
END;
clipPrintPref := boundDocument.dataSegment.preludePtr^.printPref;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sPaste}
PROCEDURE {TClipboard.}Bind;
VAR which:
ScrapType;
what:
TH;
docDirectory:
TDocDirectory;
olderVersion:
BOOLEAN;
newerVersion:
BOOLEAN;
error:
INTEGER;
PROCEDURE CopyScrap;
VAR aFile:
TFile;
fs:
TFileScanner;
dsInfo:
DsInfoRec;
BEGIN
aFile := TFile.CREATE(NIL, mainHeap, 'TKScrapCopy', '');
fs := aFile.Scanner;
SELF.clipCopy := fs;
Info_Dataseg(error, DSegOfScrap, dsInfo);
{$IFC fDbgABC}
IF error > 0 THEN
ABCbreak('CopyScrap: error from Info_Dataseg', error);
{$ENDC}
WITH dsInfo DO
fs.XferSequential(xWrite, Ptr(AddrOfScrapDSeg), mem_size);
END;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
(**)
END;
SELF.window := docDirectory.window;
END;
{Record attributes of the clipboard data that the application might want to inquire about}
SELF.Inspect;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCut}
PROCEDURE {TClipboard.}CommitCut;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
AcceptInheritScrap;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCut}
PROCEDURE {TClipboard.}EndCut;
VAR window:
TWindow;
clipSel:
TSelection;
docDirectory:
TDocDirectory;
error:
INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
window := SELF.window;
clipSel := window.selectPanel.selection;
IF clipSel.kind = nothingKind THEN
BEGIN
{$IFC fDbgABC}
ABCBreak('No selection in Clipboard at EndCut', 0);
{$ENDC}
BackOutOfScrap;
{need to put up an alert and pass info up the ladder}
END
ELSE
BEGIN
{Display the Clipboard}
PushFocus;
window.Focus;
window.Refresh([rErase, rFrame, rBackground, rDraw], hNone);
PopFocus;
info:
picLRect:
tempHeap:
picRect:
tempPad:
pic:
error:
WindowInfo;
LRect;
THeap;
Rect;
TPad;
PicHandle;
INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF scrapProcess = myProcessID THEN
BEGIN
SELF.Bind;
window := SELF.window;
IF window <> NIL THEN {LSR}
BEGIN {LSR}
panel := TPanel(window.panels.First);
pane := TPane(panel.panes.First);
viewExtentLRect := window.selectPanel.view.extentLRect;
{Let the Window Manager have a picture to display while inactive [if open]}
GetWindInfo(POINTER(window.wmgrID), info);
IF info.visible THEN
window.StashPicture(hNone);
{Let others have a picture to paste}
noPad.RectToLRect(hugeRect, picLRect);
IF SectLRect(viewExtentLRect, picLRect, picLRect) AND NOT EmptyLRect(picLRect) THEN
BEGIN
GetHeap(tempHeap);
SetHeap(POINTER(ORD(HzOfScrap)));
{Before calling Focus, set up everything for unclipped drawing of the view}
tempPad := TPad.CREATE(NIL, mainHeap, hugeRect, picLRect, screenRes,
screenRes, thePort);
tempPad.LRectToRect(picLRect, picRect);
RectRgn(altVisRgn, picRect);
useAltVisRgn := TRUE;
{ enable clipping to whole picture }
{Focus on the Clipboard}
PushFocus;
tempPad.Focus;
focusArea := NIL;
genClipPic := TRUE;
PicComment(cPicGeDwg, 0, NIL);
PicGrpBegin;
panel.view.Draw;
PicGrpEnd;
{
{
{
{
ClosePicture;
{Put it in the Clipboard}
PutGrScrap(pic, error);
IF error > 0 THEN
ABCBreak('PutGrScrap', error);
{Generate the Universal Text}
panel.view.CreateUniversalText;
{Unravel}
genClipPic := FALSE;
useAltVisRgn := FALSE;
PopFocus;
tempPad.Free;
SetHeap(tempHeap);
END;
END; {LSR}
SELF.Unbind;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sPaste}
PROCEDURE {TClipboard.}Unbind;
VAR error:
INTEGER;
PROCEDURE RestoreScrap;
VAR fs: TFileScanner;
BEGIN
fs := SELF.clipCopy;
IF fs <> NIL THEN
BEGIN
fs.XferRandom(xRead, Ptr(AddrOfScrapDSeg), fs.actual, fAbsolute, 0);
fs.Free;
SELF.clipCopy := NIL;
END;
END;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF = boundClipboard THEN
BEGIN
RestoreScrap;
{$IFC fDbgABC}
IF SELF = currentDocument THEN
ABCBreak('TClipboard.Unbind currentDocument', ORD(SELF));
{$ENDC}
boundClipboard := NIL;
{Relinquish access}
SELF.window := NIL;
EndGetScrap(error);
IF error > 0 THEN
ABCBreak('EndGetScrap', error);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCut}
FUNCTION {TClipboard.}UndoCut{: BOOLEAN};
VAR clipErr:
INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
UndoInheritScrap(clipErr);
SELF.Inspect;
{so app can inquire}
(*
*)
IF (clipErr <= 0) AND SELF.hasView THEN * WRONG BECAUSE SELF.window MAY BELONG TO ANOTHER TK APP *
BEGIN
SELF.Bind;
SELF.window.Resize(FALSE); {in case clipboard resized between the cut and the undo-cut}
SELF.Unbind;
END;
UndoCut := clipErr <= 0;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCini}
END;
METHODS OF TCommand;
{$S sCommand}
FUNCTION {TCommand.}CREATE{(object: TObject; heap: THeap; itsCmdNumber: TCmdNumber;
itsImage: TImage; isUndoable: BOOLEAN; itsRevelation: TRevelation): TCommand};
VAR cmdPhase:
TCmdPhase;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TCommand(object);
WITH SELF DO
BEGIN
cmdNumber := itsCmdNumber;
image := itsImage;
undoable := isUndoable;
doing := FALSE;
revelation := itsRevelation;
FOR cmdPhase := doPhase TO redoPhase DO
BEGIN
unHiliteBefore[cmdPhase] := TRUE;
hiliteAfter[cmdPhase] := TRUE;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TCommand.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
Field('cmdNumber: INTEGER');
Field('image: TImage');
Field('undoable: BOOLEAN');
Field('doing: BOOLEAN');
Field('revelation: Byte');
Field('unHiliteBefore: ARRAY[0..2] OF BOOLEAN');
Field('hiliteAfter: ARRAY[0..2] OF BOOLEAN');
Field('');
END;
{$S SgABCres}
{$ENDC}
{$S sCommand}
PROCEDURE {TCommand.}Commit;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S sFilter}
PROCEDURE {TCommand.}EachVirtualPart{(PROCEDURE DoToObject(filteredObj: TObject))};
PROCEDURE DoToFilteredObject(actualObj: TObject);
BEGIN
SELF.FilterAndDo(actualObj, DoToObject);
END;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.image <> NIL THEN
SELF.image.EachActualPart(DoToFilteredObject)
ELSE
currentWindow.EachActualPart(DoToObject);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sFilter}
PROCEDURE {TCommand.}FilterAndDo{(actualObj: TObject; PROCEDURE DoToObject(filteredObj: TObject))};
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
DoToObject(actualObj);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCommand}
PROCEDURE {TCommand.}Perform{(cmdPhase: TCmdPhase)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCini}
END;
{$S SgABCres}
METHODS OF TCutCopyCommand;
{$S sCut}
FUNCTION {TCutCopyCommand.}CREATE{(object: TObject; heap: THeap; itsCmdNumber: TCmdNumber;
itsImage: TImage; isCutCmd: BOOLEAN): TCutCopyCommand};
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TCutCopyCommand(TCommand.CREATE(object, heap, itsCmdNumber, itsImage, TRUE, revealAll));
SELF.isCut := isCutCmd;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TCutCopyCommand.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
SUPERSELF.Fields(Field);
Field('isCut: BOOLEAN');
Field('');
END;
{$S SgABCcld}
{$ENDC}
{$S sCut}
PROCEDURE {TCutCopyCommand.}Commit;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
clipboard.CommitCut;
{$IFC fTrace}EP;{$ENDC}
END;
{$S Override}
PROCEDURE {TCutCopyCommand.}DoCutCopy{(clipSelection: TSelection; deleteOriginal: BOOLEAN;
cmdPhase: TCmdPhase)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCut}
PROCEDURE {TCutCopyCommand.}Perform{(cmdPhase: TCmdPhase)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
CASE cmdPhase OF
doPhase:
BEGIN
clipboard.AboutToCut;
clipboard.BeginCut;
SELF.DoCutCopy(clipboard.window.selectPanel.selection, SELF.isCut, cmdPhase);
clipboard.EndCut;
END;
undoPhase:
BEGIN
IF SELF.isCut THEN
BEGIN
IF NOT clipboard.hasView THEN
ABCbreak('undoing Cut but clipboard has no view', 0)
ELSE
BEGIN
clipboard.Bind;
IF clipboard.window = NIL THEN
ABCbreak('undoing Cut but clipboard.window = NIL', 0)
ELSE
SELF.DoCutCopy(clipboard.window.selectPanel.selection, TRUE, cmdPhase);
clipboard.Unbind;
END;
END
ELSE
SELF.DoCutCopy(NIL, FALSE, cmdPhase);
IF NOT clipboard.UndoCut THEN
BEGIN
{$IFC fDbgABC}
ABCbreak('clipboard.UndoCut returns FALSE', 0);
{$ENDC}
END;
END;
redoPhase:
BEGIN
IF NOT clipBoard.UndoCut THEN
BEGIN
ABCbreak('clipboard.UndoCut returns FALSE', 0);
END
ELSE
BEGIN
clipboard.Bind;
IF NOT clipboard.hasView THEN
ABCbreak('re-doing Cut/Copy but clipboard has no view', 0)
ELSE
SELF.DoCutCopy(clipboard.window.selectPanel.selection, SELF.isCut, cmdPhase);
clipboard.Unbind;
END;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCini}
END;
{$S SgABCres}
METHODS OF TPasteCommand;
{$S sPaste}
FUNCTION {TPasteCommand.}CREATE{(object: TObject; heap: THeap; itsCmdNumber: TCmdNumber;
itsImage: TImage): TPasteCommand};
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TPasteCommand(TCommand.CREATE(object, heap, itsCmdNumber, itsImage, TRUE, revealAll));
{$IFC fTrace}EP;{$ENDC}
END;
{$S Override}
PROCEDURE {TPasteCommand.}DoPaste{(clipSelection: TSelection; pic: PicHandle; cmdPhase: TCmdPhase)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S sPaste}
PROCEDURE {TPasteCommand.}Perform{(cmdPhase: TCmdPhase)};
VAR window:
TWindow;
pic:
PicHandle;
selection: TSelection;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
CASE cmdPhase OF
doPhase, redoPhase:
IF NOT (clipboard.hasPicture OR clipboard.hasView OR clipboard.hasUniversalText) THEN
IF currScrapSet = [] THEN
process.Stop(phNoClip)
ELSE
process.Stop(phUnkClip)
ELSE
BEGIN
clipboard.Bind;
{$H-} GetGrScrap(pic); {$H+}
window := clipboard.window;
IF window = NIL THEN
SELF.DoPaste(NIL, pic, cmdPhase)
ELSE
BEGIN
selection := window.selectPanel.selection;
IF selection.Class = cSelection THEN
SELF.DoPaste(NIL, pic, cmdPhase)
ELSE
SELF.DoPaste(selection, pic, cmdPhase);
END;
clipboard.Unbind;
END;
undoPhase:
SELF.DoPaste(NIL, NIL, cmdPhase);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCini}
END;
{$S SgABCres}
METHODS OF TImage;
{$S SgABCini}
FUNCTION {TImage.}CREATE{(object: TObject; heap: THeap; itsExtent: LRect; itsView: TView): TImage};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TImage(object);
WITH SELF DO
BEGIN
extentLRect := itsExtent;
view := itsView;
allowMouseOutside := FALSE;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TImage.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
Field('extentLRect: LRect');
Field('view: TView');
Field('allowMouseOutside: BOOLEAN');
Field('');
END;
{$S SgABCres}
{$ENDC}
{$S Override}
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
FUNCTION {TImage.}Hit{(mouseLPt: LPoint): BOOLEAN};
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
Hit := LRectHasLPt(SELF.extentLRect, mouseLPt);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TImage.}Invalidate;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
IF thePad <> NIL THEN
thePad.InvalLRect(SELF.extentLRect);
{$IFC fTrace}EP;{$ENDC}
END;
{$S Override}
FUNCTION {TImage.}LaunchLayoutBox{(view: TView): TImage};
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
LaunchLayoutBox := NIL;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TImage.}OffSetBy{(deltaLPt: LPoint)};
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
{$H-} OffsetLRect(SELF.extentLRect, deltaLPt.h, deltaLPt.v); {$H+}
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TImage.}OffSetTo{(newTopLeft: LPoint)};
VAR deltaLPt:
LPoint;
curTopLeft: LPoint;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
curTopLeft := SELF.extentLRect.topLeft;
window.clickPanel := panel;
END;
SELF.view.clickLPt := mouseLPt; {e.g., for Set Page Breaks use}
CASE mPhase OF
mPress:
SELF.MousePress(mouseLPt);
mMove:
SELF.MouseMove(mouseLPt);
mRelease:
BEGIN
SELF.MouseMove(mouseLPt);
window.Update(TRUE);
SELF.MouseRelease;
END;
END;
window.Update(TRUE);
{$IFC fTrace}EP;{$ENDC}
END;
{$S Override}
PROCEDURE {TImage.}ReactToPrinterChange;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S Override}
PROCEDURE {TImage.}RecalcExtent;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TImage.}Resize{(newExtent: LRect)};
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
SELF.extentLRect := newExtent;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
FUNCTION {TImage.}SeesSameAs{(image: TImage): BOOLEAN; DEFAULT};
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
SeesSameAs := image = SELF;
{$}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCini}
END;
METHODS OF TView;
{$S SgABCini}
FUNCTION {TView.}CREATE{(object: TObject; heap: THeap; itsPanel: TPanel; itsExtent: LRect;
itsPrintManager: TPrintManager; itsDfltMargins: LRect; itsFitPagesPerfectly:BOOLEAN;
itsRes: Point; isMainView: BOOLEAN): TView};
VAR screenPad: TPad;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TView(TImage.CREATE(object, heap, itsExtent, NIL));
WITH SELF DO
BEGIN
view := SELF;
panel := itsPanel;
printManager := itsPrintManager;
res := itsRes;
clickLPt := itsExtent.topLeft;
fitPagesPerfectly := itsFitPagesPerfectly;
{$H-}
SetPt(scrollPastEnd, 60, 40);
{$H+}
END;
SELF.isMainView := isMainView;
SELF.isPrintable := (itsPrintManager <> NIL) AND isMainView;
screenPad := TPad.CREATE(NIL, heap, zeroRect, zeroLRect, screenRes, SELF.res, NIL);
SELF.screenPad := screenPad;
{$H-}SetLPt(SELF.stdScroll, (16 * SELF.res.h) DIV screenRes.h, (11 * SELF.res.v) DIV screenRes.v); {$H+}
IF isMainView THEN
BEGIN
itsPanel.HaveView(SELF);
IF itsPrintmanager <> NIL THEN
itsPrintManager.Init(SELF, itsDfltMargins);
SELF.ReactToPrinterChange;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCini}
PROCEDURE {TView.}Free;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.isMainView THEN
Free(SELF.printManager);
Free(SELF.screenPad);
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TView.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
TImage.Fields(Field);
Field('panel: TPanel');
Field('clickLPt: LPoint');
Field('printManager: TPrintManager');
Field('res: Point');
Field('screenPad: TPad');
Field('fitPagesPerfectly: BOOLEAN');
Field('isPrintable: BOOLEAN');
Field('isMainView: BOOLEAN');
Field('stdScroll: LPoint');
Field('scrollPastEnd: Point');
Field('');
END;
{$S SgABCres}
{$ENDC}
{$S SgABCpri}
PROCEDURE {TView.}AddStripOfPages{(vhs: VHSelect)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.printManager <> NIL THEN
SELF.printManager.AddStripOfPages(vhs);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sCldInit}
PROCEDURE {TView.}BeInPanel{(panel: TPanel)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.panel := panel;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
PROCEDURE {TView.}CreateUniversalText;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sRes}
FUNCTION {TView.}CursorAt{(mouseLPt: LPoint): TCursorNumber};
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
CursorAt := arrowCursor;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgDRWres}
FUNCTION {TView.}DoReceive{(selection: TSelection; lPtInView: LPoint): BOOLEAN};
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
DoReceive := FALSE; {Default is to refuse cross-panel drag}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sStartup}
FUNCTION {TView.}ForceBreakAt{(vhs: VHSelect; precedingLocation: LONGINT;
proposedLocation: LONGINT): LONGINT};
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
ForceBreakAt := proposedLocation;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sScroll}
PROCEDURE {TView.}GetStdScroll{(VAR deltaLStd: LPoint)};
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
IF NOT SELF.panel.zoomed THEN
deltaLStd := SELF.stdScroll
ELSE
WITH SELF.panel.zoomFactor DO
{$H-} BEGIN
deltaLStd.h := LIntOvrInt(LIntMulInt(ORD4(SELF.stdScroll.h), denominator.h), numerator.h);
deltaLStd.v := LIntOvrInt(LIntMulInt(ORD4(SELF.stdScroll.v), denominator.v), numerator.v);
{$H+} END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCpri}
FUNCTION {TView.}MaxPageToPrint{: LONGINT};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
MaxPageToPrint := SELF.printManager.breaks[v].size * SELF.printManager.breaks[h].size;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sStartup}
FUNCTION {TView.}NoSelection{: TSelection};
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
NoSelection := TSelection.CREATE(NIL, SELF.Heap, SELF, nothingKind, zeroLPt);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
FUNCTION {TView.}OKToDrawIn{(lRectInView: LRect): BOOLEAN};
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
OKToDrawIn := FALSE;
{The default is to assume the worst, unless the application overrides}
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCldInit}
PROCEDURE {TView.}ReactToPrinterChange;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.printManager <> NIL THEN
SELF.printManager.ReactToPrinterChange;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sStartup}
PROCEDURE {TView.}RedoBreaks;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF SELF.printManager <> NIL THEN
SELF.printManager.RedoBreaks;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCcld}
PROCEDURE {TView.}RemapManualBreaks{(
FUNCTION NewBreakLocation(vhs: VHSelect; oldBreak: LONGINT): LONGINT)};
VAR printManager:
TPrintManager;
oldLoc:
LONGINT;
newLoc:
LONGINT;
oldIndex:
LONGINT;
vhs:
VHSelect;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
printManager := SELF.printManager;
IF printManager <> NIL THEN
BEGIN
printManager.ClearPageBreaks(TRUE);
FOR vhs := v TO h DO
FOR oldIndex := 1 TO printManager.breaks[vhs].size - 1 DO
BEGIN
oldLoc := TpLONGINT(printManager.breaks[vhs].At(oldIndex))^;
newLoc := - NewBreakLocation(vhs, ABS(oldLoc));
printManager.breaks[vhs].PutAt(oldIndex, @newLoc);
END;
SELF.RedoBreaks;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCldInit}
PROCEDURE {TView.}Resize{(newExtent: LRect)};
VAR s:
TListScanner;
pageBreak:
LONGINT;
vhs:
VHSelect;
oldLimit:
LONGINT;
newLimit:
LONGINT;
breakIndex:
INTEGER;
breakArray:
TArray;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
IF NOT (SELF.isMainView) OR NOT(SELF.isPrintable) THEN
SUPERSELF.Resize(newExtent)
ELSE
IF NOT EqualLRect(SELF.extentLRect, newExtent) THEN
BEGIN
FOR vhs := v TO h DO
BEGIN
oldLimit := SELF.extentLRect.botRight.vh[orthogonal[vhs]];
newLimit := newExtent.botRight.vh[orthogonal[vhs]];
breakIndex := 1;
breakArray := SELF.printManager.breaks[vhs];
WHILE breakIndex <= breakArray.size DO
BEGIN
pageBreak := TpLONGINT(breakArray.At(breakIndex))^;
IF pageBreak = oldLimit THEN
BEGIN
{reset the end-of-view pagebreak to new limit}
pageBreak := newLimit;
breakArray.PutAt(breakIndex, @pageBreak);
END
ELSE
IF ABS(pageBreak) >= newLimit THEN
{discard other now-too-big pagebreaks}
BEGIN
breakArray.DelAt(breakIndex);
breakIndex := breakIndex - 1;
END;
breakIndex := breakIndex + 1;
{ELSE pagebreak still valid; do nothing}
END;
END;
SELF.extentLRect := newExtent;
SELF.panel.Rescroll;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
PROCEDURE {TView.}SetFunctionValue{(keyword: S255; VAR itsValue: S255)};
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
StrUpperCased(@keyword);
IF keyword = varPage THEN {+SW+}
LIntToStr(theMarginPad.pageNumber, @itsValue)
ELSE
IF keyword = varTitle THEN {+SW+}
SELF.panel.window.GetTitle(itsValue)
{ELSE
IF keyword = ....
METHODS OF TPaginatedView;
{$S SgABCpri}
FUNCTION {TPaginatedView.}CREATE{(object: TObject; heap: THeap; itsUnpaginatedView: TView)
: TPaginatedView};
VAR viewExtent:
LRect;
pgsPerRowStrip:
pgsPerColStrip:
pageWidth:
pageHeight:
printerMetrics:
pageList:
rowStrip:
colStrip:
pageOrigin:
INTEGER;
INTEGER;
LONGINT;
LONGINT;
TPrinterMetrics;
TList;
INTEGER;
INTEGER;
LPoint;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
printerMetrics := itsUnpaginatedView.printManager.printerMetrics;
pgsPerRowStrip := itsUnpaginatedView.printManager.breaks[v].size;
pgsPerColStrip := itsUnpaginatedView.printManager.breaks[h].size;
WITH printerMetrics, paperRect DO
BEGIN
pageWidth := LIntOvrInt(LIntMulInt(ORD4(right - left), itsUnpaginatedView.res.h),
printerMetrics.res.h);
pageHeight:= LIntOvrInt(LIntMulInt(ORD4(bottom - top), itsUnpaginatedView.res.v),
printerMetrics.res.v);
END;
SetLRect(viewExtent, 0, 0, pgsPerRowStrip * ORD4(pageWidth), pgsPerColStrip * ORD4(pageHeight));
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TPaginatedView(TView.CREATE(object, heap, itsUnpaginatedView.panel, viewExtent,
itsUnpaginatedView.printManager, zeroLRect, FALSE,
itsUnpaginatedView.res, FALSE));
WITH SELF DO
BEGIN
unpaginatedView := itsUnpaginatedView;
pageSize[h] := pageWidth;
pageSize[v] := pageHeight;
workingInMargins := FALSE;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TPaginatedView.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
TView.Fields(Field);
Field('unPaginatedView: TView');
Field('pageSize: ARRAY[0..1] OF LONGINT');
Field('workingInMargins: BOOLEAN');
Field('');
END;
{$S SgABCcld}
{$ENDC}
{$S SgABCpri}
PROCEDURE {TPaginatedView.}AddStripOfPages{(vhs: VHSelect)};
VAR panel: TPanel;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
panel := SELF.panel;
panel.Preview(mPrvwOff); {get back to main-view metrics in the panes}
{Don't refer to SELF after this, since Preview has deallocated me}
panel.view.printManager.AddStripOfPages(vhs);
panel.Preview(mPrvwMargins); {creates fresh paginated view with correct info}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCpri}
PROCEDURE {TPaginatedView.}AdornPageOnScreen;
CONST
{$IFC LibraryVersion <= 20}
lrOffset = 10;
topOffset = 22;
bottomOffset = 9;
{$ELSEC}
{$ENDC}
lrOutset = 6;
topOutset = 4;
bottomOutset = 2;
lrOffset = 10;
topOffset = 22;
bottomOffset = 9;
lrOutset = 6;
topOutset = 1; {+SW+}
bottomOutset = 1;
VAR pgNum:
r:
tempRect:
paperRect:
contentRect:
S255;
Rect;
Rect;
Rect;
Rect;
pat:
{$IFC LibraryVersion <= 20}
fInfo:
{$ELSEC}
fInfo:
{$ENDC}
numberLength:
printManager:
pattern;
TFInfo;
FontInfo;
INTEGER;
TPrintManager;
{$S SgABCpri}
FUNCTION {TPaginatedView.}CursorAt{(mouseLPt: LPoint): TCursorNumber};
{later deal with cursor for margins}
VAR unPagLPt: LPoint;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
SELF.DepagifyLPoint(mouseLPt, unPagLPt);
CursorAt := SELF.unpaginatedView.CursorAt(unPagLPt);
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE {TPaginatedView.}DepagifyLPoint{(pagLPt: LPoint; VAR unPagLPt: LPoint)};
{Given a point in the paginated view, determine the nearest corresponding point in the unpaginated view}
VAR printManager:
meatLRect:
vhs:
breakArray:
strip:
breakLocation:
pageBreak:
nextBreak:
pageOrigin:
strips:
lOffsetPt:
TPrintManager;
LRect;
{the portion of the page that displays a part of the main view}
VHSelect;
TArray {OF LONGINT};
INTEGER;
{the ordinal number of the strip containing the page}
LONGINT;
{the coordinate of the start of the page}
LONGINT; {the page break at the beginning of the page}
LONGINT; {the page break at the end of the page}
LPoint;
{the top left corner of the page, in the paginated view}
Point;
{the strip numbers in each direction, stored as a Point}
LPoint;
{the top left corner of the meat rect of the page, in the main view}
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
LRectHaveLPt(SELF.extentLRect, pagLPt);
printManager := SELF.unpaginatedView.printManager;
meatLRect := printManager.contentLRect;
FOR vhs := v TO h DO
BEGIN
breakArray := printManager.breaks[orthogonal[vhs]];
{compute strip number}
strip := Min(LIntDivLInt(pagLPt.vh[vhs], SELF.pageSize[vhs]) + 1, breakArray.size);
{compute breakLocation, being the location in the main view of the top-leftmost
content point of the page in which our boy was found}
IF strip = 1 THEN
breakLocation := 0
ELSE
BEGIN
pageBreak := TpLONGINT(breakArray.At(strip - 1))^;
breakLocation := ABS(pageBreak);
END;
{recompute end of meatLRect (limbo boundary)}
nextBreak := TpLONGINT(breakArray.At(strip))^;
meatLRect.botRight.vh[vhs] := meatLRect.topLeft.vh[vhs] + ABS(nextBreak) - breakLocation;
{compute pageOrigin -- the location in the paginated view of the topleft corner of this page}
{$H-}
{$H+}
PushFocus;
IF (theMarginPad.view <> SELF.unpaginatedView) OR (theMarginPad.port = printerPseudoPort) THEN
theMarginPad.Rework(SELF.unpaginatedView, zeroPt, screenRes, 1,
SELF.panel.zoomFactor, POINTER(SELF.panel.window.wmgrId));
FOR row := firstRowStrip TO lastRowStrip DO
FOR column := firstColStrip to lastColStrip DO
BEGIN
IF SELF.printManager.pageRiseDirection = h THEN
pageNumber := (row - 1) * pgsPerStrip + column
ELSE
pageNumber := (column - 1) * pgsPerStrip + row;
SetLPt(lOrigin,
LIntMulInt(SELF.pageSize[h], column - 1) - incomingPane.scrollOffset.h,
LIntMulInt(SELF.pageSize[v], row - 1)
- incomingPane.scrollOffset.v);
SELF.screenPad.LPtToPt(lOrigin, origin);
theMarginPad.SetForPage(pageNumber, origin);
theMarginPad.ClipFurtherTo(incomingPane.innerRect); {clip page down to pane}
theBodyPad.ClipFurtherTo(incomingPane.innerRect);
{ditto page body}
IF focusOnInterior THEN
theBodyPad.Focus
ELSE
theMarginPad.Focus;
DoOnAPage;
END;
PopFocus;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE {TPaginatedView.}Draw;
PROCEDURE DrawPageOnScreen;
BEGIN
SELF.printManager.DrawPage;
SELF.AdornPageOnScreen;
END;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
SELF.DoOnPages(FALSE, DrawPageOnScreen);
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE {TPaginatedView.}MouseTrack{(mPhase: TPhase; mouseLPt: LPoint)};
VAR unPagLPt: LPoint;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
SELF.DepagifyLPoint(mouseLPt, unPagLPt);
SELF.unpaginatedView.MouseTrack(mphase, unPagLPt);
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE {TPaginatedView.}PagifyLPoint{(unPagLPt: LPoint; VAR pagLPt: LPoint)};
VAR pageBreak: LONGINT;
strip:
Point;
vhs:
VHSelect;
pageNumber: LONGINT;
orthoVhs:
VHSelect;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
pageNumber := SELF.printManager.PageWith(unPagLPt, strip);
FOR vhs := v TO h DO
BEGIN
orthoVhs := orthogonal[vhs];
IF (strip.vh[orthoVhs] < 1) OR (strip.vh[orthoVhs] > SELF.printManager.breaks[orthoVhs].Size) THEN
ABCBreak('PagifyLPt: strip=', strip.vh[orthoVHs])
{only for short-term debugging}
ELSE
IF strip.vh[orthoVhs] = 1 THEN
pagLPt.vh[vhs] := unPagLPt.vh[vhs] + SELF.printManager.contentLRect.topLeft.vh[vhs]
ELSE
BEGIN
pageBreak := TpLONGINT(SELF.printManager.breaks[orthoVhs].At(strip.vh[orthoVhs] - 1))^;
pagLPt.vh[vhs] := unPagLPt.vh[vhs] + SELF.printManager.contentLRect.topLeft.vh[vhs]
+ LIntMulInt(SELF.pageSize[vhs], strip.vh[orthoVhs] - 1) - ABS(pageBreak);
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCpri}
PROCEDURE {TPaginatedView.}ReactToPrinterChange;
{$S SgABCpri}
PROCEDURE {TPageView.}Draw;
VAR s:
TListScanner;
heading:
THeading;
pageNumber: LONGINT;
outerFrame: LRect;
headings:
TList;
editing:
BOOLEAN;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
PenNormal;
IF SELF.printManager.frameBody THEN {body should be framed...}
IF amPrinting THEN
FrameLRect(SELF.printManager.contentLRect);
editing := (SELF.printManager.layoutDialogBox <> NIL) AND
(SELF.printManager.view.panel.window.dialogBox = SELF.printManager.layoutDialogBox);
headings := SELF.printManager.headings;
IF headings <> NIL THEN
BEGIN
pageNumber := theMarginPad.pageNumber;
s := headings.Scanner;
{tell each Heading to draw itself}
WHILE s.Scan(heading) DO
IF heading.ShouldDraw(pageNumber) THEN
BEGIN
IF NOT editing THEN
BEGIN
heading.AdjustForPage(pageNumber, FALSE);
{client changes contents/extent}
heading.LocateOnPage(FALSE);
{...then we adjust to page}
END;
heading.Draw;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCini}
END;
{$S SgABCres}
{$S SgABCini}
METHODS OF TPrintManager;
FOR vhs := v TO h DO
BEGIN
l := TArray.CREATE(NIL, itsMainView.Heap, 1, SIZEOF(LONGINT));
pageBreak := itsMainView.extentLRect.botRight.vh[orthogonal[vhs]];
l.InsFirst(@pageBreak);
SELF.breaks[vhs] := l;
END;
WITH itsDfltMargins DO
BEGIN {$H-}
left := ABS(left);
top := ABS(top);
right := - ABS(right);
bottom := - ABS(bottom);
END; {$H+}
SELF.pageMargins := itsDfltMargins;
pageView := SELF.NewPageView(NIL);
SELF.pageView := pageView;
SELF.SetDfltHeadings;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCini}
PROCEDURE {TPrintManager.}Free;
VAR vhs:
VHSelect;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
FOR vhs := v TO h DO
IF SELF.breaks[vhs] <> NIL THEN
SELF.breaks[vhs].Free;
Free(SELF.pageView);
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TPrintManager.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
Field('view: TView');
Field('pageView: TPageView');
Field('breaks: ARRAY[0..1] OF TArray');
Field('pageMargins: LRect');
Field('headings: TList');
Field('canEditPages: BOOLEAN');
Field('layoutDialogBox: TDialogBox');
Field('frameBody: BOOLEAN');
Field('paperLRect: LRect');
Field('printableLRect: LRect');
{safeLRect out}
Field('contentLRect: LRect');
Field(CONCAT('printerMetrics: RECORD paperRect: Rect; printRect: Rect; ',
'res: Point; reserve: ARRAY[0..7] OF Byte END'));
Field('pageRiseDirection: BOOLEAN');
Field('');
END;
{$S SgABCres}
{$ENDC}
{$S SgABCpri}
PROCEDURE {TPrintManager.}AddStripOfPages{(vhs: VHSelect)};
VAR newExtentLRect: LRect;
adjustment:
LONGINT;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
WITH SELF.contentLRect DO {cd save a mote by flipping vhs just before this}
adjustment := botRight.vh[orthogonal[vhs]] - topLeft.vh[orthogonal[vhs]];
WITH SELF.view.extentLRect DO
IF vhs = v THEN
{$H-}
SetLRect(newExtentLRect, left, top, right + adjustment, bottom)
ELSE
SetLRect(newExtentLRect, left, top, right, bottom + adjustment); {$H+}
SELF.view.Resize(newExtentLRect);
SELF.RedoBreaks;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCpri}
PROCEDURE {TPrintManager.}ChangeMargins{(margins: LRect)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
WITH margins DO
BEGIN {$H-}
left := ABS(left);
top := ABS(top);
right := - ABS(right);
bottom := - ABS(bottom);
END; {$H+}
SELF.pageMargins := margins;
SELF.view.panel.currentView.ReactToPrinterChange;
SELF.view.panel.Invalidate;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sCldInit}
PROCEDURE {TPrintManager.}ClearPageBreaks{(automatic: BOOLEAN)};
VAR s:
TListScanner;
break:
LONGINT;
vhs:
VHSelect;
endOfView: LONGINT;
breakIndex:
INTEGER;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
{ Clears all page breaks of the specified kind EXCEPT for the one marking the end of the view }
FOR vhs := v TO h DO
BEGIN
endOfView := SELF.view.extentLRect.botRight.vh[orthogonal[vhs]];
breakIndex := 1;
WHILE breakIndex < SELF.breaks[vhs].size DO
BEGIN
break := TpLONGINT(SELF.breaks[vhs].At(breakIndex))^;
IF (break >= 0) = automatic THEN
IF ABS(break) < endOfView THEN
BEGIN
SELF.breaks[vhs].DelAt(breakIndex);
breakIndex := breakIndex - 1;
END;
breakIndex := breakIndex + 1;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
PROCEDURE {TPrintManager.}DrawBreaks{(manualOnly: BOOLEAN)};
VAR wLPt1:
LPoint;
wLPt2:
LPoint;
vhs:
VHSelect;
dir:
VHSelect;
viewEnd:
LONGINT;
visEnd:
LONGINT;
widthAdjust:
INTEGER;
showing:
BOOLEAN;
limit:
LONGINT;
pageBreak:
LONGINT;
breakIndex:
INTEGER;
finished:
BOOLEAN;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
thePad.DistToLDist(autoBreakPen.pnSize, wLPt1);
thePad.DistToLDist(manualBreakPen.pnSize, wLPt2);
IF NOT amPrinting THEN
FOR vhs := v TO h DO
BEGIN
{Inhibit display of breaks to the top/left of the pane}
dir := orthogonal[vhs];
viewEnd := SELF.view.extentLRect.botRight.vh[dir];
visEnd := thePad.visLRect.botRight.vh[dir];
widthAdjust := Max(wLPt1.vh[dir], wLPt2.vh[dir]) + 1;
problems}
showing := FALSE;
limit := thePad.visLRect.topLeft.vh[dir];
breakIndex := 1;
finished := FALSE;
WHILE (breakIndex <= SELF.breaks[vhs].size) AND NOT finished DO
BEGIN
pageBreak := TpLONGINT(SELF.breaks[vhs].At(breakIndex))^;
IF ABS(pageBreak) >= limit THEN
BEGIN
IF NOT showing THEN
{Start displaying breaks; reset limit to where we'll stop}
limit := Min(viewEnd, visEnd + widthAdjust);
showing := ABS(pageBreak) < limit;
IF NOT showing THEN
{Stop displaying breaks}
finished := TRUE;
END;
IF showing THEN
IF NOT ( (pageBreak >= 0) AND manualOnly) THEN
SELF.DrawOneBreak(pageBreak, vhs);
breakIndex := breakIndex + 1;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE {TPrintManager.}DrawOneBreak{(pageBreak: LONGINT; vhs: vhSelect)};
VAR lPt1:
LPoint;
lPt2:
LPoint;
pt:
Point;
wPt:
Point; {width of line}
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF pageBreak >= 0 THEN
thePad.SetPen(autoBreakPen)
ELSE
thePad.SetPen(manualBreakPen);
lPt1 := zeroLPt;
lPt2 := SELF.view.extentLRect.botRight;
lPt1.vh[orthogonal[vhs]] := ABS(pageBreak);
lPt2.vh[orthogonal[vhs]] := ABS(pageBreak);
wPt := thePort^.pnSize;
wPt.vh[vhs] := 0;
thePad.LPtToPt(lPt1, pt);
MoveTo(pt.h - wPt.h, pt.v - wPt.v); {wPt adjustment to hang line off top/left, not bot/right}
thePad.LPtToPt(lPt2, pt);
LineTo(pt.h - wPt.h, pt.v - wPt.v); {wPt adjustment to hang line off top/left, not bot/right}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCpri}
PROCEDURE {TPrintManager.}DrawPage;
VAR
heading:
THeading;
contentRect:
Rect;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF (amPrinting) AND (SELF.frameBody) THEN {client wants frame drawn on printed page}
BEGIN
theMarginPad.LRectToRect(SELF.contentLRect, contentRect);
PenNormal;
PenSize(3,2);
PenMode(patOr);
InsetRect(contentRect, -1, -1);
FrameRect(contentRect);
END;
SELF.pageView.Draw;
theBodyPad.Focus;
SELF.view.Draw;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCpri}
PROCEDURE {TPrintManager.}EnterPageEditting;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCpri}
PROCEDURE {TPrintManager.}GetPageLimits{(pageNumber: LONGINT; VAR viewLRect: LRect)};
{ NB:
The default is that page numbers go up from left-to-right, as illustrated by:
|--------|--------|--------|
| page 1 | page 2 | page 3 |
|--------|--------|--------|
| page 4 | page 5 | page 6 |
|--------|--------|--------|
totalStrips:
INTEGER;
pageRiseDirection:
orthoDirection:
strips:
vhs:
breakArray:
strip:
nextLocation:
pageBreak:
VHSelect;
VHSelect;
Point;
VHSelect;
TArray {OF LONGINT};
INTEGER;
LONGINT;
LONGINT;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
pageRiseDirection := SELF.pageRiseDirection;
orthoDirection := orthogonal[pageRiseDirection];
totalStrips := SELF.breaks[orthoDirection].size;
strips.vh[orthoDirection] := ((pageNumber - 1) DIV totalStrips) + 1;
strips.vh[pageRiseDirection] := pageNumber - ((strips.vh[orthoDirection] - 1) * totalStrips);
FOR vhs := v TO h DO
BEGIN
breakArray := SELF.breaks[orthogonal[vhs]];
strip := strips.vh[vhs];
IF strip = 1 THEN
nextLocation := 0
ELSE
BEGIN
pageBreak := TpLONGINT(breakArray.At(strip - 1))^;
nextLocation := ABS(pageBreak);
END;
viewLRect.topLeft.vh[vhs] := nextLocation;
pageBreak := TpLONGINT(breakArray.At(strip))^;
viewLRect.botRight.vh[vhs] := ABS(pageBreak);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
FUNCTION {TPrintManager.}NewPageView{(object: TObject): NewPageView};
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
NewPageView := TPageView.CREATE(object, SELF.Heap, SELF);
{$IFC fTrace}EP;{$ENDC}
END;
FUNCTION {TPrintManager.}NewPaginatedView{(object: TObject): TPaginatedView};
{Building Block or Client reimplements this to install own flavor of paginated view}
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
NewPaginatedView := TPaginatedView.CREATE(object, SELF.Heap, SELF.view);
{$IFC fTrace}EP;{$ENDC}
END;
FUNCTION {TPrintManager.}PageWith{(VAR lPtInView: LPoint; VAR strip: Point): LONGINT};
VAR pageBreak: LONGINT;
curStrip:
INTEGER;
vhs:
VHSelect;
finished:
BOOLEAN;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
LRectHaveLPt(SELF.view.extentLRect, lPtInView);
FOR vhs := v TO h DO
BEGIN
finished := FALSE;
curStrip := 1;
WHILE (curStrip <= SELF.breaks[orthogonal[vhs]].size) AND NOT finished DO
BEGIN
pageBreak := TpLONGINT(SELF.breaks[orthogonal[vhs]].At(curStrip))^;
IF lPtInView.vh[vhs] <= ABS(pageBreak) THEN
BEGIN
strip.vh[orthogonal[vhs]] := curStrip;
finished := TRUE;
END
ELSE
curStrip := curStrip + 1;
END;
END;
PageWith := (strip.vh[SELF.pageRiseDirection] - 1) *
SELF.breaks[orthogonal[SELF.pageRiseDirection]].size
* strip.vh[orthogonal[SELF.pageRiseDirection]];
{$IFC fTrace}EP;{$ENDC}
END;
{Note:
The Pepsi and the Spring versions of the following procedure are completely different}
GOTO 5;
GOTO 6;
theMarginPad.Rework
(SELF.view, zeroPt, printerMetrics.res, 1,
scaleOne, printerPseudoPort); {set up margin/body pads...}
pageNumber := 0;
REPEAT
pageNumber := pageNumber + 1;
2:
3:
PrStartPage(dispatchCode);
CASE PrCheckErr(dispatchCode) OF
prGoDocStart:
BEGIN
fSpool := FALSE;
GOTO 1;
END;
prGoStartPage:
GOTO 2;
prGoEndPage:
BEGIN
SELF.SkipPage(pageNumber); {read on to start of next page, without
printing this one}
GOTO 4;
END;
prGoDocEnd:
prGoExit:
GOTO 5;
GOTO 6;
prGoCont:
{actually print the page}
BEGIN
theMarginPad.SetForPage(pageNumber, zeroPt);
WHILE PrNextBand(rBand) DO
BEGIN
theMarginPad.ClipFurtherTo(rBand);
theMarginPad.Focus;
SELF.DrawPage;
PrDumpBand(dispatchCode);
CASE PrCheckErr(dispatchCode) OF
PrGoDocStart:
BEGIN
fSpool := FALSE;
GOTO 1;
END;
PrGoStartPage: ABCBreak('PrGoStartPage received; page #=', pageNumber);
PrGoDumpBand : GOTO 3;
PrGoEndPage : GOTO 4;
PrGoDocEnd
: GOTO 5;
PrGoExit
: GOTO 6;
END; { CASE }
END;
{WHILE PrNextBand}
END; {prGoCont dispatch code from prStartPage}
END; {case on Err from StartPage}
4:
PrEndPage(dispatchCode);
CASE PrCheckErr(dispatchCode) OF
PrGoDocStart: BEGIN
fSpool := FALSE;
GOTO 1;
END;
PrGoExit:
END; { case }
GOTO 2;
PrDocEnd(dispatchCode);
CASE PrCheckErr(dispatchCode) OF
PrGoDocStart:
PrGoStartPage:
PrGoDocEnd
PrGoExit
END; { case }
:
:
BEGIN
fSpool := FALSE;
GOTO 1;
END;
ABCBreak('PrGoStartPage received; page #=', pageNumber);
GOTO 5;
GOTO 6;
6:
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{ END of Pepsi-release version of TPrintmanager.Print }
(*********************************************************************************************************)
{$ELSEC}
{spring-release version of TPrintManager.Print follows}
{$S SgABCpri}
PROCEDURE {TPrintManager.}Print{(printPref: TPrReserve)};
VAR unzoomed:
TScaler;
pageNumber:
LONGINT;
pgsTotal:
LONGINT;
prPort:
TPrPort;
prPrfAlias:
TPrPrfAlias;
resPageEnd:
BOOLEAN;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
prPrfAlias.reserve := printPref;
SetPt(unzoomed.numerator, 1, 1);
SetPt(unzoomed.denominator, 1, 1);
pgsTotal := SELF.view.MaxPageToPrint; {by default, # of rowBreaks * # of colBreaks}
{several changes}
vhs:
curLPt:
pageIncrement:
metrics:
VHSelect;
LPoint;
LONGINT;
TPrinterMetrics;
metrics.res.h),
metrics.res.v),
metrics.res.h),
metrics.res.v));
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
{ SELF.InvalidatePageBreaks, or some such ???}
SELF.view.panel.window.GetPrinterMetrics; {except maybe for view in first Panel created, this will
be an unnecessary (but inexpensive) step}
metrics := SELF.view.panel.window.printerMetrics;
SELF.printerMetrics := metrics;
{$H-}
SELF.pageView.Resize(SELF.paperLRect);
SELF.view.SetMinViewSize(newExtent); {++}
SELF.view.Resize(newExtent);
{set view back to its min size}
SELF.RedoBreaks;
{may resize the view upwards again by a bit}
{SELF.InvalidatePageBreaks again -- to force update where new breaks are to be shown}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sCldInit}
PROCEDURE {TPrintManager.}RedoBreaks;
VAR vhs:
VHSelect;
maxViewPixelsPerPage: INTEGER;
curLocation:
LONGINT;
onePixelTooMuch:
LONGINT;
endOfView:
LONGINT;
s:
TListScanner;
nextPageBreak:
LONGINT;
breakIndex:
penultimatePageBreak:
newViewExtent:
INTEGER;
LONGINT;
LRect;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
newViewExtent := SELF.view.extentLRect;
SELF.ClearPageBreaks(TRUE); {clear out old automatic breaks}
FOR vhs := v TO h DO
BEGIN
WITH SELF.contentLRect DO
IF vhs = v THEN
maxViewPixelsPerPage := right - left
ELSE
maxViewPixelsPerPage := bottom - top;
endOfView := SELF.view.extentLRect.botRight.vh[orthogonal[vhs]];
breakIndex := 1;
curLocation := 0;
WHILE curLocation < endOfView DO
BEGIN
nextPageBreak := TpLONGINT(SELF.breaks[vhs].At(breakIndex))^;
onePixelTooMuch := Min(curLocation + MaxViewPixelsPerPage, endOfView);
IF ABS(nextPageBreak) <= onePixelTooMuch THEN
curLocation := ABS(nextPageBreak)
ELSE {no manual page break; impose an automatic one -- propose onePixelTooMuch}
BEGIN
curLocation := SELF.view.ForceBreakAt(vhs, curLocation, onePixelTooMuch);
SELF.breaks[vhs].InsAt(breakIndex, @curLocation);
END;
breakIndex := breakIndex + 1;
END;
IF SELF.view.fitPagesPerfectly THEN {make minor adjustment upward}
BEGIN
IF (SELF.breaks[vhs].size > 1) THEN
penultimatePageBreak := TpLONGINT(SELF.breaks[vhs].At(SELF.breaks[vhs].size - 1))^
ELSE
penultimatePageBreak := 0;
newViewExtent.botRight.vh[orthogonal[vhs]] := ABS(penultimatePageBreak) +
maxViewPixelsPerPage;
END;
END; {for vhs := v to h}
SELF.view.Resize(newViewExtent);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCpri}
PROCEDURE {TPrintManager.}SetBreak{(vhs: VHSelect; where: LONGINT; isAutomatic: BOOLEAN)};
VAR s:
TListScanner;
break:
LONGINT;
{comment gone}
prevBreakLoc: LONGINT;
breakIndex:
INTEGER;
finished:
BOOLEAN;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
prevBreakLoc := 0;
breakIndex := 1;
finished := FALSE;
WHILE (breakIndex <= SELF.breaks[vhs].size) AND NOT finished DO
BEGIN
break := TpLONGINT(SELF.breaks[vhs].At(breakIndex))^;
IF ABS(break) > where THEN
{found where to insert!}
BEGIN
where := SELF.view.ForceBreakAt(vhs, prevBreakLoc, where);
break := where;
IF NOT isAutomatic THEN
break := - break;
SELF.breaks[vhs].InsAt(breakIndex, @break);
finished := TRUE;
END
ELSE
IF ABS(break) = where THEN
{replace an existing page break}
BEGIN
break := where;
IF NOT isAutomatic THEN
break := - break;
SELF.breaks[vhs].PutAt(breakIndex, @break);
finished := TRUE;
END
ELSE
prevBreakLoc := ABS(break);
breakIndex := breakIndex + 1;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
PROCEDURE {TPrintManager.}SetDfltHeadings;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{client redefines}
{$S SgABCpri}
PROCEDURE {TPrintManager.}SkipPage{(pageNumber: LONGINT)};
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCini}
END;
{$S SgABCres}
METHODS OF THeading;
{$S SgABCini}
FUNCTION {THeading.}CREATE{(object: TObject; heap: THeap; itsPrintManager: TPrintManager;
itsExtentLRect: LRect; itsPageAlignment: TPageAlignment; itsOffsetFromAlignment: LPoint): THeading};
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := THeading(TImage.CREATE(object, heap, itsExtentLRect, itsPrintManager.pageView));
WITH SELF DO
BEGIN
printManager := itsPrintManager;
pageAlignment := itsPageAlignment;
offsetFromAlignment := itsOffsetFromAlignment;
oddOnly := FALSE;
evenOnly := FALSE;
minPage := 2;
maxPage := MAXLINT;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {THeading.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
TImage.Fields(Field);
Field('printManager: TPrintManager');
Field('pageAlignment: Byte'); {enumerated type}
Field('offsetFromAlignment: LPoint');
Field('oddOnly: BOOLEAN');
Field('evenOnly: BOOLEAN');
Field('minPage: LONGINT');
Field('maxPage: LONGINT');
Field('');
END;
{$S SgABCcld}
{$ENDC}
PROCEDURE {THeading.}AdjustForPage{(pageNumber: LONGINT; editing: BOOLEAN)};
{will be overridden in Subclass if meaningful}
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE {THeading.}ChangePageAlignment{(newPageAlignment: TPageAlignment)};
VAR newOffset:
LPoint;
FUNCTION Mid(anLRect: LRect; vhs: VHSelect): LONGINT;
BEGIN
Mid := (anLRect.topLeft.vh[vhs] + anLRect.botRight.vh[vhs]) DIV 2;
END;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
IF SELF.pageAlignment <> newPageAlignment THEN
BEGIN
CASE newPageAlignment OF
aTopLeft, aBottomLeft:
newOffset.h := SELF.extentLRect.left - SELF.view.extentLRect.left;
aTopCenter, aBottomCenter:
newOffset.h := Mid(SELF.extentLRect, h) - Mid(SELF.view.extentLRect, h);
aTopRight, aBottomRight:
newOffset.h := SELF.extentLRect.right - SELF.view.extentLRect.right;
END;
CASE newPageAlignment OF
aTopLeft, aTopCenter, aTopRight:
newOffset.v := SELF.extentLRect.top - SELF.view.extentLRect.top;
END;
CASE {SELF.}pageAlignment OF
aTopLeft,
aTopCenter,
aTopRight:
BEGIN
currentV := extentLRect.top;
targetV := top;
END;
aBottomLeft,
aBottomCenter,
aBottomRight:
BEGIN
currentV := extentLRect.bottom;
targetV := bottom;
END;
END;
END;
END;
(* CIRCUMVENT COMPILER BUG *)
WITH SELF.offsetFromAlignment DO
{$H-}SetLPt(offset, targetH - currentH + h, targetV - currentV + v); {$H+}
SELF.OffsetBy(offset);
{$IFC fTrace}EP;{$ENDC}
END;
FUNCTION {THeading.}ShouldDraw{(pageNumber:
VAR judgment: BOOLEAN;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
WITH SELF DO
IF (oddOnly AND NOT ODD(pageNumber))
(evenOnly AND ODD(pageNumber))
(pageNumber < minPage)
(pageNumber > maxPage)
THEN
judgment := FALSE
ELSE
judgment := TRUE;
ShouldDraw := judgment;
{$IFC fTrace}EP;{$ENDC}
END;
LONGINT): BOOLEAN};
OR
OR
OR
END;
{$S SgABCini}
END;
{$S SgABCres}
METHODS OF TSelection;
{$S sStartup}
FUNCTION {TSelection.}CREATE{(object: TObject; heap: THeap; itsView: TView; itsKind: INTEGER;
itsAnchorLPt: LPoint): TSelection};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TSelection(object);
WITH SELF DO
BEGIN
currLPt := itsAnchorLPt;
anchorLPt := itsAnchorLPt;
boundLRect := hugeLRect;
kind := itsKind;
view := itsView;
panel := view.panel;
IF panel <> NIL THEN
window := panel.window;
coSelection := NIL;
canCrossPanels := FALSE;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
FUNCTION {TSelection.}Clone{(heap: Theap): TObject};
VAR selection:
TSelection;
coSelection:
Tselection;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
selection := TSelection(SUPERSELF.Clone(heap));
IF SELF.coSelection <> NIL THEN
BEGIN
coSelection := TSelection(SELF.coSelection.Clone(heap));
selection.coSelection := coSelection;
END;
Clone := selection;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TSelection.}Free;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
Free(SELF.coSelection);
TObject.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
FUNCTION {TSelection.}FreedAndReplacedBy{(selection: TSelection): TSelection};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.Become(selection);
FreedAndReplacedBy := SELF;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TSelection.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
Field('window: TWindow');
Field('panel: TPanel');
Field('view: TView');
Field('kind: INTEGER');
Field('anchorLPt: LPoint');
Field('currLPt: LPoint');
Field('boundLRect: LRect'); {+++LSR+++}
Field('coSelection: TSelection');
Field('canCrossPanels: BOOLEAN');
Field('');
END;
{$S SgABCres}
{$ENDC}
{$S sRes}
FUNCTION {TSelection.}CanDoCommand{(cmdNumber: TCmdNumber; VAR checkIt: BOOLEAN): BOOLEAN};
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF SELF.coSelection <> NIL THEN
CanDoCommand := SELF.coSelection.CanDoCommand(cmdNumber, checkIt)
ELSE
CanDoCommand := SELF.window.CanDoCommand(cmdNumber, checkIt);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sAlert}
PROCEDURE {TSelection.}CantDoCmd{(cmdNumber: TCmdNumber)};
VAR cmdStr: S255;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF menuBar.GetCmdName(cmdNumber, @cmdStr) THEN
BEGIN
process.ArgAlert(1, cmdStr);
process.Stop(phUnkCmd);
END
ELSE
SELF.CantDoIt;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sAlert}
PROCEDURE {TSelection.}CantDoIt;
VAR ph: INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.kind = nothingKind THEN
ph := phNoSel
ELSE
ph := phSelCant;
process.Stop(ph);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TSelection.}Deselect;
VAR selection: TSelection;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.panel.Highlight(SELF, hOnToOff);
selection := SELF.FreedAndReplacedBy(SELF.view.NoSelection);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCcld}
PROCEDURE {TSelection.}DrawGhost;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TSelection.}DoKey{(ascii: CHAR; keycap: Byte; shiftKey, appleKey, optionKey: BOOLEAN)};
VAR cmdNumber:
TCmdNumber;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF appleKey THEN
BEGIN
SELF.window.SetupMenus;
cmdNumber := menuBar.CmdKey(ascii);
SELF.window.DoCommand(cmdNumber);
END
ELSE
IF currentDocument = clipboard THEN
process.Stop(phEditClip)
ELSE
IF SELF.kind = nothingKind THEN
process.Stop(phNoSel)
ELSE
BEGIN
CASE ORD(ascii) OF
ascArwDown:
SELF.KeyEnter(0, 1);
ascArwLeft:
SELF.KeyEnter(-1, 0);
ascArwRight:
SELF.KeyEnter(1, 0);
ascArwUp:
SELF.KeyEnter(0, -1);
ascClear:
SELF.KeyClear;
ascEnter:
SELF.KeyEnter(0, 0);
OTHERWISE
CASE ORD(ascii) OF
ascBackspace:
IF shiftKey THEN
SELF.KeyForward(appleKey)
ELSE
SELF.KeyBack(appleKey);
ascReturn:
SELF.KeyReturn;
ascTab:
SELF.KeyTab(shiftKey);
OTHERWISE
SELF.KeyChar(ascii);
END;
END;
IF ORD(ascii) <> ascClear THEN
process.RememberCommand(uKeyDown); {clear is special}
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TSelection.}GetHysteresis{(VAR hysterPt: Point)};
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
SetPt(hysterPt, stdHHysteresis, stdVHysteresis);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCpri}
PROCEDURE {TSelection.}HaveView{(view: TView)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.view := view;
IF SELF.coSelection <> NIL THEN
SELF.coSelection.HaveView(view);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sStartup}
PROCEDURE {TSelection.}Highlight{(highTransit: THighTransit)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.coSelection <> NIL THEN
SELF.coSelection.Highlight(highTransit);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TSelection.}IdleBegin{(centiSeconds: LONGINT)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.coSelection <> NIL THEN
SELF.coSelection.IdleBegin(centiSeconds)
ELSE
SELF.window.IdleBegin(centiSeconds);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TSelection.}IdleContinue{(centiSeconds: LONGINT)};
BEGIN
{$IFC fTrace}BP(5);{$ENDC}
IF SELF.coSelection <> NIL THEN
SELF.coSelection.IdleContinue(centiSeconds)
ELSE
SELF.window.IdleContinue(centiSeconds);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TSelection.}IdleEnd{(centiSeconds: LONGINT)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.coSelection <> NIL THEN
SELF.coSelection.IdleEnd(centiSeconds)
ELSE
SELF.window.IdleEnd(centiSeconds);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TSelection.}KeyBack{(fWord: BOOLEAN)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.coSelection <> NIL THEN
SELF.coSelection.KeyBack(fWord)
ELSE
SELF.CantDoCmd(uBackspace);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TSelection.}KeyChar{(ch: CHAR)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.coSelection <> NIL THEN
SELF.coSelection.KeyChar(ch)
ELSE
SELF.CantDoCmd(uTyping);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TSelection.}KeyClear;
VAR dummy: BOOLEAN;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.coSelection <> NIL THEN
SELF.coSelection.KeyClear
ELSE IF (menubar.GetCmdName(uClear, NIL))
(SELF.CanDoCommand(uClear, dummy))
BEGIN
menuBar.HighlightMenu(uClear);
SELF.window.DoCommand(uClear);
END
ELSE
BEGIN
SELF.CantDoCmd(uClear);
process.RememberCommand(uClear);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TSelection.}KeyEnter{(dh, dv: INTEGER)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.coSelection <> NIL THEN
SELF.coSelection.KeyEnter(dh, dv)
ELSE
SELF.CantDoCmd(uEnter);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TSelection.}KeyForward{(fWord: BOOLEAN)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
BEGIN
IF currentWindow.lastCmd = NIL THEN
delta := 1
ELSE
IF currentWindow.lastCmd.doing THEN
delta := 1
ELSE
delta := -1;
currentWindow.changes := currentWindow.changes + delta;
IF boundDocument = currentDocument THEN
WITH boundDocument DO
dataSegment.changes := dataSegment.changes + delta;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TSelection.}MousePress{(mouseLPt: LPoint)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.coSelection <> NIL THEN
SELF.coSelection.MousePress(mouseLPt);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TSelection.}MouseMove{(mouseLPt: LPoint)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.coSelection <> NIL THEN
SELF.coSelection.MouseMove(mouseLPt);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TSelection.}MouseRelease;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.coSelection <> NIL THEN
SELF.coSelection.MouseRelease;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCcld}
PROCEDURE {TSelection.}MoveBackToAnchor;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
FUNCTION {TSelection.}NewCommand{(cmdNumber: TCmdNumber): TCommand};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.coSelection <> NIL THEN
NewCommand := SELF.coSelection.NewCommand(cmdNumber)
ELSE
NewCommand := SELF.window.NewCommand(cmdNumber);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TSelection.}PerformCommand{(command: TCommand; cmdPhase: TCmdPhase)};{+sw+}
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
command.doing := (cmdPhase <> undoPhase);
command.Perform(cmdPhase);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TSelection.}Restore;
{SELF should be undoSelection}
VAR selection: TSelection;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
selection := SELF.panel.selection.FreedAndReplacedBy(
TSelection(SELF.panel.undoSelection.Clone(SELF.Heap))); {$}
selection := SELF.panel.undoSelection.FreedAndReplaceBy(SELF.view.NoSelection);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TSelection.}Reveal(asMuchAsPossible: BOOLEAN);
TYPE TXLRect = PACKED ARRAY [1..SIZEOF(LRect)] OF CHAR;
VAR lr:
LRect;
hMin:
INTEGER;
vMin:
INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.coSelection <> NIL THEN
SELF.coSelection.Reveal(asMuchAsPossible)
ELSE
BEGIN
lr := SELF.boundLRect;
IF TXLRect(lr) <> TXLRect(hugeLRect) THEN
BEGIN
IF NOT asMuchAsPossible THEN
BEGIN
hMin := 30;
vMin := 20;
END
ELSE
WITH lr DO
BEGIN
hMin := Min(MAXINT, right - left + 6);
vMin := Min(MAXINT, bottom - top + 4);
END;
SELF.panel.RevealLRect(lr, hMin, vMin);
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TSelection.}Save;
VAR selection: TSelection;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
selection := SELF.panel.undoSelection.FreedAndReplacedBy(TSelection(SELF.Clone(SELF.Heap)));
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TSelection.}SelectParagraphs;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.coSelection <> NIL THEN
SELF.coSelection.SelectParagraphs;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCini}
BEGIN
cSelection := THISCLASS;
END;
{$S SgABCres}
panelToPrint := NIL;
objectToFree := NIL; {+SW+}
END;
panels := TList.CREATE(NIL, heap, 1);
SELF.panels := panels;
IF itsWmgrID = 0 THEN
SELF.SetInnerRect(zeroRect)
ELSE
BEGIN
pWindow := POINTER(itsWmgrID);
SELF.SetInnerRect(pWindow^.portRect);
END;
{$H-} SELF.maxInnerSize := Point(FDiagRect(SELF.innerRect)); {$H+}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCini}
PROCEDURE {TWindow.}Free;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
Free(SELF.dialogBox);
SELF.panels.Free;
TArea.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TWindow.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
TArea.Fields(Field);
Field('panels: TList');
Field('panelTree: TArea');
Field('dialogBox: TDialogBox');
Field('selectPanel: TPanel');
Field('undoSelPanel: TPanel');
Field('clickPanel: TPanel');
Field('undoClickPanel: TPanel');
Field('selectWindow: TWindow');
Field('undoSelWindow: TWindow'); {+SW+}
Field('wmgrID: Ptr');
Field('isResizable: BOOLEAN');
Field('believeWmgr: BOOLEAN');
Field('maxInnerSize: Point');
Field('changes: LONGINT');
Field('lastCmd: TCommand');
Field(CONCAT('printerMetrics: RECORD paperRect: Rect; printRect: Rect;',
'res: Point; reserve: ARRAY[0..3] OF INTEGER END'));
Field('pgSzOK: BOOLEAN');
Field('pgRgOK: BOOLEAN');
Field('panelToPrint: TPanel');
Field('objectToFree: TObject'); {+SW+}
Field('');
END;
{$S SgABCres}
{$ENDC}
{$S SgABCcld}
PROCEDURE {TWindow.}AbortEvent;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCpri}
PROCEDURE {TWindow.}AcceptNewPrintingInfo{(document: TDocManager; prReserve: TPrReserve)};
VAR s:
TListScanner;
panel:
TPanel;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
SELF.selectPanel.selection.MarkChanged;
IF document = clipboard THEN
{first, stuff the revised print record back in document}
clipPrintPref := prReserve
ELSE
document.dataSegment.preludePtr^.printPref := prReserve;
SELF.GetPrinterMetrics;
s := SELF.panels.Scanner;
WHILE s.Scan(panel) DO
panel.currentView.ReactToPrinterChange;
{tell each view that printer style changed}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sStartup}
PROCEDURE {TWindow.}Activate; {assumes we are focused on the window already}
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF NOT SELF.believeWmgr THEN {is this needed????}
SELF.Resize(FALSE);
SELF.Update(TRUE);
currentWindow := SELF;
{$ENDC}
uPrMonitor:
CanDoStdCommand := onDesktop AND (SELF.dialogBox = NIL);
{**temporary**}
{Edit}
uUndoLast:
IF SELF.lastCmd = NIL THEN
CanDoStdCommand := FALSE
ELSE
CanDoStdCommand := SELF.lastCmd.undoable;
{Page Layout}
uPrvwMargins, uPrvwBreaks,
IF couldPrint THEN
BEGIN
CanDoStdCommand :=
CASE cmdNumber OF
uPrvwMargins:
checkIt :=
uPrvwBreaks:
checkIt :=
uPrvwOff:
checkIt :=
END;
END;
previewMode = mPrvwMargins;
previewMode = mPrvwBreaks;
previewMode = mPrvwOff;
uDesignPages:
IF couldPrint THEN
BEGIN
CanDoStdCommand := (SELF.dialogBox = NIL);
checkIt := (SELF.dialogBox = panelToUse.view.printManager.layoutDialogBox)
AND (SELF.dialogBox <> NIL);
END;
uSetHorzBreak, uSetVertBreak, uClearBreaks:
CanDoStdCommand := SELF.clickPanel.view.isPrintable;
uShowFullSize, uReduce70Pct, uReduceToFit:
CanDoStdCommand := fExperimenting;
{**temporary**}
uRiseVertically, uRiseHorizontally:
IF couldPrint THEN
BEGIN
CanDoStdCommand := TRUE;
checkIt := panelToUse.view.printManager.pageRiseDirection =
END
ELSE
CanDoStdCommand := FALSE;
VHSelect(cmdNumber = uRiseHorizontally);
{$IFC fDbgABC}
{Debug}
uReportEvents, uCountHeap, uCheckIndices,
uExperimenting, uDumpGlobals, uDumpPrelude,
uMainScramble, uDocScramble:
BEGIN
CanDoStdCommand := TRUE;
CASE cmdNumber OF
uReportEvents:
checkIt := eventDebug;
uCountHeap:
checkIt := fCountHeap;
uCheckIndices:
checkIt := fCheckIndices;
uExperimenting:
checkIt := fExperimenting;
uMainScramble:
checkIt := THz(mainHeap)^.fScramble;
uDocScramble:
IF currentDocument <> NIL THEN
checkIt := THz(currentDocument.docHeap)^.fScramble
ELSE
CanDoStdCommand := FALSE;
END;
END;
uReptGarbage, uFreeGarbage:
CanDoStdCommand := clipboard.window <> SELF;
{$ENDC}
{Debug}
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sStartup}
PROCEDURE {TWindow.}ChkPrMismatch;
VAR styleDidChange: BOOLEAN;
prPrfAlias:
TPrPrfAlias;
s:
TListScanner;
panel:
TPanel;
error:
document:
INTEGER;
TDocManager;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF currentDocument <> NIL THEN
document := currentDocument
ELSE
document := boundDocument;
IF document = clipboard THEN
prPrfAlias.reserve := clipPrintPref
ELSE
prPrfAlias.reserve := document.dataSegment.preludePtr^.PrintPref;
{$IFC libraryVersion <= 20}
{ P E P S I }
IF FPrArbRqd(prPrfAlias.prPrf) THEN
BEGIN
PrArbDlg(error, prPrfAlias.prPrf, styleDidChange);
{$ELSEC}
{ S P R I N G }
IF NOT fPrPrfValid(prPrfAlias.prPrf) THEN
BEGIN
PrPrfDlg(prPrfAlias.prPrf, styleDidChange, NOT SELF.pgSzOK);
{$ENDC}
IF styleDidChange THEN
SELF.AcceptNewPrintingInfo(document, prPrfAlias.reserve);
END;
{?? Do we need to worry about refreshing the window when needed?}
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCommand}
PROCEDURE {TWindow.}CommitLast;
VAR lastCmd:
TCommand;
lastView:
TView; {+SW+}
selection: TSelection; {+SW+}
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF <> currentWindow THEN
currentWindow.CommitLast
ELSE
BEGIN
lastCmd := SELF.lastCmd;
IF lastCmd <> NIL THEN
BEGIN
IF lastCmd.doing THEN
lastCmd.Commit;
(*****
IF lastCmd.image <> NIL THEN
*****)
BEGIN
lastView := lastCmd.image.view;
selection := lastView.panel.undoSelection.FreedAndReplacedBy(lastView.NoSelection);
END;
lastCmd.Free;
SELF.lastCmd := NIL;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sStartup}
FUNCTION {TWindow.}CursorFeedback{: TCursorNumber};
VAR s:
TListScanner;
panel:
TPanel;
cursorNumber:
TCursorNumber;
mousePt:
Point;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
PushFocus;
SELF.Focus;
cursorNumber := noCursor;
GetMouse(mousePt);
IF RectHasPt(SELF.innerRect, mousePt) THEN
IF SELF.isResizable AND fGrowHit(mousePt) THEN
cursorNumber := arrowCursor
ELSE
BEGIN
s := SELF.panels.Scanner;
WHILE s.Scan(panel) DO
BEGIN
cursorNumber := panel.CursorAt(mousePt);
IF cursorNumber <> noCursor THEN
s.Done;
END;
IF cursorNumber = noCursor THEN
cursorNumber := arrowCursor;
END;
PopFocus;
CursorFeedback := cursorNumber;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCcld}
PROCEDURE {TWindow.}Deactivate; {assumes we are focused on the window already}
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
(******************** these lines are needed for the Extra Window feature *)
IF currentWindow <> SELF THEN
BEGIN
GiveControl(event); {This must be last}
{$IFC fTrace}EP;{$ENDC}
EXIT(Deactivate);
END;
(* ********************)
SELF.CommitLast;
IF SELF.dialogBox <> NIL THEN
SELF.dialogBox.Disappear;
activeWindowID := 0; {must precede StashPicture and Refresh so scroll bars are white}
SELF.Refresh([rFrame], hOnToDim); {do first to give user feedback}
SELF.StashPicture(hOfftoDim);
IF (SELF.wmgrId <> ORD(scrapFolder)) AND (event.fromProcess <> myProcessID) THEN
clipboard.Publicize;
focusArea := NIL;
IF NOT inBackground THEN
currentDocument.Deactivate;
GiveControl(event); {This must be last}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sCommand}
PROCEDURE {TWindow.}DoCommand{(cmdNumber: TCmdNumber)};
VAR command: TCommand;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF cmdNumber <> 0 THEN
BEGIN
IF cmdNumber = uUndoLast THEN
SELF.UndoLast
ELSE
BEGIN
command := SELF.selectPanel.selection.NewCommand(cmdNumber);
IF command <> NIL THEN
{NOTE: If NewCommand Frees SELF (this window), it MUST return NIL}
SELF.PerformCommand(command);
END;
process.RememberCommand(cmdNumber);
END;
menuBar.EndCmd;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sClick}
FUNCTION {TWindow.}DownAt{(mousePt: Point): BOOLEAN};
VAR s:
TListScanner;
panel: TPanel;
b:
BOOLEAN;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
b := FALSE;
IF RectHasPt(SELF.innerRect, mousePt) THEN
BEGIN
IF SELF.isResizable THEN
IF fGrowHit(mousePt) THEN
BEGIN
SELF.DownInSizeBox(mousePt);
b := TRUE;
process.RememberCommand(uResizeWindow);
END;
IF NOT b THEN
BEGIN
b := TRUE;
s := SELF.panels.Scanner;
WHILE s.Scan(panel) DO
IF panel.DownAt(mousePt) THEN
s.Done;
END;
END;
DownAt := b;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sClick}
PROCEDURE {TWindow.}DownEventAt{(mousePt: Point)};
VAR clickNeighborhood: Rect;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.Update(TRUE); {In case an alert box was dismissed by the click}
{ given that previous click was at (0,0), clickNeighborhood is a rectangle in which
this click must fall for it to have a chance at being a double click }
SetRect(clickNeighborhood, -9, -6, 9, 6);
{ clickNeighborhood should be a method call;
how much flexibility is needed???? }
SELF.ResizeTo(Point(FPtMinusPt(newBotRight, oldRect.topLeft)));
{$IFC fTrace}EP;{$ENDC}
END;
{$S sFilter} {+SW+}
PROCEDURE {TWindow.}EachActualPart{(PROCEDURE DoToObject(filteredObj: TObject))};
VAR n:
INTEGER;
cmdWindow: TWindow;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
{$IFC fDbgABC}
IF SELF = currentWindow.dialogBox THEN
cmdWindow := currentWindow
ELSE
cmdWindow := SELF;
IF cmdWindow.lastCmd = NIL THEN
n := 0
ELSE
n := cmdWindow.lastCmd.cmdNumber;
ABCBreak('A View or Window tried to filter but did not implement EachActualPart: lastCmd =', n);
{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sFilter}
PROCEDURE {TWindow.}EachVirtualPart{(PROCEDURE DoToObject(filteredObj: TObject))};
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.FilterDispatch(NIL, NIL, DoToObject);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sFilter}
PROCEDURE {TWindow.}FilterAndDo{(actualObj: TObject; PROCEDURE DoToObject(filteredObj: TObject))};
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.FilterDispatch(actualObj, NIL, DoToObject);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sFilter}
PROCEDURE {TWindow.}FilterDispatch{(actualObj: TObject; image: TImage;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sStartup}
PROCEDURE {TWindow.}Frame;
VAR growRect: Rect;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF SELF.isResizable THEN
BEGIN
GetGrowRect(growRect);
IF RectIsVisible(growRect) THEN
IF SELF.IsActive THEN
PaintGrow
ELSE
FillRect(growRect, white);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sCldInit}
PROCEDURE {TWindow.}GetPrinterMetrics;
VAR prPrfAlias:
TPrPrfAlias;
prInfo:
TPrInfo;
tkDevice:
INTEGER;
document:
TDocManager;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
IF currentDocument <> NIL THEN
document := currentDocument
ELSE
document := boundDocument;
IF document = clipboard THEN
prPrfAlias.reserve := clipPrintPref
ELSE
prPrfAlias.reserve := document.dataSegment.preludePtr^.printPref;
{$IFC libraryVersion <= 20}
{ P E P S I }
PrMetrics(prPrfAlias.prPrf, prInfo);
{$ELSEC}
{ S P R I N G }
prInfo := prPrfAlias.prPrf.prInfo; {this looks odd, but the prPrf is of type prRec really}
{$ENDC}
WITH SELF.printerMetrics, prInfo DO
BEGIN
printRect := rPrintable;
paperRect := rPaper;
END;
SELF.printerMetrics.res.h := prInfo.hRes;
SELF.printerMetrics.res.v := prInfo.vRes;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sStartup}
PROCEDURE {TWindow.}GetMinExtent{(VAR minExtent: Point; windowIsResizingIt: BOOLEAN)};
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
SELF.panelTree.GetMinExtent(minExtent, windowIsResizingIt);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sRes}
PROCEDURE {TWindow.}GetTitle{(VAR title: S255)};
VAR kludge: Str255;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
GetFldrTitle(POINTER(SELF.wmgrID), kludge);
title := kludge;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sStartup}
PROCEDURE {TWindow.}Highlight{(highTransit: THighTransit)};
PROCEDURE HilitePanel(obj: TObject);
BEGIN
TPanel(obj).Highlight(TPanel(obj).selection, highTransit);
END;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.panels.Each(HilitePanel);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sRes}
PROCEDURE {TWindow.}IdleBegin{(centiSeconds: LONGINT)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
LetOthersRun;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TWindow.}IdleContinue{(centiSeconds: LONGINT)};
BEGIN
{$IFC fTrace}BP(5);{$ENDC}
IF SELF.IsActive THEN
process.TrackCursor;
LetOthersRun;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TWindow.}IdleEnd{(centiSeconds: LONGINT)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S sStartup}
FUNCTION {TWindow.}IsActive{: BOOLEAN};
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
IF activeWindowID = 0 THEN {nothing is active}
IsActive := FALSE
ELSE IF currentWindow = NIL THEN
BEGIN
IsActive := FALSE;
{$IFC fDbgABC}
Writeln(CHR(7), '********************');
Writeln('In TWindow.IsActive, activeWindowID <> 0 AND currentWindow = NIL');
Writeln('activeWindowID=', activeWindowID:1, '
currentWindow=', ORD(currentWindow):1);
Writeln('********************');
{$ENDC}
END
ELSE
IsActive := (SELF.wmgrID = activeWindowID) OR (SELF.wmgrID = ORD(dialogFolder));
{$IFC fTrace}EP;{$ENDC}
END;
{$S sStartup}
FUNCTION {TWindow.}IsVisible{: BOOLEAN};
VAR info:
WindowInfo;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
GetWindInfo(WindowPtr(SELF.wmgrID), info);
IsVisible := info.visible;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sStartup}
PROCEDURE {TWindow.}LoadMenuBar;
VAR i:
INTEGER;
menuID:
INTEGER;
inClipboard:
BOOLEAN;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
inClipboard := activeWindowID = ORD(scrapFolder);
FOR i := 1 TO menuBar.numMenus DO
BEGIN
menuID := wmgrMenus[i].menuID;
IF SELF.WantMenu(menuID, inClipboard) THEN
menuBar.Insert(menuID, 0);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sRes}
PROCEDURE {TWindow.}MenuEventAt{(mousePt: Point)};
VAR cmdNumber: TCmdNumber;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.SetupMenus;
cmdNumber := menuBar.DownAt(mousePt);
IF SELF.selectPanel = NIL THEN
{$IFC fDbgABC} ABCBreak('ObeyTheEvent: selectPanel=NIL', 0) {$ENDC}
ELSE
SELF.DoCommand(cmdNumber);
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC LibraryVersion > 20}
{$S SgABCcld}
PROCEDURE {TWindow.}NameToPrefix(VAR error, offset: INTEGER; VAR name, prefix: TFilePath);
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
NameToPrefix(error, offset, WindowPtr(SELF.wmgrID), Pathname(name), Pathname(prefix));
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$ENDC}
{$S sCommand}
FUNCTION {TWindow.}NewCommand{(cmdNumber: TCmdNumber): TCommand};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
NewCommand := currentWindow.NewStdCommand(cmdNumber);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCommand}
FUNCTION {TWindow.}NewStdCommand{(cmdNumber: TCmdNumber): TCommand};
VAR document:
TDocManager;
didStyleChange: BOOLEAN;
{$IFC LibraryVersion <= 20}
prPrf:
TPrPrf;
{$ENDC}
prPrfAlias:
TprPrfAlias;
shouldPrint:
BOOLEAN;
error:
INTEGER;
str:
S255;
permCmd:
BOOLEAN;
{ TRUE iff the command is a permanent one }
command:
TCommand;
s:
TListScanner;
panel:
TPanel;
zoomNum:
Point;
zoomDen:
Point;
selectPanel:
TPanel;
clickPanel:
TPanel;
selection:
TSelection;
vhs:
VHSelect;
andContinue:
BOOLEAN;
excessBytes:
INTEGER;
printManager:
TPrintManager;
panelToUse:
TPanel;
FUNCTION RevertConfirmed: BOOLEAN;
VAR s:
TParamAlert;
ph:
INTEGER;
{$IFC LibraryVersion <= 20}
{$ELSEC}
{$ENDC}
info:
fs_info;
info:
Q_Info;
osErr:
pPath:
osDT:
INTEGER;
^Pathname;
LONGINT;
BEGIN
RevertConfirmed := FALSE;
IF SELF.changes = 0 THEN
process.Note(phUnchanged)
ELSE
BEGIN
IF document.files.saveExists THEN
BEGIN
pPath := @document.files.volumePrefix;
{$IFC LibraryVersion <= 20}
Lookup(osErr, pPath^, info);
{$ELSEC}
Quick_Lookup(osErr, pPath^, info);
{$ENDC}
IF osErr <= 0 THEN
osDT := info.DTM
ELSE
osDT := -1;
{$IFC LibraryVersion < 13}
DTAlert(osDT, s);
{$ELSEC}
DTAlert(alerts, osDT, s);
{$ENDC}
process.ArgAlert(1, s);
ph := phRevert;
END
ELSE
ph := phRevBlank;
IF process.Caution(ph) THEN
RevertConfirmed := TRUE;
END;
END;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
document := currentDocument;
{$IFC fDbgABC}
IF SELF.wmgrID <> document.window.wmgrID THEN
ABCbreak('In TWindow.NewStdCommand: SELF.wmgrID <> document.window.wmgrID; document=',
ORD(document));
{$ENDC}
selectPanel := SELF.selectPanel;
clickPanel := SELF.clickPanel;
selection := selectPanel.selection;
IF selectPanel.view.isPrintable THEN
panelToUse := selectPanel
ELSE
panelToUse := SELF.panelToPrint;
error := 0;
NewStdCommand := NIL; {the default return value}
permCmd := FALSE; {if set to TRUE, make a permanent command object}
allowAbort := TRUE; {??? should we assume this ???}
CASE cmdNumber OF
{File/Print Menu}
uSetAllAside:
BEGIN
SELF.CommitLast;
DoFilingCmd(cmdClosAll);
permCmd := TRUE;
END;
uSetAside, uSetClipAside:
BEGIN
SELF.CommitLast;
DoFilingCmd(cmdClose);
permCmd := TRUE;
END;
uPutAway, uSaveVersion: {must be the active window to do this}
BEGIN
andContinue := cmdNumber = uSaveVersion;
SELF.CommitLast;
IF andContinue THEN
excessBytes := docExcess
ELSE
excessBytes := 0;
document.ConserveMemory(excessBytes, TRUE {do GC});
IF (document.window.changes <> 0) AND
(document.files.shouldToolSave OR NOT document.openedAsTool) THEN
BEGIN
process.BeginWait(phSaving);
document.SaveVersion(error, document.files.volumePrefix, andContinue);
process.EndWait;
END
uPrFmt:
BEGIN
IF document = clipboard THEN
prPrfAlias.reserve := clipPrintPref
ELSE
prPrfAlias.reserve := document.dataSegment.preludePtr^.printPref;
PushFocus;
uRiseHorizontally:
BEGIN
IF cmdNumber = uRiseVertically THEN
panelToUse.view.printManager.pageRiseDirection := v
ELSE
panelToUse.view.printManager.pageRiseDirection := h;
IF panelToUse.previewMode = mPrvwMargins THEN
panelToUse.Invalidate;
END;
uAddColumnStrip,
uAddRowStrip:
BEGIN
IF cmdNumber = uAddColumnStrip THEN
vhs := v
ELSE
vhs := h;
panelToUse.currentView.AddStripOfPages(vhs);
END;
uShowFullSize:
BEGIN
SetPt(zoomNum, 1, 1);
selectPanel.SetZoomFactor(zoomNum, zoomNum);
selectPanel.Invalidate;
END;
uReduce70Pct:
BEGIN
WITH selectPanel.zoomFactor DO
IF numerator.h = 1 THEN
BEGIN
zoomNum.h := 7;
zoomDen.h := denominator.h * 10;
zoomNum.v := 7;
zoomDen.v := denominator.v * 10;
END
ELSE {numerator not 1, must be 7}
BEGIN
zoomNum.h := 1;
zoomDen.h := denominator.h DIV 5;
zoomNum.v := 1;
zoomDen.v := denominator.v DIV 5;
END;
selectPanel.SetZoomFactor(zoomNum, zoomDen);
selectPanel.Invalidate;
END;
uReduceToFit:
{?} {can't do it now--how to express?} ;
uSetHorzBreak:
IF clickPanel.view.isPrintable THEN
BEGIN
clickPanel.view.printManager.SetBreak(h, clickPanel.view.clickLPt.v, FALSE);
clickPanel.currentView.ReDoBreaks;
clickPanel.Invalidate;
END;
uSetVertBreak:
IF clickPanel.view.isPrintable THEN
BEGIN
clickPanel.view.printManager.SetBreak(v, clickPanel.view.clickLPt.h, FALSE);
clickPanel.currentView.ReDoBreaks;
clickPanel.Invalidate; {later, do a more selective inval}
END;
uClearBreaks:
IF clickPanel.view.isPrintable THEN
BEGIN
clickPanel.view.printManager.ClearPageBreaks(FALSE);
clickPanel.currentView.ReDoBreaks;
clickPanel.Invalidate; {later, do a more selective inval}
END;
{$IFC fDbgABC}
{Debug Menu}
uReportEvents:
SELF.ToggleFlag(eventDebug);
uCountHeap:
SELF.ToggleFlag(fCountHeap);
uCheckIndices:
SELF.ToggleFlag(fCheckIndices);
uDumpGlobals:
{dump process variables}
process.DumpGlobals;
uDumpPrelude:
{dump active document's prelude}
document.DumpPrelude;
uExperimenting:
SELF.ToggleFlag(fExperimenting);
uReptGarbage, uFreeGarbage:
IF document <> clipboard THEN
BEGIN
MarkHeap(document.docHeap, ORD(document.dataSegment.preludePtr^.docDirectory));
SweepHeap(document.docHeap, cmdNumber = uReptGarbage);
END;
uMainScramble:
IF newCommand <> NIL THEN {this is a command that changes the document}
BEGIN
{commit the previous command}
SELF.CommitLast;
{save the new command & get rid of the old one}
SELF.SaveCommand(newCommand);
{execute the new command}
SELF.PerformLast(doPhase);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sCommand}
PROCEDURE {TWindow.}PerformLast{(cmdPhase: TCmdPhase)}; {+SW+} {LSR: Your version below, commented out}
VAR image:
TImage;
lastCmd:
TCommand;
lastWindow: TWindow;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF <> currentWindow THEN
currentWindow.PerformLast(cmdPhase)
ELSE
BEGIN
lastCmd := SELF.lastCmd;
image := lastCmd.image;
IF image = NIL THEN
lastWindow := SELF
ELSE
lastWindow := image.view.panel.window; {+SW+}
{UnHighlight all selections before performing the command (unless command object says otherwise)}
IF lastCmd.unHiliteBefore[cmdPhase] THEN
currentWindow.selectWindow.Highlight(hOnToOff); {+sw+}
IF cmdPhase <> doPhase THEN
lastWindow.RestoreSelection;{+sw+}
IF lastCmd.revelation <> revealNone THEN
lastWindow.RevealSelection(lastCmd.revelation = revealAll,
NOT lastCmd.unHiliteBefore[cmdPhase]);
lastWindow.selectPanel.selection.PerformCommand(lastCmd, cmdPhase);
{+sw+}
SELF.SaveSelection;
IF NOT deferUpdate THEN
IF lastCmd.HiliteAfter[cmdPhase] THEN
BEGIN
lastWindow.Update(FALSE);{+sw+}
lastWindow.Highlight(hOffToOn);{+sw+}
END
ELSE
lastWindow.Update(TRUE);{+sw+}
END;
{$IFC fTrace}EP;{$ENDC}
END;
(*
*)
currentWindow.PerformLast(cmdPhase)
ELSE
BEGIN
lastCmd := SELF.lastCmd;
PerformIt;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sStartup}
PROCEDURE {TWindow.}PickStdCursor;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SetStdCursor(arrowCursor);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
document := currentDocument
ELSE
document := boundDocument;
IF document = clipboard THEN
prPrfAlias.reserve := clipPrintPref
ELSE
prPrfAlias.reserve := document.dataSegment.preludePtr^.PrintPref;
PushFocus;
{$IFC libraryVersion <= 20}
{ P E P S I }
indeedPrint := FPrInsDlg(error, prPrfAlias.prPrf, prPrfAlias.prIns, isNewStyle);
{$ELSEC}
{ S P R I N G }
IF nixWholeDialog THEN
prMode := ePrDialogSuppress
ELSE
IF nixPgRange THEN
prMode := ePgRangeSuppress
ELSE
prMode := ePrNormal;
{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
(*
{$S SgABCcld}
PROCEDURE {TWindow.}PutUpDialogBox{(dialogBox: TDialogBox)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.CommitLast;
SELF.dialogBox := dialogBox;
IF dialogBox.selectWindow <> NIL THEN
SELF.selectWindow := dialogBox.selectWindow; *) {+SW+}
dialogBox.Appear;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sStartup}
PROCEDURE {TWindow.}Refresh{(rActions: TActions; highTransit: THighTransit)};
PROCEDURE RefreshPanel(obj: TObject);
VAR panel: TPanel;
BEGIN
panel := TPanel(obj);
IF RectIsVisible(panel.outerRect) THEN
panel.Refresh(rActions, highTransit);
END;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF = clipboard.window THEN
highTransit := hNone;
{$IFC fDbgABC}
IF (rBackground IN rActions) AND (highTransit > hOffToOn) THEN
ABCBreak('Refresh: rBackground requested, but highTransit does not start from Off', 0);
{$ENDC}
IF rFrame IN rActions THEN
SELF.Frame;
SELF.panels.Each(RefreshPanel);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sStartup}
PROCEDURE {TWindow.}Resize{(moving: BOOLEAN)};
{Make the Tool Kit data structures agree with the window manager's idea of the window size;
also, ensure that bottom right corner of window is on the screen}
VAR oldOuterRect:
Rect;
myGrafPort:
GrafPtr;
newScreenRect:
Rect;
proposedSize:
Point;
minExtent:
Point;
newOuterRect:
Rect;
currentlyVisible:
BOOLEAN;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
PushFocus;
SELF.Focus;
currentlyVisible := SELF.IsVisible;
myGrafPort:= POINTER(SELF.wmgrID);
IF currentlyVisible THEN
BEGIN
{ Find out where the window is on the screen }
newScreenRect := myGrafPort^.portRect;
proposedSize := Point(FDiagRect(newScreenRect));
IF NOT SELF.believeWmgr THEN
WITH SELF DO
BEGIN
maxInnerSize := proposedSize;
believeWmgr := TRUE;
END;
IF moving THEN { Constrain it to the maximum explicitly set by the user }
BEGIN
LocalToGlobal(newScreenRect.topLeft);
{ Propose the window botRight be at the screen botRight }
proposedSize := Point(FPtMinPt(Point(FPtMinusPt(screenBits.bounds.botRight,
newScreenRect.topLeft)),
SELF.maxInnerSize));
END;
END
ELSE
proposedSize := Point(FDiagRect(SELF.innerRect));
{ But be sure it is at least the minimum size }
SELF.GetMinExtent(minExtent, TRUE);
proposedSize := Point(FPtMaxPt(proposedSize, minExtent));
IF NOT moving THEN
SELF.maxInnerSize := proposedSize;
oldOuterRect := SELF.outerRect;
SetRect(newScreenRect, 0, 0, proposedSize.h, proposedSize.v);
IF currentlyVisible THEN
{ finally set the wmgr window ("folder") size. }
FolderSize(myGrafPort, proposedSize.h, proposedSize.v, FALSE);
{ Reset our idea of window's size }
SELF.SetInnerRect(newScreenRect);
ClipRect(SELF.innerRect);
focusRgn := thePort^.visRgn;
newOuterRect := SELF.outerRect;
IF NOT EqualPt(oldOuterRect.botRight, newOuterRect.botRight) THEN
SELF.panelTree.ResizeOutside(newOuterRect);
PopFocus;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
PROCEDURE {TWindow.}ResizeTo{(newSize: Point)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF NOT EqualPt(Point(FDiagRect(SELF.innerRect)), newSize) THEN
BEGIN
FolderSize(POINTER(SELF.wmgrID), newSize.h, newSize.v, FALSE);
SELF.Resize(FALSE);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sRes}
PROCEDURE {TWindow.}RestoreSelection;
PROCEDURE RestoreSel(obj: TObject);
BEGIN
TPanel(obj).undoSelection.Restore;
END;
{$}
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.selectPanel := SELF.undoSelPanel;
SELF.clickPanel := SELF.undoClickPanel;
SELF.selectWindow := SELF.undoSelWindow; {+SW+}
SELF.panels.Each(RestoreSel);
IF SELF.dialogBox <> NIL THEN
SELF.dialogBox.RestoreSelection;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCommand}
PROCEDURE {TWindow.}RevealSelection(asMuchAsPossible, doHilite: BOOLEAN);
PROCEDURE RevlSel(obj: TObject);
BEGIN
TPanel(obj).selection.Reveal(asMuchAsPossible);
END;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.Update(doHilite);
SELF.panels.Each(RevlSel);
SELF.Update(doHilite);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCommand}
PROCEDURE {TWindow.}SaveCommand{(command: TCommand)};
PROCEDURE SaveUndoSelection(obj: TObject);
VAR panel: TPanel;
sel:
TSelection;
BEGIN
panel := TPanel(obj);
sel := panel.undoSelection.FreedAndReplacedBy(TSelection(panel.selection.Clone(SELF.Heap)));
END;
BEGIN {Called by PerformCommand between NewCommand & PerformLast to establish an undo-point}
{$IFC fTrace}BP(7);{$ENDC}
IF SELF <> currentWindow THEN
currentWindow.SaveCommand(command) {probably this is a dialog box}
ELSE
IF SELF.lastCmd <> NIL THEN
SELF.lastCmd.Become(command)
ELSE
SELF.lastCmd := command;
SELF.panels.Each(SaveUndoSelection);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCommand}
PROCEDURE {TWindow.}SaveSelection;
PROCEDURE SaveSel(obj: TObject);
BEGIN
TPanel(obj).selection.Save;
END;
{$}
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.panels.Each(SaveSel);
SELF.undoSelPanel := SELF.selectPanel;
SELF.undoClickPanel := SELF.clickPanel;
SELF.undoSelWindow := SELF.selectWindow; {+SW+}
IF SELF.dialogBox <> NIL THEN
SELF.dialogBox.SaveSelection;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCommand}
PROCEDURE {TWindow.}SetupMenus;
VAR anS255:
S255;
undoTempl: TCmdNumber;
mapHandle: TMapHandle;
selection: TSelection;
i:
INTEGER;
wmgrCmd:
TWmgrCmd;
checkIt:
BOOLEAN;
mainWindow: TWindow;
BEGIN {NOTE: wmgrMenus[menuIndex] can not be assigned to a local variable because it is passed as a VAR}
{$IFC fTrace}BP(5);{$ENDC}
mainWindow := currentWindow;
{First, change the text of the Set Aside and Undo items.}
mainWindow.GetTitle(anS255); {don't use SELF because we might be a dialog box}
anS255 := CONCAT('"', anS255, '"');
menuBar.BuildCmdName(uSetAside, utSetAside, @anS255);
menuBar.BuildCmdName(uSetClipAside, utSetAside, @anS255);
IF mainWindow.lastCmd = NIL THEN {the mainWindow always has the last command}
menuBar.BuildCmdName(uUndoLast, utUndoLast, NIL)
ELSE
BEGIN
IF mainWindow.lastCmd.doing THEN
undoTempl := utUndoLast
ELSE
undoTempl := utRedoLast;
IF menuBar.GetCmdName(mainWindow.lastCmd.cmdNumber, @anS255) THEN
BEGIN
anS255 := CONCAT('"', anS255, '"');
menuBar.BuildCmdName(uUndoLast, undoTempl, @anS255);
END
ELSE
menuBar.BuildCmdName(uUndoLast, undoTempl, NIL);
END;
{Then enable and check the appropriate items}
mapHandle := TMapHandle(menuBar.mapping);
selection := SELF.selectPanel.selection;
FOR i := 1 TO menuBar.numCommands DO
BEGIN
wmgrCmd := mapHandle^^.table[i];
WITH wmgrCmd DO
IF menuBar.isLoaded[menuIndex] THEN
BEGIN
checkIt := FALSE;
(**********
IF selection.CanDoCommand(cmdNumber, checkIt) THEN
EnableItem(wmgrMenus[menuIndex], itemIndex)
ELSE
DisableItem(wmgrMenus[menuIndex], itemIndex);
**********)
{The following line is an optimization for the preceding}
wmgrMenus[menuIndex].enableFlags[itemIndex] :=
selection.CanDoCommand(cmdNumber, checkit);
CheckItem(wmgrMenus[menuIndex], itemIndex, checkIt);
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCini}
PROCEDURE {TWindow.}SetWmgrId{(itsWmgrId: TWindowID)};
VAR panelScanner:
TListScanner;
panel:
TPanel;
paneScanner:
TListScanner;
pane:
TPane;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.wmgrId := itsWmgrId;
panelScanner := SELF.panels.Scanner;
WHILE panelScanner.Scan(panel) DO
BEGIN
paneScanner := panel.panes.Scanner;
WHILE paneScanner.Scan(pane) DO
pane.port := POINTER(itsWmgrId);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
PROCEDURE {TWindow.}StashPicture{(highTransit: THighTransit)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
RectRgn(altVisRgn, SELF.outerRect);
useAltVisRgn := TRUE;
{Make TPad.Focus use altVisRgn instead of visRgn}
PushFocus;
SELF.Focus;
WMOpenPicture(POINTER(SELF.wmgrID));
SELF.Refresh([rErase, rFrame, rBackground, rDraw], highTransit); {recorded & not displayed}
WMClosePicture;
useAltVisRgn := FALSE;
PopFocus;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
PROCEDURE {TWindow.}TakeDownDialogBox; {+sw+}
VAR dialogBox: TDialogBox;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
{Don't CommitLast here, because the Dialog Box may have created a command that can be undone later}
dialogBox := SELF.dialogBox;
IF dialogBox <> NIL THEN
BEGIN
BEGIN
{$IFC fDbgABC} ABCbreak('TCommand.cmdNumber not in menu', lastCmd.cmdNumber); {$ENDC}
str := 'Last Command';
END;
process.ArgAlert(1, str);
process.Stop(phCantUndo);
END
ELSE
IF lastCmd.doing THEN
SELF.PerformLast(undoPhase)
ELSE
SELF.PerformLast(redoPhase);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sStartup}
PROCEDURE {TWindow.}Update{(doHilite: BOOLEAN)};
VAR pWindow:
WindowPtr;
updateRgn:
RgnHandle;
highTransit:
THighTransit;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
PushFocus;
SELF.Focus;
pWindow := POINTER(SELF.wmgrID);
BeginUpdate(pWindow);
updateRgn := pWindow^.visRgn;
IF NOT EmptyRgn(updateRgn) THEN
BEGIN
IF doHilite THEN
highTransit := highLevel[SELF.isActive]
ELSE
highTransit := hNone;
FillRgn(updateRgn, white);
SELF.Refresh([rFrame, rBackground, rDraw], highTransit);
END;
EndUpdate(pWindow);
PopFocus;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sStartup}
FUNCTION {TWindow.}WantMenu{(menuID: INTEGER; inClipboard: BOOLEAN): BOOLEAN};
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
IF inClipboard THEN
WantMenu := menuID = mnuClipFilePrint
ELSE
WantMenu := (menuID < mBuzzword);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCini}
END;
{$S SgABCres}
METHODS OF TDialogBox;
{$S SgABCcld}
FUNCTION {TDialogBox.}CREATE{(object: TObject; heap: THeap; itsResizability: BOOLEAN; itsHeight: INTEGER;
itsKeyResponse, itsMenuResponse,
itsDownInMainWindowResponse: TDiResponse): TDialogBox};
VAR diBxRect: Rect;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TDialogBox(TWindow.CREATE(object, heap, ORD(dialogFolder), itsResizability));
WITH SELF DO
BEGIN
keyResponse := itsKeyResponse;
menuResponse := itsMenuResponse;
downInMainWindowResponse := itsDownInMainWindowResponse;
freeOnDismissal := FALSE; {+SW+}
END;
SELF.GetPrinterMetrics; {mostly just so that these won't be total garbage in debug output}
SetRect(diBxRect, 0, 0, screenBits.bounds.right, itsHeight);
SELF.SetInnerRect(diBxRect);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TDialogBox.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
TWindow.Fields(Field);
Field('keyResponse: Byte');
Field('menuResponse: Byte');
Field('downInMainWindowResponse: Byte');
Field('freeOnDismissal: BOOLEAN'); {+SW+}
Field('');
END;
{$S SgABCres}
{$ENDC}
{$S SgABCcld}
PROCEDURE {TDialogBox.}Appear;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
DialogHeight(LengthRect(SELF.innerRect, v), TRUE);
SELF.outerRect.bottom := SELF.outerRect.top; {force Resize to recalculate everything}
SELF.Resize(FALSE);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCcld}
PROCEDURE {TDialogBox.}BeDismissed;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
currentWindow.TakeDownDialogBox;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCcld}
PROCEDURE {TDialogBox.}Disappear;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
DialogHeight(0, FALSE);
SELF.believeWmgr := FALSE; {the window's innerRect is known to NOT match the size of the dialog box}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCcld}
PROCEDURE {TDialogBox.}GetMinExtent{(VAR minExtent: Point; windowIsResizingIt: BOOLEAN)};
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
SUPERSELF.GetMinExtent(minExtent, windowIsResizingIt);
minExtent.h := screenBits.bounds.right;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
FUNCTION {TDialogBox.}IsVisible{: BOOLEAN};
VAR info:
WindowInfo;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
IF SUPERSELF.IsVisible THEN
IsVisible := currentWindow.dialogBox = SELF
ELSE
IsVisible := FALSE;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCini}
END;
{$S SgABCres}
{SUBROUTINES OF TMenuBar}
{$S sRes}
PROCEDURE InAllMenusDo{(iffLoaded: BOOLEAN; theCommand: TCmdNumber;
PROCEDURE doProc(VAR menu: MenuInfo; itemIndex: INTEGER))};
VAR i:
INTEGER;
lowIDX:
INTEGER;
highIDX:
INTEGER;
mapHandle: TMapHandle;
fFound:
BOOLEAN;
BEGIN
fFound := FALSE;
mapHandle := TMapHandle(menuBar.mapping);
lowIDX := 1;
highIDX := menuBar.numCommands;
WHILE NOT fFound AND (lowIdx <= highIdx) DO
BEGIN
i := (lowIDX+highIDX) DIV 2;
{$R-} WITH mapHandle^^.table[i] DO {$IFC fRngABC}{$R+}{$ENDC} { OK to do this because once
we call doProc, we don't refer to this record any more }
IF theCommand = cmdNumber THEN
BEGIN
END;
fFound := TRUE;
IF menuBar.isLoaded[menuIndex] = iffLoaded THEN
doProc(wmgrMenus[menuIndex], itemIndex);
END
ELSE
IF theCommand > cmdNumber THEN
lowIDX := i+1
ELSE
highIDX := i-1;
END;
{$S sCommand}
FUNCTION CmdFromWmgr(menuId, itemIndex: INTEGER): TCmdNumber;
VAR wmgrCmd:
TWmgrCmd;
cmdNumber: TCmdNumber;
i:
INTEGER;
mapHandle: TMapHandle;
BEGIN {does not need to be very fast}
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
IF itemIndex < 0 THEN
CmdFromWmgr := -itemIndex {this is how we will implement graphical menus}
ELSE
BEGIN
mapHandle := TMapHandle(menuBar.mapping);
FOR i := 1 TO menuBar.numCommands DO
BEGIN
{$R-}
wmgrCmd := mapHandle^^.table[i];
{$IFC fRngABC}{$R+}{$ENDC}
IF wmgrCmd.itemIndex = itemIndex THEN
IF menuBar.isLoaded[wmgrCmd.menuIndex] THEN
IF wmgrMenus[wmgrCmd.menuIndex].menuId = menuId THEN
BEGIN
CmdFromWmgr := wmgrCmd.cmdNumber;
EXIT(CmdFromWmgr);
END;
END;
CmdFromWmgr := 0;
END;
END;
{$S sRes}
FUNCTION FindMenu(menuID: INTEGER): INTEGER;
{ given a menuID (the number in the phrase file) return the menuIndex into
SELF.mapping := mapping;
numCommands := mapping.Size;
SELF.numCommands := numCommands;
InitErrorAbort(itsScanner.error);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TMenuBar.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
Field('isLoaded: ARRAY [1..31] OF BOOLEAN');
(* MaxMenus = 31 *)
Field('mapping: TArray');
Field('numMenus: INTEGER');
Field('numCommands: INTEGER');
END;
{$S SgABCres}
{$ENDC}
{$S sRes}
PROCEDURE {TMenuBar.}BuildCmdName{(destCmd, templateCmd: TCmdNumber; param: TPString)};
VAR templ: S255;
xStart: INTEGER;
xEnd:
INTEGER;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
IF SELF.GetCmdName(templateCmd, @templ) THEN
BEGIN
xStart := POS('^', templ);
IF xStart > 0 THEN
BEGIN
DELETE(templ, xStart, 1);
xEnd := POS('^', templ);
IF xEnd > 0 THEN
DELETE(templ, xEnd,1)
ELSE
xEnd := LENGTH(templ) + 1;
IF param <> NIL THEN
BEGIN
DELETE(templ, xStart, xEnd-xStart);
INSERT(param^, templ, xStart);
END;
END;
SELF.PutCmdName(destCmd, @templ);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TMenuBar.}Check{(cmdNumber: TCmdNumber; checked: BOOLEAN)};
Label 1;
PROCEDURE DoCheck(VAR menu: MenuInfo; itemIndex: INTEGER);
BEGIN
CheckItem(menu, itemIndex, checked);
Goto 1;
END;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
InAllMenusDo(TRUE, cmdNumber, DoCheck);
1: {$IFC fTrace}EP;{$ENDC}
END;
{$S sCommand}
FUNCTION {TMenuBar.}CmdKey{(ch: CHAR): TCmdNumber};
VAR menuId, itemIndex: INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
MenuKey(ch, menuId, itemIndex);
if menuId <> 0 THEN
HiLiteMenu(menuId);
CmdKey := CmdFromWmgr(menuId, itemIndex);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TMenuBar.}Delete{(menuID: INTEGER)};
VAR menuIndex: INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
DeleteMenu(menuId);
menuIndex := FindMenu(menuID);
IF menuIndex > 0 THEN
SELF.isLoaded[menuIndex] := FALSE;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCommand}
FUNCTION {TMenuBar.}DownAt{(mousePt: Point): TCmdNumber};
VAR menuId, itemIndex: INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
process.ChangeCursor(arrowCursor);
MenuSelect(mousePt, menuId, itemIndex);
if menuId <> 0 THEN
HiLiteMenu(menuId);
DownAt := CmdFromWmgr(menuId, itemIndex);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sStartup}
PROCEDURE {TMenuBar.}Draw;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
DrawMenuBar;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TMenuBar.}Enable{(cmdNumber: TCmdNumber; canBeChosen: BOOLEAN)};
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
IF canBeChosen THEN
InAllMenusDo(TRUE, cmdNumber, EnableItem)
ELSE
InAllMenusDo(TRUE, cmdNumber, DisableItem);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TMenuBar.}EndCmd;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
HiLiteMenu(0);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
FUNCTION {TMenuBar.}GetCmdName{(cmdNumber: TCmdNumber; pName: TPString): BOOLEAN};
Label 1;
PROCEDURE DoGet(VAR menu: MenuInfo; itemIndex: INTEGER);
1:
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCcld}
FUNCTION {TMenuBar.}MenuWithID(menuID: INTEGER): Ptr;
VAR menuIndex: INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
menuIndex := FindMenu(menuID);
IF menuIndex > 0 THEN
MenuWithId := @wmgrMenus[menuIndex]
ELSE
MenuWithID := NIL;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TMenuBar.}PutCmdName{(cmdNumber: TCmdNumber; pName: TPString)};
Label 1;
VAR kludge: Str255;
PROCEDURE DoPut(VAR menu: MenuInfo; itemIndex: INTEGER);
BEGIN
SetItem(menu, itemIndex, @kludge);
Goto 1;
END;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
XferLeft(POINTER(ORD(pName)), @kludge, LENGTH(pName^)+1);
InAllMenusDo(TRUE, cmdNumber, DoPut);
InAllMenusDo(FALSE, cmdNumber, DoPut);
1: {$IFC fTrace}EP;{$ENDC}
END;
(**********
{$S SgABCini}
PROCEDURE {TMenuBar.}SetupGrMenu(menuID: INTEGER; width, height: INTEGER;
newChooseProc, newDrawProc: Ptr);
{if either proc is NIL, don't change the current value;
if either width or height is <= 0, don't change the current value;
when the menu is first read in, it is setup to behave like a standard text menu}
VAR menuIndex: INTEGER
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
menuIndex := FindMenu(menuID);
IF menuIndex > 0 THEN
WITH wmgrMenus[menuIndex] DO
BEGIN
IF width > 0 THEN
menuWidth := width;
IF height > 0 THEN
menuHeight := height;
IF newChooseProc <> NIL THEN
chooseProc := newChooseProc;
IF newDrawProc <> NIL THEN
drawProc := newDrawProc;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
**********)
{$S sRes}
PROCEDURE {TMenuBar.}Unload;
VAR i: INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
ClearMenuBar;
FOR i := 1 TO SELF.numMenus DO
SELF.isLoaded[i] := FALSE;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCini}
END;
{$S SgABCres}
{$IFC LibraryVersion <= 20 AND FALSE} {do it this way in case we need it back for the Pepsi version}
METHODS OF TFont;
{$S SgABCini}
FUNCTION {TFont.}CREATE{(object: TObject; heap: THeap; itsFamily: INTEGER): TFont};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TFont(object);
SELF.family := itsFamily;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TFont.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
Field('family: INTEGER');
END;
{$S SgABCres}
{$ENDC}
{$S SgABCini}
END;
{$S SgABCres}
{$ENDC}
{$S sCldInit}
PROCEDURE InvalDiffRect(r1, r2: Rect); {invalidate r1 - r2}
VAR dummyRect: Rect;
rgn1:
RgnHandle;
rgn2:
RgnHandle;
BEGIN
{$IFC fTrace}BP(5);{$ENDC}
IF EmptyRect(r1) THEN
{nothing to do}
ELSE IF SectRect(r1, r2, dummyRect) THEN
BEGIN
rgn1 := NewRgn;
rgn2 := NewRgn;
RectRgn(rgn1, r1);
RectRgn(rgn2, r2);
DiffRgn(rgn1, rgn2, rgn1);
InvalRgn(rgn1);
DisposeRgn(rgn1);
DisposeRgn(rgn2);
END
ELSE
InvalRect(r1);
{$IFC fTrace}EP;{$ENDC}
END;
METHODS OF TPanel;
{$S SgABCini}
FUNCTION
END;
SELF.zoomed := FALSE;
WITH SELF.zoomFactor DO
{$H-} BEGIN
SetPt(numerator, 1, 1);
SetPt(denominator, 1, 1);
{$H+} END;
SELF.SetOuterRect(itsWindow.outerRect);
noPad.RectToLRect(SELF.innerRect, viewedLRect);
panes := TList.CREATE(NIL, heap, 1);
SELF.panes := panes;
aPane := SELF.NewPane(heap, SELF.innerRect, viewedLRect);
WITH SELF.lastClick DO
BEGIN
gotPane := TRUE;
clickPane := aPane;
END;
SELF.panes.InsLast(aPane);
bandOuterRect := SELF.innerRect;
InsetRect(bandOuterRect, -1, -1);
FOR vhs := v TO h DO
BEGIN
scrollBar := TScrollBar.CREATE(NIL, heap, vhs, bandOuterRect, aBar IN SELF.abilities[vhs]);
SELF.scrollBars[vhs] := scrollBar;
scroller := scrollBar.firstBox;
band := SELF.NewBand(heap, SELF.innerRect, scroller, vhs);
band.panes.InsLast(SELF.panes.First);
bandList := TList.CREATE(NIL, heap, 1);
bandList.InsLast(band);
SELF.bands[vhs] := bandList;
END;
IF itsWindow.panelTree = NIL THEN {The first panel gets inserted automatically}
BEGIN
itsWindow.panelTree := SELF;
itsWindow.panels.InsLast(SELF);
itsWindow.selectPanel := SELF;
itsWindow.clickPanel := SELF;
SELF.DecideAboutBars(SELF.outerRect);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCini}
PROCEDURE {TPanel.}Free;
VAR vhs: VHSelect;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
Free(SELF.selection);
Free(SELF.undoSelection);
Free(SELF.view);
IF SELF.currentView <> SELF.view THEN
Free(SELF.currentView);
FOR vhs := v TO h DO
BEGIN
SELF.bands[vhs].Free;
SELF.scrollBars[vhs].Free;
END;
SELF.panes.Free;
Free(SELF.deletedSplits);
TArea.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TPanel.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
TArea.Fields(Field);
Field('window: TWindow');
Field('panes: TList');
Field('currentView: TView');
Field('view: TView');
Field('paginatedView: TPaginatedView');
Field('selection: TSelection');
Field('undoSelection: TSelection');
Field('bands: ARRAY [0..1] OF TList');
Field('scrollBars: ARRAY [0..1] OF TScrollBar');
Field('abilities: ARRAY [0..1] OF Byte');
Field('minInnerDiagonal: Point');
Field('resizeBranch: TBranchArea');
Field('zoomed: BOOLEAN');
Field('zoomFactor: RECORD numerator: Point; denominator: Point END');
Field('previewMode: Byte');
Field('');
{$S sRes}
PROCEDURE {TPanel.}BeginSelection;
{+SW+}
VAR thisWindow:
TWindow;
companionWindow:
TWindow;
PROCEDURE DeselPanel(obj: TObject);
BEGIN
TPanel(obj).selection.Deselect;
END;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.BeSelectPanel(TRUE);
thisWindow := SELF.window;
companionWindow := NIL;
IF thisWindow = currentWindow THEN
companionWindow := thisWindow.dialogBox {+SW+}
ELSE
IF thisWindow = currentWindow.dialogBox THEN
IF currentWindow.dialogBox.downInMainWindowResponse = diGiveToMainWindow THEN
companionWindow := currentWindow;
IF companionWindow <> NIL THEN
BEGIN
PushFocus;
companionWindow.Focus;
companionWindow.panels.Each(DeselPanel);
PopFocus;
END;
thisWindow.panels.Each(DeselPanel);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TPanel.}BeSelectPanel{(inSelectWindow: BOOLEAN)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF inSelectWindow THEN
currentWindow.selectWindow := SELF.window;
SELF.window.selectPanel := SELF;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sStartup}
PROCEDURE {TPanel.}CleanUpPanes{(deleteList: TList)};
VAR s:
TListScanner;
pane:
bs:
band:
vhs:
TPane;
TListScanner;
TBand;
VHSelect;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.lastClick.gotPane THEN
IF deleteList.Pos(0, SELF.lastClick.clickPane) > 0 THEN
WITH SELF.lastClick DO
BEGIN
gotPane := FALSE;
clickPt := clickPane.innerRect.topLeft; {+}
END;
s := deleteList.Scanner;
WHILE s.Scan(pane) DO
BEGIN
SELF.panes.DelObject(pane, FALSE);
FOR vhs := v To h DO
BEGIN
bs := SELF.bands[vhs].Scanner;
WHILE bs.Scan(band) DO
band.panes.DelObject(pane, FALSE);
END;
END;
deleteList.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sRes}
PROCEDURE {TPanel.}ComputeContentRect;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
WITH SELF DO
BEGIN
{$H-}
contentRect.topLeft := Point(FPtPlusPt(innerRect.topLeft, tlSideBandSize));
contentRect.botRight := Point(FPtMinusPt(innerRect.botRight, brSideBandSize));
InsetRect(contentRect, 1, 1);
{$H+}
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sStartup}
FUNCTION {TPanel.}CursorAt{(mousePt: Point): TCursorNumber};
VAR pane:
TPane;
nearestPt: Point;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
IF NOT RectHasPt(SELF.outerRect, mousePt) THEN
CursorAt := noCursor
ELSE
IF currentDocument = clipboard THEN
CursorAt := arrowCursor
ELSE
IF RectHasPt(SELF.innerRect, mousePt) THEN
BEGIN
pane := TPane(SELF.ChildWithPt(mousePt, SELF.panes, nearestPt));
CursorAt := pane.CursorAt(mousePt);
END
ELSE
CursorAt := arrowCursor;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCini}
PROCEDURE {TPanel.}DecideAboutBars{(newOuterRect: Rect)};
VAR branch:
TBranchArea;
needsBothBars: BOOLEAN;
vhs:
VHSelect;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
branch := SELF.FindBranchThatIsResized;
SELF.resizeBranch := branch;
needsBothBars := (branch <> NIL) OR
(EqualPt(newOuterRect.botRight, SELF.window.outerRect.botRight) AND SELF.window.isResizable);
FOR vhs := v TO h DO
SELF.scrollBars[vhs].ChangeVisibility(needsBothBars, zeroRect, SELF.abilities[vhs]);
SELF.SetOuterRect(newOuterRect);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
FUNCTION {TPanel.}Divide{(vhs: VHSelect;
fromEdgeOfPanel: INTEGER; units: TUnitsFromEdge;
whoCanResizeIt: TResizability;
minSize: INTEGER; itsVAbilities, itsHAbilities: TAbilities): TPanel};
VAR itsMinInnerDiag:
panel:
Point;
TPanel;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
itsMinInnerDiag := SELF.minInnerDiagonal;
itsMinInnerDiag.vh[vhs] := minSize;
panel := TPanel.CREATE(NIL, SELF.heap, SELF.window,
itsMinInnerDiag.v, itsMinInnerDiag.h, itsVAbilities, itsHAbilities);
SELF.Insert(panel, vhs, fromEdgeOfPanel, units, whoCanResizeIt);
Divide := panel;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sScroll}
PROCEDURE {TPanel.}DoScrolling{(inArea: TArea; itsPane: TPane;
hOk, vOk: BOOLEAN; VAR deltaLPt: LPoint)};
{positive scrolls towards end, (0,0) means invalidate only;
if inArea is a pane then itsPane=inArea
if inArea is a band then itsPane is any one of the band's panes;
hOk & vOk indicate whether scrolling is allowed in that direction;
deltaLPt is set to amount actually scrolled by;
NOTE: assumes we are focused on something at least as big as inArea. }
VAR viewedLRect:
LRect;
resizing:
BOOLEAN;
scrollableLRect:
LRect;
freedomLRect:
LRect;
deltaPt:
Point;
vhs:
VHSelect;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
resizing := EqualLPt(deltaLPt, zeroLPt);
itsPane.GetScrollLimits(viewedLRect, scrollableLRect);
LRectMinusLRect(scrollableLRect, viewedLRect, freedomLRect);
LRectHaveLPt(freedomLRect, deltaLPt);
IF NOT hOk THEN
deltaLPt.h := 0;
IF NOT vOK THEN
deltaLPt.v := 0;
IF NOT EqualLPt(deltaLPt, zeroLPt) THEN
BEGIN
IF resizing OR NOT IsSmallPt(deltaLPt) THEN
InvalRect(inArea.innerRect)
ELSE
BEGIN
itsPane.LDistToDist(deltaLPt, deltaPt);
ScrollRect(inArea.innerRect, -deltaPt.h, -deltaPt.v, scrollRgn);
InvalRgn(scrollRgn);
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
FUNCTION {TPanel.}DownAt{(mousePt: Point): BOOLEAN};
VAR found:
BOOLEAN;
cantDown:
BOOLEAN;
vhs:
VHSelect;
outerRect:
Rect;
innerRect:
Rect;
insetContent:
Rect;
growRect:
Rect;
window:
TWindow;
dialogBox:
TDialogBox;
icon:
TEnumIcons;
scroller:
TScroller;
pane:
TPane;
viewedLRect:
LRect;
hysteresis:
BOOLEAN;
limitRect:
Rect;
hysterPt:
Point;
origPt:
Point;
diffPt:
Point;
nearestPt:
Point;
aheadEvent:
EventRecord;
destPanel:
TPanel;
destView:
TView;
lPtInView:
LPoint;
received:
BOOLEAN;
mouseInContent: BOOLEAN; {TRUE iff mouse is currently in contentRect}
PROCEDURE EnforceHysteresis;
BEGIN
diffPt := Point(FPtMinusPt(mousePt, origPt));
SELF.selection.GetHysteresis(hysterPt);
IF (ABS(diffPt.h) < hysterPt.h) AND (ABS(diffPt.v) < hysterPt.v) THEN
mousePt := origPt
ELSE
hysteresis := FALSE;
END;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
outerRect := SELF.outerRect;
innerRect := SELF.innerRect;
insetContent := SELF.contentRect;
InsetRect(insetContent, 1, 1);
IF NOT RectHasPt(innerRect, mousePt) THEN {+}
BEGIN
found := FALSE;
FOR vhs := v TO h DO
IF NOT found THEN
IF SELF.scrollBars[vhs].DownAt(mousePt, scroller, icon) THEN
BEGIN
SELF.HitScroller(vhs, mousePt, scroller, icon);
found := TRUE;
END;
IF NOT found THEN
BEGIN
SetRect(growRect, innerRect.right + 1, innerRect.bottom + 1,
outerRect.right - 1, outerRect.bottom - 1);
IF RectHasPt(growRect, mousePt) THEN
BEGIN
SELF.DownInSizeBox(mousePt);
found := TRUE;
process.RememberCommand(uResizePanel);
END;
END;
DownAt := found;
END
ELSE
BEGIN
DownAt := TRUE;
IF currentDocument = clipboard THEN
process.Stop(phEditClip)
ELSE
BEGIN
window := SELF.window;
dialogBox := window.dialogBox;
IF dialogBox = NIL THEN
cantDown := FALSE
ELSE
IF dialogBox.downInMainWindowResponse = diDismissDialogBox THEN
BEGIN
dialogBox.BeDismissed;
cantDown := FALSE;
END
ELSE
cantDown := (dialogBox.downInMainWindowResponse = diRefuse);
IF cantDown THEN
process.Stop(phDialogUp)
ELSE
BEGIN
{$IFC fDbgABC}
IF SELF.currentView = NIL THEN
ABCBreak('DownAt with no view set', 0);
{$ENDC}
mouseInContent := RectHasPt(insetContent, mousePt);
pane := TPane(SELF.ChildWithPt(mousePt, SELF.panes, nearestPt));
IF mouseInContent THEN
WITH SELF.lastClick DO
BEGIN
gotPane := TRUE;
clickPane := pane;
END;
process.RememberCommand(uMousePress);
pane.MouseTrack(mPress, mousePt);
IF SELF.selection.canCrossPanels THEN
BEGIN
pane.RectToLRect(window.innerRect, viewedLRect);
WITH pane.origin DO {$H-} {convert to (0,0)-origined view coordinates}
OffsetLRect(viewedLRect, h, v); {$H+}
pane := TPane.CREATE(NIL, SELF.Heap, SELF, window.innerRect, viewedLRect);
PushFocus;
pane.Focus;
SELF.selection.DrawGhost;
PopFocus;
END;
oldTopLeft:
oldBotRight:
vhs:
minPt:
maxPt:
elderFirst:
minExtents:
newBotRight:
newCd:
Point;
Point;
VHSelect;
Point;
Point;
BOOLEAN;
ARRAY [FALSE..TRUE] OF Point;
Point;
INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
branch := SELF.resizeBranch;
IF branch <> NIL THEN
BEGIN
outerRect := branch.outerRect;
oldTopLeft := outerRect.topLeft;
oldBotRight := outerRect.botRight;
vhs := branch.arrangement;
{$IFC fTrace}BP(7);{$ENDC}
{ Find the panel branch of which this is the bottom right corner of the top left child }
child := SELF;
fini := FALSE;
REPEAT
parent := child.parentBranch;
IF parent = NIL THEN
fini := TRUE
ELSE
fini := parent.TopLeftChild = child;
child := parent;
UNTIL fini;
FindBranchThatIsResized := NIL;
IF parent <> NIL THEN
IF userCanResizeIt IN parent.resizability THEN
FindBranchThatIsResized := parent;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sStartup}
PROCEDURE {TPanel.}Frame;
VAR actively:
BOOLEAN;
growRect:
Rect;
branch:
TBranchArea;
vhs:
VHSelect;
{$IFC LibraryVersion > 20}
icon:
Char;
{$ENDC}
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF NOT RectsNest(SELF.innerRect, focusRgn^^.rgnBBox) THEN
BEGIN
TArea.Frame;
actively := SELF.window.IsActive;
IF SELF.scrollBars[v].isVisible OR SELF.scrollBars[h].isVisible THEN
IF NOT EqualPt(SELF.outerRect.botRight, SELF.window.outerRect.botRight) THEN
BEGIN
{Draw the panel's resize box}
SetRect(growRect, SELF.innerRect.right, SELF.innerRect.bottom,
SELF.outerRect.right, SELF.outerRect.bottom);
FillRect(growRect, white);
IF actively THEN
BEGIN
branch := SELF.resizeBranch;
IF branch <> NIL THEN
{Draw a resize icon in the box}
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
band := scroller.band;
CASE icon OF
iSkewer:
BEGIN
scroller.TrackSkewer(mousePt, newSkwrCd, aScroller, prevScroller);
SELF.MoveSplitBefore(scroller, newSkwrCd);
process.RememberCommand(uSplitting);
END;
iThumb:
BEGIN
scroller.TrackThumb(mousePt, oldThumbPos, newThumbPos);
IF oldThumbPos <> newThumbPos THEN
BEGIN
band.ThumbTo(newThumbPos);
scroller.MoveThumb(band.ThumbPos);
END;
process.RememberCommand(uThumbing);
END;
iScrollBack, iScrollFwd, iFlipBack, iFlipFwd:
BEGIN
scroller.FillIcon(icon, TRUE);
SELF.currentView.GetStdScroll(deltaLStd);
SetupMvThumb(POINTER(scroller.sBoxID));
REPEAT
band.ScrollStep(icon, deltaLStd.vh[vhs]);
SELF.window.Update(TRUE);
PenNormal;
MoveThumb(band.ThumbPos);
UNTIL NOT StillDown;
scroller.FillIcon(icon, FALSE);
process.RememberCommand(uScrolling);
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCcld}
PROCEDURE {TPanel.}Insert{(panel: TPanel; vhs: VHSelect;
fromEdgeOfPanel: INTEGER; units: TUnitsFromEdge;
whoCanResizeIt: TResizability)};
VAR window:
elderFirst:
myOuterRect:
mySize:
itsOuterRect:
TWindow;
BOOLEAN;
Rect;
INTEGER;
Rect;
newSize:
cdInWindow:
myFormerParent:
ourNewParent:
INTEGER;
{Proposed length of the new panel (in the vh direction)}
INTEGER;
{the coordinate of myOuterRect that is changing}
TBranchArea;
TBranchArea;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
window := SELF.window;
window.panels.InsLast(panel);
panel.window := window;
elderFirst := fromEdgeOfPanel < 0;
myOuterRect := SELF.outerRect;
mySize := LengthRect(myOuterRect, vhs);
itsOuterRect := myOuterRect;
newSize := ABS(fromEdgeOfPanel);
IF units = percentFromEdge THEN
{convert to pixelsFromEdge}
newSize := LIntDivInt(LIntMulInt(mySize, newSize), 100);
newSize := Max(1, Min(newSize, myOuterRect.botRight.vh[vhs] - myOuterRect.topLeft.vh[vhs] - 1));
IF elderFirst THEN
newSize := -newSize;
cdInWindow := TRectCoords(myOuterRect)[elderFirst].vh[vhs] + newSize;
TRectCoords(myOuterRect)[elderFirst].vh[vhs] := cdInWindow;
TRectCoords(itsOuterRect)[NOT elderFirst].vh[vhs] := cdInWindow;
myFormerParent := SELF.parentBranch;
ourNewParent := TBranchArea.CREATE(NIL, SELF.Heap, vhs, elderFirst, whoCanResizeIt, SELF, panel);
IF myFormerParent = NIL THEN
window.panelTree := ourNewParent
ELSE
myFormerParent.ReplaceChild(SELF, ourNewParent);
panel.SetOuterRect(zeroRect); {since the panel is not on the screen right now,
it shouldn't have any size}
panel.ResizeOutside(itsOuterRect);
SELF.ResizeOutside(myOuterRect);
{Just in case some panel is below its mimimum size, let the window expand if needed}
window.Resize(FALSE);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgDRWres}
PROCEDURE {TPanel.}Invalidate;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
PushFocus;
SELF.window.Focus;
InvalRect(SELF.innerRect);
PopFocus;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
PROCEDURE {TPanel.}InvalLRect{(lRectInView: LRect)};
PROCEDURE InvalOnThePad;
BEGIN
thePad.InvalLRect(lRectInView);
END;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.OnAllPadsDo(InvalOnThePad);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCcld}
PROCEDURE {TPanel.}MakeBand{(vhs: VHSelect; scroller, prevScroller: TScroller)};
VAR prevBand:
TBand;
band:
TBand;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
prevBand := prevScroller.band;
band := SELF.NewBand(SELF.Heap, zeroRect, scroller, vhs);
band.panes.Become(prevBand.panes.Clone(SELF.Heap));
SELF.bands[vhs].InsAt(SELF.bands[vhs].Pos(0, prevBand) + 1, band);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sSplit}
PROCEDURE {TPanel.}MoveSplitBefore{(scroller: TScroller; newSkwrCd: INTEGER)};
VAR vhs:
VHSelect;
outsideContent:
hsb:
prevHsb:
prevScroller:
nextScroller:
otherBand:
band:
oldSkwrCd:
newViewLCd:
viewDeltaLCd:
sbRect:
newSkwrPt:
sbList:
limitRect:
r:
BOOLEAN;
THsb;
THsb;
TScroller;
TScroller;
TBand;
TBand;
INTEGER;
LONGINT;
LONGINT;
{-gb}
Rect;
Point;
TSbList;
Rect;
Rect;
newSkwrPt.vh[vhs] := newSkwrCd;
newSkwrPt.vh[orthogonal[vhs]] := sbRect.topLeft.vh[orthogonal[vhs]];
PreSbList(sbList, scroller.scrollBar);
hsb := HsbFromPt(sbList, newSkwrPt);
PostSbList(sbList, scroller.scrollBar);
IF (hsb = hsbNil) {user started to create a new split but changed his mind} OR
outsideContent {new split would be in a side band} THEN
scroller := NIL {user started to create a new split but changed his mind}
ELSE
scroller := TScroller(RefconSb(hsb));
END
ELSE
BEGIN
prevScroller := TScroller(RefconSb(prevHsb));
{don't allow the new position of split to cross another split}
FixRLimits(hsb, limitRect);
WITH limitRect DO
newSkwrCd := Max(topLeft.vh[vhs], Min(botRight.vh[vhs], newSkwrCd));
END;
IF scroller <> NIL THEN
BEGIN
scroller.GetSize(sbRect);
oldSkwrCd := sbRect.topLeft.vh[vhs];
WITH SELF.contentRect DO
IF oldSkwrCd <= topLeft.vh[vhs] THEN
oldSkwrCd := topLeft.vh[vhs] - 1
ELSE IF oldSkwrCd >= botRight.vh[vhs] THEN
oldSkwrCd := botRight.vh[vhs] + 1;
IF newSkwrCd <> oldSkwrCd THEN
BEGIN
band := scroller.band;
viewDeltaLCd := newSkwrCd - oldSkwrCd;
IF SELF.zoomed THEN
{ if zoomed then adjust viewDeltaLCd accordingly }
WITH SELF.zoomFactor DO
{$H-}
viewDeltaCd := LIntOvrInt(LIntMulInt(viewDeltaLCd, denominator.vh[vhs]),
{-gb +++LSR+++} numerator.vh[vhs]);
{$H-}
newViewLCd := band.ViewLCd + viewDeltaLCd;
IF prevScroller = NIL THEN
BEGIN {new band}
IF hsb <> hsbNil THEN
{-gb}
{-gb}
{-gb}
BEGIN
InvalScrollers(band, band);
scroller.SplitAt(newSkwrCd, nextScroller);
SELF.ResizeBand(vhs, band, band.ViewLCd, FALSE);
SELF.MakeBand(vhs, nextScroller, scroller);
otherBand := nextScroller.band;
SELF.ResizeBand(vhs, otherBand, newViewLCd, FALSE);
{must invalidate now (special case)}
IF otherBand.ViewLCd <> newViewLCd THEN {the new band scrolled a bit}
InvalRect(otherBand.innerRect);
Pt2Rect(band.innerRect.botRight, otherBand.innerRect.topLeft, r);
InvalRect(r);
SELF.RepaneOrthogonalBands(vhs);
SELF.RemakePanes;
END;
END
ELSE
BEGIN {resize or delete band}
{If new position of split is outside the contentRect, make it go away}
IF outsideContent THEN
WITH limitRect DO
IF newSkwrCd <= SELF.contentRect.topLeft.vh[vhs] THEN
newSkwrCd := topLeft.vh[vhs]
ELSE
newSkwrCd := botRight.vh[vhs];
scroller.ResplitAt(newSkwrCd, prevScroller);
otherBand := prevScroller.band;
InvalScrollers(otherBand, band);
SELF.ResizeBand(vhs, otherBand, otherBand.ViewLCd, TRUE);
SELF.ResizeBand(vhs, band, newViewLCd, TRUE);
END;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCldInit}
FUNCTION {TPanel.}NewBand{(heap: THeap; myInnerRect: Rect;
scroller: TScroller; vhs: VHSelect): TBand};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
NewBand := TBand.CREATE(NIL, heap, SELF, myInnerRect, scroller, vhs);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
FUNCTION {TPanel.}NewStatusView{(object: TObject; itsExtent: LRect): TView};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
NewStatusView := TView.CREATE(object, SELF.Heap, SELF, itsExtent, NIL, zeroLRect,
FALSE, screenRes, TRUE);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sCldInit}
FUNCTION {TPanel.}NewView{(object: TObject; itsExtent: LRect; itsPrintManager: TPrintManager;
itsDfltMargins: LRect; itsFitPerfectlyOnPages: BOOLEAN): TView};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
NewView := TView.CREATE(object, SELF.Heap, SELF, itsExtent, itsPrintManager, itsDfltMargins,
itsFitPerfectlyOnPages, screenRes, TRUE);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sStartup}
FUNCTION {TPanel.}NewPane{(heap: THeap; innerRect: Rect; viewedLRect: LRect): TPane};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
NewPane := TPane.CREATE(NIL, heap, SELF, innerRect, viewedLRect);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
FUNCTION {TPanel.}OKToDrawIn{(lRectInView: LRect): BOOLEAN};
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF NOT SELF.view.OKToDrawIn(lRectInView) THEN
OKToDrawIn := FALSE
ELSE
IF SELF.previewMode = mPrvwBreaks THEN
{$S sRes}
FUNCTION {TPanel.}PaneShowing{(anLRect: LRect): TPane};
VAR pane:
TPane;
s:
TListScanner;
viewedLRect:
LRect;
scrollableLRect:
LRect;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
PaneShowing := NIL;
s := SELF.panes.Scanner;
WHILE s.Scan(pane) DO
BEGIN
pane.GetScrollLimits(viewedLRect, scrollableLRect);
WITH anLRect DO
BEGIN
LRectHaveLPt(scrollableLRect, topLeft);
LRectHaveLPt(scrollableLRect, botRight);
END;
WITH viewedLRect DO
IF top <= anLRect.bottom THEN
IF bottom >= anLRect.top THEN
IF left <= anLRect.right THEN
IF right >= anLRect.left THEN
BEGIN
s.Done;
PaneShowing := pane;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
FUNCTION {TPanel.}PaneToScroll(VAR anLRect: LRect; hMinToSee, vMinToSee: INTEGER): TPane;
VAR tempLRect:
LRect;
pane:
TPane;
dummyPt:
Point;
BEGIN
{$IFC fTrace}BP(5);{$ENDC}
WITH anLRect DO
BEGIN
tempLRect.top := top + vMinToSee;
tempLRect.bottom := bottom - vMinToSee;
tempLRect.left := left + hMinToSee;
PROCEDURE XorBreaksOnThePad;
BEGIN
SELF.view.printManager.DrawBreaks(FALSE);
END;
PROCEDURE ClearSelection;
BEGIN
noSelection := SELF.selection.FreedAndReplacedBy(SELF.view.NoSelection);
END;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
IF SELF.view.isPrintable THEN
{Actually shouldn't be called unless isPrintable}
BEGIN
oldMode := SELF.previewMode;
showMargins := (newMode = mPrvwMargins);
hideMargins := (oldMode = mPrvwMargins);
IF oldMode = newMode THEN
BEGIN
END
ELSE
IF showMargins OR hideMargins
BEGIN
THEN
paginatedView := SELF.paginatedView;
IF showMargins THEN
BEGIN
paginatedView := SELF.view.printManager.NewPaginatedView(NIL);
SELF.currentView := paginatedView;
SELF.paginatedView := paginatedView;
END
ELSE
SELF.currentView := SELF.view; { newMode = show Breaks or show main view }
SELF.previewMode := newMode;
FOR vhs := v TO h DO
BEGIN
offset.vh[orthogonal[vhs]] := 0;
bs := SELF.bands[vhs].Scanner;
WHILE bs.Scan(band) DO
BEGIN
firstPane := TPane(band.panes.First);
IF showMargins THEN
paginatedView.PagifyLPoint(firstPane.viewedLRect.topLeft, pagiLPoint)
ELSE
IF hideMargins THEN
paginatedView.DePagifyLPoint(firstPane.viewedLRect.topLeft, pagiLPoint);
offset.vh[vhs] := pagiLPoint.vh[vhs] - firstPane.viewedLRect.topLeft.vh[vhs];
ps := band.panes.Scanner;
WHILE ps.Scan(pane) DO
BEGIN
pane.currentView := SELF.currentView;
pane.OffsetBy(offset);
END;
END;
END;
IF hideMargins THEN
BEGIN
paginatedView.Free;
SELF.paginatedView := NIL;
theMarginPad.view := NIL;
END;
SELF.Rescroll; {Does Invalidate and Moves Thumbs}
END
ELSE
BEGIN
SELF.window.Update(TRUE);
{Update in the old mode, in case regions were invalid}
SELF.previewMode := newMode;
{Set the new mode}
SELF.OnAllPadsDo(XorBreaksOnThePad);
{Xor the page breaks}
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCpri}
PROCEDURE {TPanel.}PrintView{(printPref: TPrReserve)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.view.printManager <> NIL THEN
SELF.view.printManager.Print(printPref);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sStartup}
PROCEDURE {TPanel.}Refresh{(rActions: TActions; highTransit: THighTransit)};
{$IFC fTrace}BP(7);{$ENDC}
deletedSplits := SELF.deletedSplits;
IF deletedSplits <> NIL THEN
BEGIN
{$IFC fDbgABC}
IF deletedSplits.recordBytes <> 2 THEN
ABCbreak('This panel has a deletedSplits array, but its recordBytes <> 2', ORD(SELF));
{$ENDC}
IF vhs = v THEN
atCd := - atCd;
deletedSplits.InsLast(@atCd);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
PROCEDURE {TPanel.}Remove;
VAR itsParent:
TBranchArea;
itsGrandParent: TBranchArea;
itsSibling:
TArea;
itsWindow:
TWindow;
firstPanel:
TPanel;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
itsParent := SELF.parentBranch;
itsWindow := SELF.window;
{$IFC fDbgABC}
IF itsParent = NIL THEN
ABCBreak('You cannot remove the last panel in the window', ORD(SELF));
{$ENDC}
itsGrandParent := itsParent.parentBranch;
itsSibling := itsParent.OtherChild(SELF);
itsSibling.ResizeOutside(itsParent.outerRect);
itsSibling.parentBranch := itsGrandParent;
IF itsGrandParent = NIL THEN
itsWindow.panelTree := itsSibling
ELSE
itsGrandParent.ReplaceChild(itsParent, itsSibling); {also sets my parentBranch to NIL}
SELF.resizeBranch := NIL;
firstPanel := TPanel(itsWindow.panels.First);
IF itsWindow.selectPanel = SELF THEN
itsWindow.selectPanel := firstPanel;
IF itsWindow.clickPanel = SELF THEN
itsWindow.clickPanel := firstPanel;
{We do not change undoSelPanel & undoClickPanel because undo may bring them back; so caller beware!}
itsParent.Free;
itsWindow.panels.DelObject(SELF, FALSE);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
PROCEDURE {TPanel.}RepaneOrthogonalBands{(vhs: VHSelect)};
VAR bs, orthoBs, ps: TListScanner;
orthoBands: TList;
band, oBand: TBand;
pane: TPane;
BEGIN
{assumes they are right in the orthogonal band}
{$IFC fTrace}BP(7);{$ENDC}
orthoBands := SELF.bands[orthogonal[vhs]];
orthoBs := orthoBands.Scanner;
while orthoBs.Scan(oBand) do
oBand.panes.DelAll(FALSE);
bs := SELF.bands[vhs].Scanner;
WHILE bs.Scan(band) DO
BEGIN
ps := band.panes.Scanner;
orthoBs := orthoBands.Scanner;
WHILE ps.Scan(pane) AND orthoBs.Scan(oBand) DO
oBand.panes.insLast(pane);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
PROCEDURE {TPanel.}Replace{(panel: TPanel)};
VAR itsParent:
TBranchArea;
itsWindow:
TWindow;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
itsParent := SELF.parentBranch;
itsWindow := SELF.window;
itsWindow.panels.DelObject(SELF, FALSE);
itsWindow.panels.InsLast(panel);
IF itsParent = NIL THEN
itsWindow.panelTree := panel
ELSE
itsParent.ReplaceChild(SELF, panel); {also sets my parentBranch to NIL}
SELF.resizeBranch := NIL;
panel.ResizeOutside(SELF.outerRect);
IF itsWindow.selectPanel = SELF THEN
itsWindow.selectPanel := panel;
IF itsWindow.clickPanel = SELF THEN
itsWindow.clickPanel := panel;
{We do not change undoSelPanel & undoClickPanel because undo may bring them back; so caller beware!}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sCldInit}
PROCEDURE {TPanel.}Rescroll;
VAR vhs:
VHSelect;
band:
TBand;
s:
TListScanner;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
InvalRect(SELF.outerRect); {Since the view is changing, no part of the old image is good}
FOR vhs := v TO h DO
BEGIN
s := SELF.bands[vhs].Scanner;
WHILE s.Scan(band) DO
IF band.scroller <> NIL THEN
SetThumb(POINTER(band.scroller.sBoxID), band.ThumbPos);
{since we invalidated everything, just telling the SB library where the
thumb should be is enough}
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
PROCEDURE {TPanel.}ResizeBand{(vhs: VHSelect; band: TBand; newViewLCd: LONGINT;
fInvalidate: BOOLEAN)};
VAR scroller:
TScroller;
sbRect:
Rect;
tempRect:
Rect;
toBeDeleted:
TList {OF TPane};
ps:
TListScanner;
pane:
TPane;
oldBandInner:
Rect;
newOuterRect:
Rect;
unchangedRect: Rect;
tempBand:
TBand;
sideBand:
TSideBand;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
scroller := band.scroller;
IF scroller = NIL THEN {band is a side band}
sbRect := band.outerRect
ELSE
BEGIN
scroller.GetSize(sbRect);
WITH sbRect DO {regular bands must lie within the contentRect; the +/- 1 is
because the contentRect corresponds to the innerRect, but
sbRect must be based on the outerRect}
BEGIN
topLeft.vh[vhs] := Max(topLeft.vh[vhs], SELF.contentRect.topLeft.vh[vhs] - 1);
botRight.vh[vhs] := Min(botRight.vh[vhs], SELF.contentRect.botRight.vh[vhs] + 1);
END;
END;
unchangedRect := zeroRect;
IF LengthRect(sbRect, vhs) <= 0 THEN
BEGIN
toBeDeleted := TList.CREATE(NIL, SELF.Heap, band.panes.size);
ps := band.panes.Scanner;
WHILE ps.Scan(pane) DO
toBeDeleted.InsLast(pane);
SELF.bands[vhs].DelObject(band, TRUE);
SELF.CleanUpPanes(toBeDeleted);
END
ELSE
BEGIN
newOuterRect := SELF.innerRect;
InsetRect(newOuterRect, -1, -1);
AlignRect(newOuterRect, sbRect, vhs);
oldBandInner := band.innerRect;
band.SetOuterRect(newOuterRect);
band.ResizePanes(newViewLCd);
IF fInvalidate THEN
IF band.ViewLCd = newViewLCd THEN
IF SectRect(oldBandInner, band.innerRect, unchangedRect) THEN;
END;
IF fInvalidate THEN
InvalDiffRect(band.outerRect, unchangedRect);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCldInit}
PROCEDURE {TPanel.}ResizeInside{(newInnerRect: Rect)};
VAR toBeDeleted:
TList {OF TPane};
allBandOuterRect:
Rect;
vhs:
VHSelect;
s:
TListScanner;
nextTopLeft:
INTEGER;
lastBotRight:
INTEGER;
thisBotRight:
INTEGER;
band:
TBand;
ps:
TListScanner;
pane:
TPane;
newBandOuterRect:
Rect;
oldViewLCd:
LONGINT;
firstBand:
TBand;
lastBand:
TBand;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
toBeDeleted := TList.CREATE(NIL, SELF.Heap, 0);
allBandOuterRect := newInnerRect;
InsetRect(allBandOuterRect, -1, -1);
FOR vhs := v TO h DO
BEGIN
firstBand := TBand(SELF.bands[vhs].First);
IF firstBand.scroller = NIL THEN
firstBand := TSideBand(firstBand).CoBand;
lastBand := TBand(SELF.bands[vhs].Last);
IF lastBand.scroller = NIL THEN
lastBand := TSideBand(lastBand).CoBand;
{$H-}
WITH SELF.contentRect DO
BEGIN
nextTopLeft := Max(topLeft.vh[vhs]-1, allBandOuterRect.topLeft.vh[vhs]);
lastBotRight := Min(botRight.vh[vhs]+1, allBandOuterRect.botRight.vh[vhs]);
END;
{$H+}
s := SELF.bands[vhs].Scanner;
WHILE s.Scan(band) DO
IF band.scroller = NIL THEN {a side band}
BEGIN
IF NOT TSideBand(band).topOrLeft THEN {a bottom/right side band must be moved
into a new position}
BEGIN
SELF.SideBandRect(vhs, FALSE, newBandOuterRect); {.SideBandRect returns an InnerRect}
InsetRect(newBandOuterRect, -1, -1); {outerRect is innerRect outset by 1...}
WITH newBandOuterRect.topLeft DO
vh[vhs] := vh[vhs] + 1;
{... EXCEPT on the top/left}
band.ResizeOutside(newBandOuterRect);
END;
END
ELSE {a regular band}
{Always leave at least one pane}
IF (band <> firstBand) AND (nextTopLeft >= lastBotRight) THEN
BEGIN
ps := band.panes.Scanner;
WHILE ps.Scan(pane) DO
IF toBeDeleted.Pos(0, pane) <= 0 THEN
toBeDeleted.InsLast(pane);
SELF.RememberSplit(vhs, band.outerRect.topLeft.vh[vhs]);
s.Delete(TRUE);
END
ELSE
BEGIN
newBandOuterRect.topLeft.vh[vhs] := nextTopLeft;
IF band = lastBand THEN
thisBotRight := lastBotRight
ELSE
thisBotRight := Min(nextTopLeft + lengthRect(band.outerRect, vhs), lastBotRight);
newBandOuterRect.botRight.vh[vhs] := thisBotRight;
AlignRect(newBandOuterRect, allBandOuterRect, orthogonal[vhs]);
oldViewLCd := band.ViewLCd;
band.ResizeOutside(newBandOuterRect);
IF oldViewLCd <> band.ViewLCd THEN
InvalRect(band.innerRect);
nextTopLeft := newBandOuterRect.botRight.vh[vhs];
END;
END;
SELF.CleanUpPanes(toBeDeleted);
SELF.RestoreSplits; {do this after all the bands have been adjusted}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCcld}
PROCEDURE {TPanel.}ResizeOutside{(newOuterRect: Rect)};
VAR oldOuterRect:
Rect;
oldInnerRect:
Rect;
newInnerRect:
Rect;
unchangedRect: Rect;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
oldOuterRect := SELF.outerRect;
IF NOT EqualRect(oldOuterRect, newOuterRect) THEN
BEGIN
oldInnerRect := SELF.innerRect;
SELF.DecideAboutBars(newOuterRect);
newInnerRect := SELF.innerRect;
unchangedRect := zeroRect;
IF EqualPt(oldOuterRect.topLeft, newOuterRect.topLeft) THEN
IF SectRect(oldInnerRect, newInnerRect, unchangedRect) THEN;
InvalDiffRect(newOuterRect, unchangedRect);
SELF.ResizeInside(newInnerRect);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sCldInit}
PROCEDURE {TPanel.}RestoreSplits;
VAR deletedSplits: TArray;
contentRect:
Rect;
vhs:
VHSelect;
firstScrollers: ARRAY[VHSelect] OF TScroller;
s:
TArrayScanner;
pInt:
Ptr;
cd:
INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
deletedSplits := SELF.deletedSplits;
IF deletedSplits <> NIL THEN
BEGIN
{$IFC fDbgABC}
IF deletedSplits.recordBytes <> 2 THEN
ABCbreak('This panel has a deletedSplits array, but its recordBytes <> 2', ORD(SELF));
{$ENDC}
contentRect := SELF.contentRect;
FOR vhs := v TO h DO
firstScrollers[vhs] := SELF.scrollBars[vhs].firstBox;
s := deletedSplits.Scanner;
WHILE s.Scan(pInt) DO
BEGIN
cd := TpInteger(pInt)^;
IF cd < 0 THEN
BEGIN
vhs := v;
cd := - cd;
END
ELSE
vhs := h;
IF (cd > contentRect.topLeft.vh[vhs]) AND
(cd < contentRect.botRight.vh[vhs] - dptSkewer.vh[vhs]) THEN
BEGIN
SELF.MoveSplitBefore(firstScrollers[vhs], cd);
s.Delete;
END;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sRes}
PROCEDURE {TPanel.}RevealLRect(VAR anLRect: LRect; hMinToSee, vMinToSee: INTEGER);
VAR pane:
TPane;
revisedLRect:
LRect;
BEGIN
{$IFC fTrace}BP(5);{$ENDC}
IF SELF.previewMode = mPrvwMargins THEN {need to map coords}
BEGIN
SELF.paginatedView.PagifyLPt(anLRect.topLeft, revisedLRect.topLeft);
SELF.paginatedView.PagifyLPt(anLRect.botRight, revisedLRect.botRight);
END
ELSE
revisedLRect := anLRect;
s := SELF.bands[vhs].Scanner;
WHILE s.Scan(band) DO
IF band.scroller <> NIL THEN {not a side band}
BEGIN
bandIsCovered := NOT SectRect(band.innerRect, SELF.contentRect, tempRect);
IF bandIsCovered THEN
s.Delete(FALSE); {delete it from the list before some other method, so our scanner
doesn't get confused; it will still get freed later, though}
IF moveNextSplit OR (bandIsConvered AND NOT topOrLeft) THEN
BEGIN
SELF.RememberSplit(vhs, band.outerRect.topLeft.vh[vhs]);
SELF.MoveSplitBefore(band.scroller, removeCd);
END;
END;
{$S sCldInit}
FUNCTION {TBand.}CREATE{(object: TObject; heap: THeap; itsPanel: TPanel; itsInnerRect: Rect;
itsScroller: TScroller; itsDir: VHSelect): TBand};
VAR panes: TList;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TBand(object);
WITH SELF DO
BEGIN
window := itsPanel.window;
panel := itsPanel;
scroller := itsScroller;
scrollDir := itsDir;
parentBranch := NIL;
END;
panes := TList.CREATE(NIL, heap, 1);
SELF.panes := panes;
SELF.SetInnerRect(itsInnerRect);
IF itsScroller <> NIL THEN
itsScroller.band := SELF;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCini}
PROCEDURE {TBand.}Free;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
Free(SELF.scroller);
SELF.panes.FreeObject;
TArea.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TBand.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
TArea.Fields(Field);
Field('window: TWindow');
Field('panes: TList');
Field('panel: TPanel');
Field('scroller: TScroller');
Field('scrollDir: Byte');
Field('');
END;
{$S SgABCres}
{$ENDC}
{$S sScroll}
PROCEDURE {TBand.}OffsetPanes{(deltaLPt: LPoint)};
PROCEDURE YouOffset(obj: TObject);
BEGIN
TPane(obj).OffsetBy(deltaLPt);
END;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.panes.Each(YouOffset);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCldInit}
PROCEDURE {TBand.}ResizeOutside{(newOuterRect: Rect)};
VAR scroller:
TScroller;
newScrollerSize:
Rect;
unchangedRect:
Rect;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF NOT EqualRect(SELF.outerRect, newOuterRect) THEN
BEGIN
unchangedRect := SELF.outerRect;
IF NOT EqualPt(unchangedRect.topLeft, newOuterRect.topLeft) THEN
unchangedRect := zeroRect
ELSE
InsetRect(unchangedRect, 1, 1); {we want unchangedRect to be the old innerRect}
InvalDiffRect(newOuterRect, unchangedRect);
scroller := SELF.scroller;
SELF.SetOuterRect(newOuterRect);
newScrollerSize := SELF.outerRect;
WITH SELF DO
BEGIN
newScrollerSize.botRight.vh[orthogonal[scrollDir]] :=
panel.innerRect.botRight.vh[orthogonal[scrollDir]] + 1;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sScroll}
PROCEDURE {TBand.}ScrollBy{(deltaLCd: LONGINT)};
{positive scrolls towards end; 0 means resize & don't move thumb}
VAR deltaLPt:
LPoint;
vhs:
VHSelect;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
PushFocus;
SELF.window.Focus;
WITH SELF, deltaLPt DO
BEGIN
vhs := scrollDir;
vh[vhs] := deltaLCd;
vh[orthogonal[vhs]] := 0;
END;
SELF.panel.DoScrolling(SELF, TPane(SELF.panes.First), vhs=h, vhs=v, deltaLPt);
IF NOT EqualLPt(deltaLPt, zeroLPt) THEN
SELF.OffsetPanes(deltaLPt);
IF deltaLCd <> 0 THEN
IF SELF.scroller <> NIL THEN {can this be a side band???}
SELF.scroller.MoveThumb(SELF.ThumbPos);
PopFocus;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sScroll}
PROCEDURE {TBand.}ScrollStep{(icon: TEnumIcons; deltaLStd: LONGINT)};
VAR vhs:
VHSelect;
len:
LONGINT;
deltaLCd:
LONGINT;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
vhs := SELF.scrollDir;
len := LIntDivInt(LengthRect(SELF.innerRect, vhs) * ORD4(SELF.panel.view.res.vh[vhs]),
screenRes.vh[vhs]);
CASE icon OF {how far to scroll without regard for overshooting the ends}
iScrollBack:
deltaLCd := -deltaLStd;
iScrollFwd:
deltaLCd := deltaLStd;
iFlipBack:
deltaLCd := Min(deltaLStd - len, -deltaLStd);
iFlipFwd:
deltaLCd := Max(len - deltaLStd, deltaLStd);
END;
SELF.ScrollBy(deltaLCd);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sScroll}
PROCEDURE {TBand.}ScrollTo{(viewLCd: LONGINT)};
VAR pane:
TPane;
deltaLCd:
LONGINT;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
pane := TPane(SELF.panes.First);
deltaLCd := viewLCd - pane.viewedLRect.topLeft.vh[SELF.scrollDir];
SELF.ScrollBy(deltaLCd);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sScroll}
FUNCTION {TBand.}ThumbPos{: INTEGER};
VAR vhs:
VHSelect;
pane:
TPane;
viewedLRect:
LRect;
scrollableLRect:
LRect;
thumbLRange:
LONGINT;
barRange:
INTEGER;
lOffset:
LONGINT;
barPos:
INTEGER;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
vhs := SELF.scrollDir;
pane := TPane(SELF.panes.First);
pane.GetScrollLimits(viewedLRect, scrollableLRect);
thumbLRange := LengthLRect(scrollableLRect, vhs) - LengthLRect(viewedLRect, vhs);
barRange := SELF.scroller.ThumbRange;
IF barRange = 0 THEN
ThumbPos := 0
ELSE
BEGIN
lOffset := viewedLRect.topLeft.vh[vhs] - scrollableLRect.topLeft.vh[vhs];
IF thumbLRange > 1 THEN
{Only divide by positive denominators}
barPos := LIntDivLInt(LIntMulInt(lOffset, barRange - 1) + thumbLRange - barRange,
thumbLRange - 1)
ELSE
IF (thumbLRange = 1) AND (lOffset > 0) THEN
{Very rare case: view one pixel bigger
than pane...}
barPos := barRange
{...and scrolled to end}
ELSE
barPos := 0;
{Usually because the view is smaller than the
pane}
{barPos = 0 or barRange only if nowhere to scroll}
ThumbPos := Max(0, Min(1000, LIntDivInt(LIntMulInt(barPos, 1000) + barRange - 1, barRange)));
{ThumbPos = 0 or 1000 only if nowhere to scroll [assumes band is <= 1000 pixels long]}
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sScroll}
PROCEDURE {TBand.}ThumbTo{(newThumbPos: INTEGER)};
VAR vhs:
VHSelect;
thumbLRange:
LONGINT;
pane:
TPane;
viewedLRect:
LRect;
scrollableLRect:
LRect;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
vhs := SELF.scrollDir;
pane := TPane(SELF.panes.First);
pane.GetScrollLimits(viewedLRect, scrollableLRect);
thumbLRange := LengthLRect(scrollableLRect, vhs) - LengthLRect(viewedLRect, vhs);
SELF.ScrollTo(scrollableLRect.topLeft.vh[vhs] +
LIntDivInt(LIntMulInt(thumbLRange, newThumbPos), 1000));
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
FUNCTION {TBand.}ViewLCd{: LONGINT};
VAR pane:
TPane;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
pane := TPane(SELF.panes.First);
ViewLCd := pane.viewedLRect.topLeft.vh[SELF.scrollDir];
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCini}
END;
{$S SgABCres}
METHODS OF TSideBand;
{$S SgABCcld}
FUNCTION {TSideBand.}CREATE{(object: TObject; heap: THeap; itsPanel: TPanel; itsInnerRect: Rect;
itsDir: VHSelect; itsTopOrLeft: BOOLEAN;
itsViewLCd: LONGINT): TSideBand};
VAR bandList:
TList;
itsCoBand: TBand;
deltaLPt:
LPoint;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
TSideBand(object).topOrLeft := itsTopOrLeft; {needed to be set before SetInnerRect, which is
done in TBand.CREATE}
SELF := TSideBand(TBand.CREATE(object, heap, itsPanel, itsInnerRect, NIL, itsDir));
bandList := itsPanel.bands[itsDir];
IF itsTopOrLeft THEN
BEGIN
itsCoBand := TBand(bandList.First);
bandList.InsFirst(SELF);
END
ELSE
BEGIN
itsCoBand := TBand(bandList.Last);
bandList.InsLast(SELF);
END;
SELF.panes.Become(itsCoBand.panes.Clone(heap));
SELF.ResizePanes(itsViewLCd);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCcld}
PROCEDURE {TSideBand.}Free;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
SELF.scroller := NIL;
{let my coBand free the scroller}
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TSideBand.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SUPERSELF.Fields(Field);
Field('topOrLeft: BOOLEAN');
Field('');
{$IFC fTrace}EP;{$ENDC}
END;
{$ENDC}
{$S SgABCcld}
FUNCTION {TSideBand.}CoBand{: TBand};
VAR bandList:
TList;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
bandList := SELF.panel.bands[SELF.scrollDir];
IF SELF.topOrLeft THEN
CoBand := TBand(bandList.At(2))
ELSE
CoBand := TBand(bandList.At(bandList.Size-1));
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCcld}
PROCEDURE {TSideBand.}GetBorder{(VAR border: Rect)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SUPERSELF.GetBorder(border);
WITH SELF, border DO
IF topOrLeft THEN
botRight.vh[scrollDir] := 0
ELSE
topLeft.vh[scrollDir] := 0;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCcld}
PROCEDURE {TSideBand.}ResizeOutside{(newOuterRect: Rect)};
VAR unchangedRect:
Rect;
rectToInval:
Rect;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF NOT EqualRect(SELF.outerRect, newOuterRect) THEN
BEGIN
unchangedRect := SELF.outerRect;
IF NOT EqualPt(unchangedRect.topLeft, newOuterRect.topLeft) THEN
unchangedRect := zeroRect
ELSE
InsetRect(unchangedRect, 1, 1); {we want unchangedRect to be the old innerRect}
SELF.SetOuterRect(newOuterRect);
rectToInval := SELF.innerRect;
InsetRect(rectToInval, -1, -1);
InvalDiffRect(rectToInval, unchangedRect);
SELF.ResizePanes(SELF.ViewLCd);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCcld}
PROCEDURE {TSideBand.}ResizePanes{(newViewLCd: LONGINT)};
{assumes SELF.innerRect already set}
VAR vhs:
VHSelect;
s:
TListScanner;
pane:
TPane;
viewedLRect:
LRect;
scrollableLRect:
LRect;
oldViewLCd:
LONGINT;
deltaLPt:
LPoint;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
vhs := SELF.scrollDir;
s := SELF.panes.Scanner;
WHILE s.Scan(pane) DO
pane.Resize(SELF.innerRect, vhs);
oldViewLCd := SELF.ViewLCd;
deltaLPt.vh[orthogonal[vhs]] := 0;
deltaLPt.vh[vhs] := newViewLCd - oldViewLCd;
SELF.OffsetPanes(deltaLPt);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sError}
PROCEDURE {TSideBand.}ScrollTo{(viewLCd: LONGINT)};
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
ABCBreak('Can not do TSideBand.ScrollTo', 0);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCcld}
FUNCTION {TSideBand.}ThumbPos{: INTEGER};
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
ThumbPos := 0;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCini}
END;
{$S SgABCres}
METHODS OF TPane;
{$S sCldInit}
FUNCTION {TPane.}CREATE{(object: TObject; heap: THeap; itsPanel: TPanel; itsInnerRect: Rect;
itsViewedLRect: LRect): TPane};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TPane(TPad.CREATE(object, heap, itsInnerRect, itsViewedLRect, screenRes,
screenRes, POINTER(itsPanel.window.wmgrId)));
SELF.currentView := itsPanel.currentView;
SELF.panel := itsPanel;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TPane.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
TPad.Fields(Field);
Field('currentView: TView');
Field('panel: TPanel');
END;
{$S SgABCres}
{$ENDC}
{$S sRes}
FUNCTION {TPane.}CursorAt{(mousePt: Point): TCursorNumber};
{assumes mousePt is within the pane's innerRect}
VAR mouseLPt:
LPoint;
panePt:
Point; {window-relative, under the coordinate system defined by pane}
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
PushFocus;
panePt := mousePt;
LocalToGlobal(panePt);
SELF.Focus;
GlobalToLocal(panePt); {mousePt is now adjusted for the pane's new origin}
SELF.PtToLPt(panePt, mouseLPt);
IF LRectHasLPt(SELF.currentView.extentLRect, mouseLPt) THEN
CursorAt := SELF.currentView.CursorAt(mouseLPt)
ELSE
CursorAt := arrowCursor;
PopFocus;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TPane.}GetScrollLimits{(VAR viewedLRect, scrollableLRect: LRect)};
VAR extra: Point;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
viewedLRect := SELF.viewedLRect;
WITH SELF.currentView DO
BEGIN
scrollableLRect := extentLRect;
extra := scrollPastEnd;
END;
WITH scrollableLRect, extra DO
BEGIN
right := right + Max(0, Min(viewedLRect.right - viewedLRect.left - h, h));
bottom := bottom + Max(0, Min(viewedLRect.bottom - viewedLRect.top - v, v));
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sCldInit}
PROCEDURE {TPane.}HaveView{(view: TView)};
VAR deltaLPt:
LPoint;
viewedLRect:
LRect;
paneSize:
Point;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.currentView := view;
IF (view.res.h <> SELF.viewedRes.h) OR (view.res.v <> SELF.viewedRes.v) THEN
BEGIN
PtMinusPt(SELF.innerRect.botRight, SELF.innerRect.topLeft, paneSize);
viewedLRect := view.extentLRect;
viewedLRect.right := viewedLRect.left +
LIntDivInt(ORD4(paneSize.h) * view.res.h, SELF.padRes.h);
viewedLRect.bottom := viewedLRect.top +
LIntDivInt(ORD4(paneSize.v) * view.res.v, SELF.padRes.v);
SELF.Redefine(SELF.innerRect, viewedLRect, SELF.padRes, view.res, SELF.zoomFactor, SELF.port);
END
ELSE
BEGIN
SetLPt(deltaLPt, view.extentLRect.left - SELF.viewedLRect.left,
view.extentLRect.top - SELF.viewedLRect.top);
SELF.OffsetBy(deltaLPt);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sRes}
PROCEDURE {TPane.}MouseTrack{(mPhase: TMousePhase; mousePt: Point)};
{assumes mousePt is within the pane's innerRect;
mousePt is window-relative, (0,0)-origined}
VAR mouseLPt:
LPoint;
panePt:
Point; {window-relative, under the coordinate system defined by pane}
currentView:
TView;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
PushFocus;
panePt := mousePt;
LocalToGlobal(panePt);
SELF.Focus;
GlobalToLocal(panePt); {mousePt is now adjusted for the pane's new origin}
SELF.PtToLPt(panePt, mouseLPt);
currentView := SELF.currentView;
currentView.MouseTrack(mPhase, mouseLPt);
PopFocus;
{ &&& we should optimize the following -- SELF.CursorAt also does the same focusing as above }
process.ChangeCursor(SELF.CursorAt(mousePt));
{$IFC fTrace}EP;{$ENDC}
END;
{$S sStartup}
{+++LSR+++} {This whole method is substantially changed}
PROCEDURE {TPane.}Refresh{(rActions: TActions; highTransit: THighTransit)};
VAR panel:
needGray:
viewExtentLRect:
viewedLRect:
tempLRect:
TPanel;
BOOLEAN;
LRect;
LRect;
LRect;
PROCEDURE HighlightOnThePad;
BEGIN
panel.selection.Highlight(highTransit);
END;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
panel := SELF.panel;
viewExtentLRect := SELF.currentView.extentLRect;
viewedLRect := SELF.viewedLRect;
IF rFrame IN rActions THEN
SELF.Frame;
needGray := (rBackground IN rActions) AND
((viewedLRect.right > viewExtentLRect.right) OR
(viewedLRect.bottom > viewExtentLRect.bottom));
IF rErase IN rActions THEN
SELF.Erase;
IF (rDraw IN rActions) OR (highTransit <> hNone) OR needGray THEN
BEGIN
PushFocus;
SELF.Focus;
IF needGray THEN
BEGIN
PenNormal;
PenSize(2, 2);
{draw the vertical strip of gray ...}
tempLRect := viewedLRect;
tempLRect.left := viewExtentLRect.right;
FillLRect(tempLRect, lPatLtGray);
{... then the horizontal strip ...}
tempLRect := viewedLRect;
tempLRect.top := viewExtentLRect.bottom;
FillLRect(tempLRect, lPatLtGray);
{... then frame the bottom right of the view extent with a 2-pixel line outside the extent;
note that the topLeft does not matter}
tempLRect.topLeft := viewedLRect.topLeft;
tempLRect.botRight := viewExtentLRect.botRight;
InsetLRect(tempLRect, -2, -2);
FrameLRect(tempLRect);
END;
IF rDraw IN rActions THEN
SELF.currentView.Draw;
IF highTransit <> hNone THEN
IF panel.previewMode = mPrvwMargins THEN
panel.paginatedView.DoOnPages(TRUE, HighlightOnThePad)
ELSE
HighlightOnThePad;
IF rDraw IN rActions THEN {Page breaks after highlighting, in case highlighting doesn't XOR}
IF panel.previewMode = mPrvwBreaks THEN {Xors automatic as well as manual page breaks}
SELF.currentView.printManager.DrawBreaks(FALSE);
PopFocus;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sRes}
PROCEDURE {TPane.}Resize{(newInnerRect: Rect; vhs: VHSelect)};
VAR innerRect:
Rect;
paneLongSize:
LPoint;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
innerRect := SELF.innerRect;
AlignRect(innerRect, newInnerRect, vhs);
SELF.SetInnerRect(innerRect);
SELF.clippedRect := innerRect;
SELF.DistToLDist(Point(FDiagRect(innerRect)), paneLongSize);
{$H-} LPtPlusLPt(SELF.viewedLRect.topLeft, paneLongSize, SELF.viewedLRect.botRight); {$H+}
SELF.availLRect := SELF.viewedLRect;
{$H-} InsetLRect(SELF.availLRect, -8192, -8192); {$H+}
{$IFC fTrace}EP;{$ENDC}
END;
{$S sScroll}
PROCEDURE {TPane.}ScrollBy(VAR deltaLPt: LPoint);
VAR panel:
TPanel;
deltaPt:
Point;
vhs:
VHSelect;
band:
TBand;
tempPt:
Point;
BEGIN
{$IFC fTrace}BP(5);{$ENDC}
panel := SELF.panel;
IF panel.panes.Size = 1 THEN
BEGIN
PushFocus;
SELF.panel.window.Focus;
panel.DoScrolling(SELF, SELF, TRUE, TRUE, deltaLPt);
IF NOT EqualLPt(deltaLPt, zeroLPt) THEN
BEGIN
SELF.OffsetBy(deltaLPt);
FOR vhs := v TO h DO
panel.scrollBars[vhs].firstBox.MoveThumb(TBand(panel.bands[vhs].First).ThumbPos);
END;
PopFocus;
END
ELSE
FOR vhs := v TO h DO
BEGIN
band := TBand(panel.ChildWithPt(SELF.innerRect.topLeft, panel.bands[vhs], tempPt));
band.ScrollBy(deltaLPt.vh[vhs]);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sScroll}
PROCEDURE {TPane.}ScrollToReveal(VAR anLRect: LRect; hMinToSee, vMinToSee: INTEGER);
VAR ptMinToSee:
Point;
minToSee:
INTEGER;
viewedLRect:
LRect;
deltaLPt:
LPoint;
vhs:
VHSelect;
lcd:
LONGINT;
BEGIN
{$IFC fTrace}BP(5);{$ENDC}
viewedLRect := SELF.viewedLRect;
SetPt(ptMinToSee, hMinToSee, vMinToSee);
FOR vhs := v TO h DO
BEGIN
minToSee := Min(LengthRect(SELF.innerRect, vhs), ptMinToSee.vh[vhs]);
lcd := anLRect.topLeft.vh[vhs] + minToSee - viewedLRect.botRight.vh[vhs];
IF lcd <= 0 THEN
BEGIN
lcd := anLRect.botRight.vh[vhs] - minToSee - viewedLRect.topLeft.vh[vhs];
IF lcd >= 0 THEN
lcd := 0;
END;
deltaLPt.vh[vhs] := lcd;
END;
SELF.ScrollBy(deltaLPt);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCcld}
PROCEDURE {TPane.}SetZoomFactor{(zoomNumerator, zoomDenominator: Point)};
VAR zoomFactor: TScaler;
newLRight:
LONGINT;
newLBottom: LONGINT;
newViewedLRect: LRect;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
Reduce(zoomNumerator.h, zoomDenominator.h); {reduce to lowest terms}
Reduce(zoomNumerator.v, zoomDenominator.v);
{adjust viewed lRect}
newLRight := Min(
(SELF.viewedLRect.right * zoomDenominator.h * SELF.zoomFactor.numerator.h)
DIV ( zoomNumerator.h * SELF.zoomFactor.denominator.h),
SELF.currentView.extentLRect.right);
newLBottom := Min(
(SELF.viewedLRect.bottom * zoomDenominator.v * SELF.zoomFactor.numerator.v)
DIV ( zoomNumerator.v * SELF.zoomFactor.denominator.v),
SELF.currentView.extentLRect.bottom);
SetLRect(newViewedLRect, SELF.viewedLRect.left, SELF.viewedLRect.top,
newLRight, newLBottom);
SetPt(zoomFactor.numerator, zoomNumerator.h, zoomNumerator.v);
SetPt(zoomFactor.denominator, zoomDenominator.h, zoomDenominator.v);
SELF.Redefine(SELF.innerRect, newViewedLRect, SELF.padRes, SELF.viewedRes, zoomFactor, SELF.port);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCini}
END;
{$S SgABCres}
METHODS OF TMarginPad;
{$S SgABCini}
FUNCTION {TMarginPad.}CREATE{(object: TObject; heap: THeap): TMarginPad};
VAR bodyPad: TBodyPad;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TMarginPad(object);
bodyPad := TBodyPad.CREATE(NIL, heap, SELF);
SELF.bodyPad := bodyPad;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCpri}
PROCEDURE {TMarginPad.}Rework{(itsView: TView; itsOrigin: Point; itsRes: Point;
itsPageNumber: LONGINT; itsZoomFactor: TScaler; itsPort: GrafPtr)};
VAR itsViewedLRect: LRect;
printerMetrics: TPrinterMetrics;
bodyPad:
TBodyPad;
innerRect:
Rect;
PROCEDURE ScaleToPadSpace(printRect: Rect; VAR padRect: Rect);
VAR padLRect: LRect;
{NB: itsOrigin is a free var in this proc}
BEGIN
SetLRect(padLRect,
LIntOvrInt(ORD4(printRect.left)
* itsRes.h * itsZoomFactor.numerator.h,
printerMetrics.res.h * itsZoomFactor.denominator.h),
LIntOvrInt(ORD4(printRect.top)
* itsRes.v * itsZoomFactor.numerator.v,
printerMetrics.res.v * itsZoomFactor.denominator.v),
LIntOvrInt(ORD4(printRect.right) * itsRes.h * itsZoomFactor.numerator.h,
printerMetrics.res.h * itsZoomFactor.denominator.h),
LIntOvrInt(ORD4(printRect.bottom) * itsRes.v * itsZoomFactor.numerator.v,
printerMetrics.res.v * itsZoomFactor.denominator.v));
noPad.LRectToRect(padLRect, padRect);
OffsetRect(padRect, itsOrigin.h, itsOrigin.v);
END;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.view := itsView;
printerMetrics := SELF.view.printManager.printerMetrics;
SELF.pageNumber := itsPageNumber;
ScaleToPadSpace(printerMetrics.paperRect, innerRect);
SELF.Redefine(innerRect, SELF.view.printManager.paperLRect,
itsRes,
{pad resolutions}
itsView.res,
{viewed resolutions}
itsZoomFactor, itsPort);
{calls TPad's Redefine method}
{page's 'viewed space' has same metrics as the owning view's}
SELF.bodyPad.Recompute;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCini}
PROCEDURE {TMarginPad.}Free;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
Free(SELF.bodyPad);
TObject.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCpri}
PROCEDURE {TMarginPad.}SetForPage{(itsPageNumber: LONGINT; itsOrigin: Point)};
VAR innerRect: Rect;
newOffset: LPoint;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.pageNumber := itsPageNumber;
innerRect := SELF.innerRect;
OffsetRect(innerRect, itsOrigin.h - SELF.innerRect.left, itsOrigin.v - SELF.innerRect.top);
SELF.SetInnerRect(innerRect);
SELF.clippedRect := innerRect;
WITH innerRect DO
SetLPt(newOffset, - left, - top);
SELF.SetScrollOffset(newOffset);
SELF.bodyPad.SetForPage(itsPageNumber);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TMarginPad.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
TPad.Fields(Field);
Field('view: TView');
Field('pageNumber: LONGINT');
Field('bodyPad: TBodyPad');
Field('');
END;
{$S SgABCres}
{$ENDC}
{$IFC fDbgABC}
{$S SgABCdbg}
FUNCTION TMarginPad.BindHeap{(activeVsClip, doBind: BOOLEAN): THeap}; {called by HeapDump in UOBJECT2}
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
BindHeap := NIL;
(* IF activeWindowID <> 0 THEN {don't allow inactive windows to use this} -- WHY NOT????
BEGIN
IF activeVsClip THEN
BEGIN
(*
IF (currentDocument <> NIL) AND doBind THEN
BindHeap := currentDocument.docHeap;
IF (boundDocument <> NIL) AND doBind THEN
BindHeap := boundDocument.docHeap;
END
ELSE
IF currentDocument <> clipboard THEN
IF doBind THEN
BEGIN
hadToBindClip := boundClipboard = NIL;
IF hadToBindClip THEN
clipboard.Bind;
BindHeap := clipboard.docHeap;
END
ELSE IF hadToBindClip THEN
clipboard.Unbind;
END;
END;
{$S SgABCres}
{$ENDC}
*)
*)
{$S SgABCcld}
PROCEDURE {TMarginPad.}Crash;
BEGIN
{SELF = crashPad, presumably, but in any case, someone wants this process to die, so...}
IF isInitialized THEN
process.Complete(FALSE);
END;
{$S SgABCres}
PROCEDURE TMarginPad.SetScrollOffset(VAR newOffset: LPoint);
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF fExperimenting OR NOT amPrinting THEN
SUPERSELF.SetScrollOffset(newOffset)
ELSE
WITH SELF DO
BEGIN
scrollOffset := newOffset;
origin := zeroPt;
cdOffset := newOffset;
{+SW+}
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCini}
END;
{$S SgABCres}
METHODS OF TBodyPad;
{$S SgABCini}
FUNCTION {TBodyPad.}CREATE{(object: TObject; heap: THeap; itsMarginPad: TMarginPad): TBodyPad};
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TBodyPad(object);
SELF.marginPad := itsMarginPad;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TBodyPad.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
TPad.Fields(Field);
Field('marginPad: TMarginPad');
Field('nonNullBody: Rect');
END;
{$S SgABCres}
{$ENDC}
{$S SgABCpri}
PROCEDURE {TBodyPad.}Focus;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
SELF.ClipFurtherTo(SELF.nonNullBody);
TPad.Focus;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCpri}
PROCEDURE {TBodyPad.}Recompute;
VAR myViewedLRect: LRect;
myInnerRect:
Rect;
view:
TView;
marginPad:
TMarginPad;
bodyRect:
Rect;
printManager:
TPrintManager;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
marginPad := SELF.marginPad;
view := marginPad.view;
printManager := view.printManager;
printManager.GetPageLimits(marginPad.pageNumber, myViewedLRect);
marginPad.LRectToRect(printManager.contentLRect, myInnerRect);
WITH marginPad.origin DO {$H-}
OffsetRect(myInnerRect, -h, -v); {$H+}
SELF.Redefine(myInnerRect, myViewedLRect, marginPad.padRes,
view.res, marginPad.zoomFactor, SELF.marginPad.port);
bodyRect.topLeft := SELF.innerRect.topLeft;
SELF.LPtToPt(myViewedLRect.botRight, bodyRect.botRight);
bodyRect.botRight := Point(FPtMinusPt(bodyRect.botRight, SELF.origin));
SELF.nonNullBody := bodyRect;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCpri}
PROCEDURE {TBodyPad.}SetForPage{(itsPageNumber: LONGINT)};
VAR myViewedLRect: LRect;
myInnerRect:
Rect;
bodyRect:
Rect;
printManager:
TPrintManager;
newOffset:
LPoint;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
printManager := SELF.marginPad.view.printManager;
printManager.GetPageLimits(itsPageNumber, myViewedLRect);
SELF.marginPad.LRectToRect(printManager.contentLRect, myInnerRect);
WITH SELF.marginPad.origin DO {$H-}
OffsetRect(myInnerRect, -h, -v); {$H+}
SELF.SetInnerRect(myInnerRect);
WITH SELF, newOffset, scaleFactor DO
BEGIN
viewedLRect := myViewedLRect;
availLRect := myViewedLRect;
{$H-} InsetLRect(availLRect, -8192, -8192); {$H+}
clippedRect := myInnerRect;
IF scaled THEN
BEGIN
{$H-}
h := LIntOvrInt(LIntMulInt(myViewedLRect.left, numerator.h), denominator.h) {+++LSR+++}
- myInnerRect.left;
v := LIntOvrInt(LIntMulInt(myViewedLRect.top, numerator.v), denominator.v) {+++LSR+++}
- myInnerRect.top; {$H+}
END
ELSE
BEGIN
h := myViewedLRect.left - myInnerRect.left;
v := myViewedLRect.top - myInnerRect.top;
END;
END;
SELF.SetScrollOffset(newOffset);
SELF.nonNullBody := SELF.innerRect;
SELF.LPtToPt(myViewedLRect.botRight, SELF.nonNullBody.botRight);
SELF.nonNullBody.botRight := Point(FPtMinusPt(SELF.nonNullBody.botRight, SELF.origin)); {$H+}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$H-}
{+SW+}
{$S SgABCini}
END;
{$S SgABCres}
METHODS OF TScroller;
{$S sCldInit}
FUNCTION {TScroller.}CREATE{(object: TObject; heap: THeap; itsScrollBar: TScrollBar; itsId: TSBoxID)
:TScroller};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TScroller(object);
WITH SELF DO
BEGIN
scrollBar := itsScrollBar;
band := NIL;
sBoxID := itsId;
{$H-} SetSbRefcon(POINTER(sBoxID), ORD(SELF)); {$H+}
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S SgABCini}
PROCEDURE {TScroller.}Free;
VAR sbList: TSbList;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
PreSbList(sbList, SELF.scrollBar);
{$H-} KillSb(sbList, POINTER(SELF.sBoxID)); {$H+}
PostSbList(sbList, SELF.scrollBar);
TObject.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TScroller.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
Field('scrollBar: TScrollBar');
Field('band: TBand');
Field('sBoxID: LONGINT');
END;
{$S SgABCres}
{$ENDC}
{$S sScroll}
PROCEDURE {TScroller.}FillIcon{(icon: TEnumIcons; fBlack: BOOLEAN)};
TYPE TIconAlias =
RECORD
CASE INTEGER OF
1: (sblib: TIcon);
2: (abc:
TEnumIcons);
END;
VAR iconAlias:
TIconAlias;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
iconAlias.abc := icon;
PaintArw(POINTER(SELF.sBoxID), iconAlias.sblib, fBlack);
END;
{$S sRes}
PROCEDURE {TScroller.}GetSize{(VAR boxRect: Rect)};
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
GetSbRect(POINTER(SELF.sBoxID), boxRect);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sScroll}
PROCEDURE {TScroller.}MoveThumb{(newThumbPos: INTEGER)};
{NOTE: assumes we are focused on the window, NOT on a pane}
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
IF activeWindowID <> 0 THEN
BEGIN
SetupMvThumb(POINTER(SELF.sboxID));
MoveThumb(newThumbPos);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sSplit}
PROCEDURE {TScroller.}ResplitAt{(newSkwrCd: INTEGER; prevScroller: TScroller)};
VAR vhs:
VHSelect;
sbRect:
Rect;
prevSbRect: Rect;
hsb:
THSb;
deltaCd:
INTEGER;
minSize:
INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
vhs := SELF.ScrollDir;
minSize := dptSkewer.vh[vhs];
hsb := POINTER(SELF.sBoxID);
GetSbRect(hsb, sbRect);
prevScroller.GetSize(prevSbRect);
{If either scroller to becomes too small, delete it}
IF newSkwrCd <= prevSbRect.topLeft.vh[vhs] + minSize THEN
newSkwrCd := prevSbRect.topLeft.vh[vhs]
ELSE IF newSkwrCd >= sbRect.botRight.vh[vhs] - minSize THEN
newSkwrCd := sbRect.botRight.vh[vhs];
deltaCd := newSkwrCd - sbRect.topLeft.vh[vhs];
AdjSplitBetween(POINTER(prevScroller.sBoxID), hsb, deltaCd);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sRes}
FUNCTION {TScroller.}ScrollDir{: VHSelect};
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
ScrollDir := TyVHOfSb(POINTER(SELF.sBoxID));
{$IFC fTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE {TScroller.}SetSize{(ownerRect: Rect)};
VAR sbRect: Rect;
vhs: VHSelect;
width: INTEGER;
{ownerRect is the band's outerRect.
For v bar: top/bottom = ownerRect top/bottom
left
= ownerRect right - 1
right
= left + dhSBox}
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
vhs := orthogonal[SELF.ScrollDir];
sbRect := ownerRect;
sbRect.topLeft.vh[vhs] := sbRect.botRight.vh[vhs] - 1;
IF SELF.scrollBar.isVisible THEN
width := dptSbox.vh[vhs]
ELSE
width := 0;
sbRect.botRight.vh[vhs] := sbRect.topLeft.vh[vhs] + width;
SetSbRect(POINTER(SELF.sBoxID), sbRect);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sSplit}
PROCEDURE {TScroller.}SplitAt{(newSkwrCd: INTEGER; VAR nextScroller: TScroller)};
VAR newHsb: THsb;
sbList: TSbList;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
PreSbList(sbList, SELF.scrollBar);
SplitSb(sbList, POINTER(SELF.sBoxID), newHsb, newSkwrCd);
PostSbList(sbList, SELF.scrollBar);
nextScroller := TScroller.CREATE(NIL, SELF.Heap, SELF.scrollBar, ORD(newHsb));
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
{$S sScroll}
FUNCTION {TScroller.}ThumbRange{: INTEGER};
VAR posts: TPosts;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
MkPosts(POINTER(SELF.sBoxID), posts);
ThumbRange := posts[iconGryB] - posts[iconPagA] - dptThumb.vh[SELF.ScrollDir];
{$IFC fTrace}EP;{$ENDC}
END;
{$S sSplit}
PROCEDURE {TScroller.}TrackSkewer{(mousePt: Point; VAR newSkwrCd: INTEGER;
VAR scroller, prevScroller: TScroller)};
VAR hsb, prevHsb:
THsb;
sbList:
TSbList;
limitRect:
Rect;
newSkwrPt:
Point;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
hsb := POINTER(SELF.sBoxID);
FixRLimits(hsb, limitRect);
AlignRect(limitRect, SELF.band.outerRect, orthogonal[SELF.ScrollDir]);
DragSkewer(hsb, mousePt, limitRect, newSkwrPt);
newSkwrCd := newSkwrPt.vh[SELF.ScrollDir];
prevHsb:= HsbPrev(hsb);
IF prevHsb = hsbNil THEN
BEGIN
PreSbList(sbList, SELF.scrollBar);
hsb := HsbFromPt(sbList, newSkwrPt);
PostSbList(sbList, SELF.scrollBar);
IF hsb = hsbNil THEN
scroller := NIL
ELSE
scroller := POINTER(RefconSb(hsb));
prevScroller := NIL;
END
ELSE
BEGIN
scroller := SELF;
prevScroller := POINTER(RefconSb(prevHsb));
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sScroll}
PROCEDURE {TScroller.}TrackThumb{(mousePt: Point; VAR oldThumbPos, newThumbPos: INTEGER)};
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
oldThumbPos := CThumbPos(POINTER(SELF.sBoxID));
DragThumb(POINTER(SELF.sBoxID), mousePt, newThumbPos);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCini}
END;
{$S SgABCres}
METHODS OF TScrollBar;
{$S SgABCini}
FUNCTION {TScrollBar.}CREATE{(object: TObject; heap: THeap; vhs: VHSelect; outerRect: Rect;
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE {TScrollBar.}Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN
Field('firstBox: TScroller');
Field('isVisible: BOOLEAN');
Field('');
END;
{$S SgABCres}
{$ENDC}
{$S sCldInit}
PROCEDURE {TScrollBar.}ChangeVisibility{(needsBothBars: BOOLEAN;
bandOuterRect: Rect; itsAbilities: TAbilities)};
VAR hsb:
THsb;
scroller:
TScroller;
needsThisBar:
BOOLEAN;
icons:
TSIcon;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
needsThisBar := needsBothBars OR (aBar IN itsAbilities);
SELF.isVisible := needsThisBar;
icons := [];
IF needsThisBar THEN
{$S sStartup}
PROCEDURE {TScrollBar.}Draw;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.isVisible THEN
PaintSbar(POINTER(SELF.firstBox.sBoxID));
{$IFC fTrace}EP;{$ENDC}
END;
{$S sStartup}
PROCEDURE {TScrollBar.}Erase;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.isVisible THEN
EraseSBar(POINTER(SELF.firstBox.sBoxID));
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCini}
END;
{$S SgABCres}
{$S SgABCini}
(*
>>>>>>>>
U D I A L O G
<<<<<<<<
*)
{$SETC forOS := TRUE}
UNIT UDialog;
{04/25/84 0015
{04/23/84 1210
UABC,
UTKUniversalText,
UText;
The Dialog Building Block provides the following standard kinds of dialog Images:
Button
Checkbox
Cluster
InputFrame
Legend
A
A
A
A
A
Lisa-style button (a round-cornered Rectangle for pushing, with text inside it)
checkbox (a box for checking, plus an optional associated textual label)
set of related checkboxes of which only one is selected at a time
place for keyboard input to be inhaled
character string, together with font & face information
TextDialogImage
PicObject
The basic bankable dialog entity which can be stashed into/retrieved from a Resource File
is the class TDialog. For each different kind of dialog box you want, you will typically define
another subclass of TDialog.
To EDIT a dialog interactively, you must:
(1) Have the menu items 'Edit Dialog' and 'Stop Editing Dialog' in your phrase-file
(2) If the dialog is viewed in your main window rather than in a dialog box, (such as Preferences)
then your own main Window.CanDoCmd should enable uEditDialog whenever the dialog to be editted
is unambiguously selected in the window and there is not a dialog box up; in this
case, the dialog editting takes place in a dialog box whereas the dialog itself resides
in the main window.
CAUTION: Until Resource Files are incoporated, the edits to a dialog are local to the document
in which you made the edits, as well as documents made from a stationery pad made from
that document.
How to have your own view be a subclass of TDialogView, and still do all of its normal View things,
while having the Dialog Building Block handle everything that occurs which is relevant to
its dialogs:
(a) To draw the non-dialog parts of the view, implement method TDialogView.XDraw
(b) To set the cursor in the non-dialog parts of the view, implement method TDialogView.XCursorAt
(c) Implement XMousePress, XMouseMove, and XMouseRelease instead of their non-x counterparts
*)
TYPE
S4 = STRING[4];
TId = STRING[IDLength];
TButtonMetrics =
RECORD
height:
curvH:
curvV:
INTEGER;
INTEGER;
INTEGER;
typeStyle:
TTypeStyle;
expandNum:
expandDen:
INTEGER;
INTEGER;
INTEGER;
PenState;
absMinWidth:
penState:
END;
TStringKey =
RECORD
trueKey:
key:
END;
{-------------------------------------------------------------------------------------------------------}
{ ********* CLASSES ********* }
{ -------------------------------- classes implemented in file UDialog2 ------------------------------- }
TDialogWindow = SUBCLASS of TDialogBox
controlPanel:
dialogView:
mainDialog:
TPanel;
TDialogView;
TDialog;
{One with a dialogView in it; may be told to push its dflt button}
{the view installed in SELF.controlPanel}
{the first dialog installed in SELF.dialogView}
{Creation/Destruction}
FUNCTION TDialogWindow.CREATE(object: TObject; heap: THeap; itsResizability: BOOLEAN;
itsHeight: INTEGER; itsKeyResponse, itsMenuResponse, itsDownInMainWindowResponse: TDiResponse)
: TDialogWindow;
{Showing and Hiding}
PROCEDURE TDialogWindow.Appear; OVERRIDE;
PROCEDURE TDialogWindow.BeDismissed; OVERRIDE;
FUNCTION TDialogWindow.CanDoCommand(cmdNumber: TCmdNumber; VAR checkIt: BOOLEAN): BOOLEAN;
PROCEDURE TDialogWindow.Disappear; OVERRIDE;
OVERRIDE;
{Commands}
FUNCTION TDialogWindow.NewCommand(cmdNumber: TCmdNumber): TCommand; OVERRIDE;
END;
{TDialogWindow interface}
{-------------------------------------------------------------------------------------------------------}
{a view which contains dialog images as well as, possibly, other things}
rootDialog:
TDialog;
{The children of this object are the constituent Dialogs of this view}
nonDialogExtent:
LRect;
TButton;
TButton;
BOOLEAN;
paintFreeBoxes:
paintSense:
startedPainting:
BOOLEAN;
BOOLEAN;
BOOLEAN;
styleSheet:
mouseIsDown:
magnetCursor:
BOOLEAN;
TCursorNumber; {to force CursorAt to return this value until mouseIsDown is FALSE}
checkboxes}
TDialogView.AbandonThatButton;
TDialogView.ButtonPushed(button: TButton);
{normally, TDialog's ButtonPushed is used}
TDialogView.CheckboxHit(checkbox: TCheckbox; toggleDirection: BOOLEAN);
TDialogView.PushButton(button: TButton);
{client or ToolKit may call}
TDialogView.SetDefaultButton(button: TButton);
{NB:
PushButton sets the dialogView's hitButton to the requested button, assures that it
is highlighted, and then calls the client's ButtonPushed method of the TDialog which
is the parent of the button}
{ *** Private
FUNCTION
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
END;
{TDialogView interface}
{-------------------------------------------------------------------------------------------------------}
TDialogImage = SUBCLASS OF TImage
parent:
isActive:
isEditable:
withID:
TDialogImage;
BOOLEAN;
BOOLEAN;
BOOLEAN;
{Creation/destruction}
FUNCTION TDialogImage.CREATE(object: TObject; heap: THeap; itsExtent: LRect; itsId: S255;
itsView: TView; withChildren: BOOLEAN): TDialogImage;
PROCEDURE
FUNCTION
PROCEDURE
PROCEDURE
FUNCTION
PROCEDURE
PROCEDURE
FUNCTION
FUNCTION
END;
{-------------------------------------------------------------------------------------------------------}
TDialog = SUBCLASS OF TImageWithID
stringKey:
TStringKey;
{Creation}
FUNCTION
{Elements originating from phrase file; in each case, the text for the legend associated with the
component, if any, as well as a LOCATION for the component, are obtained from the same entry
in the phrase file, with the syntax
<text>@<h-coordinate>,<v-coordinate>
EXAMPLE:
449
Next@430,50
If we call NewButton(449, ...), then a button is created, with the text 'Next' inside it;
the button is given idNumber 449, and is located at (430, 50)}
{***************************** PUBLIC INTERFACE -- USE THESE METHODS ************************************}
FUNCTION
FUNCTION
TCmdNumber;
INTEGER;
BOOLEAN;
TButton;
legend:
buttonMetrics:
TLegend;
TButtonMetrics;
{Creation/Destruction}
FUNCTION TButton.CREATE(object: TObject; heap: THeap; itsId: S255; itsView: TView;
itsLocation: LPoint; itsMetrics: TButtonMetrics; sameSizedButton: TButton;
itsCmdNumber: TCmdNumber): TButton;
PROCEDURE
PROCEDURE
FUNCTION
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
FUNCTION
TButton.DrawJustMe; OVERRIDE;
TButton.Highlight(highTransit: THighTransit);
TButton.LaunchLayoutBox(view: TView): TImage; OVERRIDE;
TButton.MousePress(mouseLPt: LPoint); OVERRIDE;
TButton.MouseRelease; OVERRIDE;
TButton.RecalcExtent; OVERRIDE;
TButton.Recompute(minWidth: INTEGER);
TButton.StillMyMouse(mouseLPt: LPoint): BOOLEAN; OVERRIDE;
BOOLEAN;
rectImage:
legend:
TRectImage;
TLegend;
{also a child}
{if nonnil, also a child}
TCheckbox.ChangeLabel(newS255: S255);
TCheckbox.CursorAt(mouseLPt: LPoint): TCursorNumber; OVERRIDE;
TCheckbox.Draw; OVERRIDE;
TCheckbox.LaunchLayoutBox(view: TView): TImage; OVERRIDE;
TCheckbox.MousePress(mouseLPt: LPoint); OVERRIDE;
TCheckbox.Toggle;
{TCheckbox interface}
{-------------------------------------------------------------------------------------------------------}
TCluster = SUBCLASS of TImageWithID
{children:
TList;
location:
LPoint;
(of TCheckbox) }
{only used for adding the first aligned checkbox}
hitBox:
hiLitBox:
lastBox:
FUNCTION
{******
******
******
******
******
******
TCheckbox;
TCheckbox;
TCheckBox;
PUBLIC INTERFACE:
Create a cluster using TDialog.NewCluster; add checkboxes to it by calling any of the following
three methods. To change which box is selected in the cluster programmatically, call SelectBox
To find out which box is selected in a cluster, look at cluster.hiLitBox.idNumber}
FUNCTION
FUNCTION
TTextDialogImage;
TLegend;
borders:
Rect;
drawInputLRect:
BOOLEAN;
drawHitLRect:
maxInputChars:
inputTypeStyle:
{TInputFrame interface}
{-------------------------------------------------------------------------------------------------------}
TLegend = SUBCLASS OF TDialogImage
location:
paragraph:
wouldBeDraggable:
usesSysFont:
LPoint;
TParagraph;
BOOLEAN;
BOOLEAN;
TPicObject = SUBCLASS OF TImageWithID {An Object which holds a QD Picture File} {CAUTION: totally untested}
picture:
boxAtCreation:
PicHandle;
Rect;
{need to get itsView parameter into all these guys}
penState: PenState;
FUNCTION TRectImage.CREATE(object: TObject; heap: THeap; itsExtent: LRect; itsId: S255;
itsView: TView; itsPenState: PenState; withChildren: BOOLEAN): TRectImage;
PROCEDURE TRectImage.Draw; OVERRIDE;
FUNCTION TRectImage.LaunchLayoutBox(view: TView): TImage; OVERRIDE;
END;
{-------------------------------------------------------------------------------------------------------}
TTextDialogImage = SUBCLASS OF TImageWithID
textImage:
wouldBeDraggable:
refCount:
TTextImage;
BOOLEAN;
INTEGER;
FUNCTION
TTextDialogImage.ChangeRefCountBy(delta: INTEGER);
TTextDialogImage.CursorAt(mouseLPt: LPoint): TCursorNumber; OVERRIDE;
TTextDialogImage.Draw; OVERRIDE;
TTextDialogImage.LaunchLayoutBox(view: TView): TImage; OVERRIDE;
TTextDialogImage.MousePress(mouseLPt: LPoint); OVERRIDE;
TTextDialogImage.OffsetBy(deltaLPt: LPoint); OVERRIDE;
{-------------------------------------------------------------------------------------------------------}
TFrameSelection = SUBCLASS OF TSelection
inputFrame: TInputFrame;
FUNCTION
FUNCTION
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
END;
{TFrameSelection interface}
{Variables}
viewBeingPlanned:
TView;
allowSketching:
retainPickedBox:
currentLayoutBox:
BOOLEAN;
{for internal use of the layout mechanism}
BOOLEAN;
TLayoutBox;
{Creation/Destruction}
FUNCTION TPlannerView.CREATE(object: TObject; heap: THeap; itsViewBeingPlanned: TView;
itsPanel: TPanel; itsAllowSketching: BOOLEAN; itsRetainPickedBox: BOOLEAN): TPlannerView;
TImage;
TTitleTab;
suppressDrawingManipulee:
BOOLEAN;
isResizable:
borders:
wouldMakeSelection:
BOOLEAN;
Rect;
BOOLEAN;
isDraggable:
shouldFrame:
BOOLEAN;
BOOLEAN;
hasDraggee:
BOOLEAN;
{Creation/Destruction}
FUNCTION TLayoutBox.CREATE(object: TObject; heap: THeap; baseExtent: LRect; itsID: S255;
itsParent: TLayoutBox; itsView: TView; itsManipulee: TImage; itsBorders: Rect;
itsResizable: BOOLEAN; itsSuppression: BOOLEAN; withChildren: BOOLEAN): TLayoutBox;
PROCEDURE TLayoutBox.Free; OVERRIDE;
{Change and Display}
PROCEDURE TLayoutBox.ChangeDragState(enteringDrag: BOOLEAN);
PROCEDURE TLayoutBox.ConsiderMouse(mouseLPt: LPoint; VAR madeSelection: BOOLEAN;
FUNCTION
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
FUNCTION
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
END;
TLegendLayoutBox = SUBCLASS OF TLayoutBox
textDialogImage:
{manipulee is a TLegend}
TTextDialogImage;
{Creation/Destruction}
FUNCTION TLegendLayoutBox.CREATE(object: TObject; heap: THeap; itsView: TView; itsLegend: TLegend
): TLegendLayoutBox;
FUNCTION TLegendLayoutBox.CursorAt(mouseLPt: LPoint): TCursorNumber; OVERRIDE;
PROCEDURE TLegendLayoutBox.Draw; OVERRIDE;
PROCEDURE TLegendLayoutBox.OffsetBy(deltaLPt: LPoint); OVERRIDE;
PROCEDURE TLegendLayoutBox.OffsetLayoutBoxBy(deltaLPt: LPoint; textImageAsWell: BOOLEAN); OVERRIDE;
{use of the second argument is strange and non self-explanatory; comments in the internal
documentation may help. Nobody should be calling this old boy from outside, anyway}
PROCEDURE TLegendLayoutBox.MousePress(mouseLPT: LPoint); OVERRIDE;
PROCEDURE TLegendLayoutBox.RecalcExtent; OVERRIDE;
END;
TButtonLayoutBox = SUBCLASS OF TLayoutBox
{Variables}
nextSameSizedBox:
oldLegendTopLeft:
{manipulee is a TButton}
TButtonLayoutBox;
LPoint;
{Creation/Destruction}
FUNCTION TButtonLayoutBox.CREATE(object: TObject; heap: THeap; itsButton: TButton;
itsView: TView): TButtonLayoutBox;
{Other Methods}
TLayoutBox;
TLegend;
BOOLEAN; {FALSE if string is too wide to fit}
TLayoutBox;
FUNCTION
FUNCTION
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
END;
{Variables}
layoutBox:
hOffset:
vOffset:
{Creation}
FUNCTION
TLayoutBox;
LONGINT;
LONGINT;
{Command Execution}
PROCEDURE TLayMoveCmd.Perform(cmdPhase: TCmdPhase); OVERRIDE;
END;
TEditLegendSelection = SUBCLASS OF TSelection
{Variables}
legendLayoutBox:
hostLegend:
textDialogImage:
suppressHost:
tripleClick:
TLegendLayoutBox;
TLegend;
TTextDialogImage;
BOOLEAN;
BOOLEAN; {+SW+}
{Creation/Destruction}
FUNCTION TEditLegendSelection.CREATE(object: TObject; heap: THeap; itsLegendLayoutBox:
TLegendLayoutBox; itsAnchorLPt: LPoint): TEditLegendSelection;
FUNCTION TEditLegendSelection.Clone(heap: THeap): TObject; OVERRIDE;
PROCEDURE TEditLegendSelection.Deselect; OVERRIDE;
PROCEDURE TEditLegendSelection.Free; OVERRIDE;
{Udders}
FUNCTION
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
FUNCTION
PROCEDURE
PROCEDURE
PROCEDURE
END;
TWindow;
TDialogView;
BOOLEAN;
FUNCTION
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
TStdPrintManager.EnterPageEditting; OVERRIDE;
TStdPrintManager.Init(itsMainView: TView; itsDfltMargins: LRect); OVERRIDE;
TStdPrintManager.ReactToPrinterChange; OVERRIDE;
TStdPrintManager.SetDfltHeadings; OVERRIDE;
END;
TLegendHeading = SUBCLASS OF THeading
masterLegend:
currentLegend:
TLegend;
TLegend;
topToBaseline:
borders:
{Creation/Destruction}
FUNCTION TLegendHeading.CREATE(object: TObject; heap: THeap; itsPrintManager: TPrintManager;
itsString: S255; itsTypeStyle: TTypeStyle;
itsPageAlignment: TPageAlignment; itsOffsetFromAlignment: LPoint;
END;
TPageDesignWindow = SUBCLASS OF TDialogWindow
hostView:
layoutPanel:
FUNCTION
TView; {the view whose pages are being designed in this dialog}
TPanel; {my controlPanel is the status panel}
OVERRIDE;
END;
TPagePlannerView = SUBCLASS OF TPlannerView
FUNCTION TPagePlannerView.CREATE(object: TObject; heap: THeap; itsPrintManager: TPrintManager;
itsPanel: TPanel): TPagePlannerView;
PROCEDURE TPagePlannerView.Draw; OVERRIDE;
END;
TPageStatusDialog = SUBCLASS OF TDialog
currentHeading:
THeading;
oddEvenCluster:
minPageFrame:
maxPageFrame:
alignCluster:
unitsCluster:
marginTitle:
TCluster;
TInputFrame;
TInputFrame;
TCluster;
TCluster;
TLegend;
leftCluster:
topCluster:
rightCluster:
bottomCluster:
TCluster;
TCluster;
TCluster;
TCluster;
{Creation/Destruction}
FUNCTION TPageStatusDialog.CREATE(object: TObject; heap: THeap; itsPanel: TPanel): TPageStatusDialog;
{Sonst}
PROCEDURE
PROCEDURE
FUNCTION
PROCEDURE
PROCEDURE
END;
VAR
stdFrameBorders:
stdHdngBorders:
stdHdngTypeStyle:
stdIDBorders:
stdInputTypeStyle:
stdFrmeOffset:
stdLabelOffset:
Rect;
Rect;
TTypeStyle;
Rect;
TTypeStyle;
Point;
Point;
{Unit-Global Procedures}
FUNCTION
FUNCTION
FUNCTION
NewSysLegend(heap: THeap; itsChars: S255; itsXLoc, itsYLoc: LONGINT; itsView: TView): TLegend;
PROCEDURE SetParaExtent(paragraph: TParagraph; view: TView; location: LPoint; VAR extentLRect: LRect);
PROCEDURE LRectAddBorders(baseLRect: LRect; borders: Rect; VAR resultLRect: LRect);
PROCEDURE GetTextAndLocation(phraseNumber: INTEGER; VAR itsChars: S255; VAR itsLocation: LPoint);
IMPLEMENTATION
{$I LIBTK/UDialog2}
{$I LIBTK/UDialog3}
{$I LIBTK/UDialog4}
(**********
{$I UDialog2}
{$I UDialog3}
{$I UDialog4}
**********)
{dialogs}
{layout}
{page margins}
{dialogs}
{layout}
{page margins}
END.
{unit UDialog}
(*
UDialog2
TDialogWindow -- TDialogView -- TDialogImage -- TImageWithID
TButton -- TCheckbox -- TCluster -- TInputFrame -- TLegend
-- TDialog
--
*)
{04/23/84
{04/23/84
{04/15/84
{04/04/84
{01/29/84
{12/22/83
1210
1210
2345
2300
1750
1927
{$IFC fRngABC}
{$R+}
{$ELSEC}
{$R-}
{$ENDC}
{$IFC fSymABC}
{$D+}
{$ELSEC}
{$D-}
{$ENDC}
VAR copyRight: STRING[45];
{----------------------------------------------------------------------------------------------------------}
{$S DlgAlloc}
PROCEDURE GetTextAndLocation(phraseNumber: INTEGER; VAR itsChars: S255; VAR itsLocation: LPoint);
VAR rawPhrase: S255;
restOfIt:
S255;
morsel:
S255;
semiColon: INTEGER;
comma:
INTEGER;
aLocation: LPoint;
FUNCTION OKIntegerValue(Str: S255; VAR itsValue: LONGINT): BOOLEAN;
VAR result: TConvResult;
BEGIN
(*
{$S DlgAlloc}
FUNCTION NewStdDialogWindow(heap: THeap; itsHeight: INTEGER; itsKeyResponse,
itsMenuResponse, itsDownInMainWindowResponse: TDiResponse): TDialogWindow;
VAR dialogWindow:
TDialogWindow;
panel:
TPanel;
dialogView:
TDialogView;
extentLRect:
LRect;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
dialogWindow := TDialogWindow.CREATE(NIL, heap, FALSE {not resizable}, itsHeight,
itsKeyResponse, itsMenuResponse, itsDownInMainWindowResponse);
panel := TPanel.CREATE(NIL, heap, dialogWindow, 0, screenBits.bounds.right, [], []);
dialogWindow.controlPanel := panel;
SetLRect(extentLRect, 0, 0, screenBits.bounds.right, screenBits.bounds.bottom - 40);
dialogView := TDialogView.CREATE(NIL, heap, extentLRect, panel, NIL, screenRes);
dialogWindow.dialogView := dialogView;
NewStdDialogWindow := dialogWindow;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
FUNCTION NewSysLegend(heap: THeap; itsChars: S255; itsXLoc, itsYLoc: LONGINT; itsView: TView): TLegend;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
NewSysLegend := NewStdLegend(heap, itsChars, itsXLoc, itsYLoc, itsView, sysTypeStyle);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
FUNCTION NewStdLegend(heap: THeap; itsChars: S255; itsXLoc, itsYLoc: LONGINT; itsView: TView;
itsTypeStyle: TTypeStyle): TLegend;
VAR itsString:
S255;
itsLocation:
LPoint;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SetLPt(itsLocation, itsXLoc, itsYLoc); {=}
NewStdLegend := TLegend.CREATE(NIL, heap, itsChars, itsView, itsLocation, itsTypeStyle);
{$IFC fTrace}EP;{$ENDC}
END;
METHODS OF TDialogWindow;
{$S DlgAlloc}
FUNCTION TDialogWindow.CREATE(object: TObject; heap: THeap; itsResizability: BOOLEAN; itsHeight: INTEGER;
itsKeyResponse, itsMenuResponse, itsDownInMainWindowResponse: TDiResponse): TDialogWindow;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TDialogWindow(TDialogBox.CREATE(object, heap, itsResizability, itsHeight, itsKeyResponse,
itsMenuResponse, itsDownInMainWindowResponse));
SELF.controlPanel := SELF.selectPanel; {If not holding a TDialogView, client must reset}
SELF.dialogView := NIL;
SELF.mainDialog := NIL;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TDialogWindow.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('controlPanel: TPanel');
Field('dialogView: TDialogView');
Field('mainDialog: TDialog');
Field('');
END;
{$ENDC}
{$S DlgHot}
PROCEDURE TDialogWindow.Appear;
PROCEDURE TellYourView(obj: TObject);
PROCEDURE YouPrepare(obj: TObject);
BEGIN
TDialogImage(obj).PrepareToAppear;
END;
BEGIN
IF InClass(TPanel(obj).view, TDialogView) THEN
TDialogView(TPanel(obj).view).EachActualPart(YouPrepare);
END;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SUPERSELF.Appear;
SELF.panels.Each(TellYourView);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TDialogWindow.BeDismissed;
VAR dialogView:
TDialogView;
defaultButton: TButton;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
PushFocus;
SELF.Focus;
IF InClass(SELF.controlPanel.view, TDialogView) THEN
BEGIN
dialogView := TDialogView(SELF.controlPanel.view);
defaultButton := dialogView.defaultButton;
IF defaultButton <> NIL THEN
dialogView.PushButton(defaultButton)
{may want to put in a delay loop here to assure hilit button seen}
ELSE {dialog box has no default button; just take it down}
currentWindow.TakeDownDialogBox;
END
ELSE
{not a dialogView up there--must be a layout view}
currentWindow.TakeDownDialogBox;
PopFocus;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
FUNCTION TDialogWindow.CanDoCommand(cmdNumber: TCmdNumber; VAR checkIt: BOOLEAN): BOOLEAN;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
CASE cmdNumber OF
uEditDialog:
CanDoCommand := TRUE;
OTHERWISE
stdBottomBorder);
SetRect(stdIDBorders , - stdLeftRightMargin, -stdTitleHeight - stdBottomBorder, stdLeftRightMargin,
stdBottomBorder);
SetRect(stdThinBorders , 0, -stdSlimTitleHeight, 0, 0);
SetPt(stdLabelOffset, 8, -2);
SetPt(stdFrmeOffset, 20, 0);
SetRect(stdFrameBorders, -30, -16, 30, 16);
SetRect(stdHdngBorders, -6, -12, 6, 4);
MakeTypeStyle(famModern, size12Pitch, [], stdInputTypeStyle);
MakeTypeStyle(famModern, size15Pitch, [], titleTypeStyle);
MakeTypeStyle(famModern, size12Pitch, [], stdHdngTypeStyle);
copyright := 'Copyright 1983, 1984 by Apple Computer, Inc.';
END;
METHODS OF TDialogView;
{$S DlgAlloc}
FUNCTION TDialogView.CREATE{(object: TObject; heap: THeap; itsExtentLRect: LRect; itsPanel: TPanel;
itsPrintManager: TPrintManager; itsRes: Point)};
VAR rootDialog:
TDialog;
dialogWindow:
TDialogWindow;
styleSheet:
TStyleSheet;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TDialogView(TView.CREATE(object, heap, itsPanel, itsExtentLRect, itsPrintManager, stdMargins,
(itsPrintManager <> NIL), itsRes, TRUE));
SELF.nonDialogExtent := itsExtentLRect;
rootDialog := TDialog.CREATE(NIL, heap, 'ROOT', SELF);
SELF.rootDialog := rootDialog; {create an empty master}
styleSheet := TStyleSheet.CREATE(NIL, heap);
SELF.styleSheet := styleSheet;
WITH SELF DO
BEGIN
isShowing := FALSE; {not yet actually put up}
currentDialogImage := NIL;
defaultButton := NIL;
hitButton := NIL;
paintFreeBoxes := FALSE; {client can set this to TRUE after the CREATE call}
paintSense := FALSE;
startedPainting := FALSE;
mouseIsDown := FALSE;
magnetCursor := noCursor;
END;
IF InClass(itsPanel.window, TDialogWindow) THEN
BEGIN
dialogWindow := TDialogWindow(itsPanel.window);
IF dialogWindow.controlPanel = NIL THEN
dialogWindow.controlPanel := itsPanel;
IF dialogWindow.dialogView = NIL THEN
dialogWindow.dialogView := SELF;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgCold}
PROCEDURE TDialogView.Free;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
Free(SELF.rootDialog);
Free(SELF.styleSheet);
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TDialogView.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('rootDialog: TDialog');
Field('nonDialogExtent: LRect');
Field('currentDialogImage: TDialogImage');
Field('defaultButton: TButton');
Field('hitButton: TButton');
Field('isShowing: BOOLEAN');
Field('paintFreeBoxes: BOOLEAN');
Field('paintSense: BOOLEAN');
Field('startedPainting: BOOLEAN');
Field('styleSheet: TStyleSheet');
Field('mouseIsDown: BOOLEAN');
Field('magnetCursor: INTEGER');
Field('');
END;
{$ENDC}
{$S DlgHot}
PROCEDURE TDialogView.AbandonThatButton;
PROCEDURE TurnOutTheLights;
BEGIN
SELF.hitButton.Highlight(hOnToOff);
END;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.hitButton <> NIL THEN
BEGIN
SELF.panel.OnAllPadsDo(TurnOutTheLights);
IF SELF.currentDialogImage = SELF.hitButton THEN
SELF.currentDialogImage := NIL;
SELF.hitButton := NIL;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
PROCEDURE TDialogView.AddDialog(dialog: TDialog);
VAR dialogWindow:
TDialogWindow;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.rootDialog.AddImage(dialog);
IF InClass(SELF.panel.window, TDialogWindow) THEN
BEGIN
dialogWindow := TDialogWindow(SELF.panel.window);
IF dialogWindow.mainDialog = NIL THEN
dialogWindow.mainDialog := dialog;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
FUNCTION TDialogView.AddNewDialog(itsKey: S4): TDialog;
VAR dialogWindow:
TDialogWindow;
dialog:
TDialog;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
{The client will occasionally want to override this, in order to change the display as an
immediate consequence of a Checkbox being toggled}
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
{ ... }
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
FUNCTION TDialogView.CursorAt(mouseLPt: LPoint): TCursorNumber;
VAR cursorNumber:
TCursorNumber;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
cursorNumber := noCursor;
IF SELF.mouseIsDown AND (SELF.magnetCursor <> noCursor) THEN
cursorNumber := SELF.magnetCursor
ELSE
BEGIN
IF LRectHasLPt(SELF.rootDialog.extentLRect, mouseLPt) THEN
cursorNumber := SELF.rootDialog.CursorAt(mouseLPt);
IF cursorNumber = noCursor THEN
cursorNumber := SELF.XCursorAt(mouseLPt);
END;
CursorAt := cursorNumber;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TDialogView.Draw;
VAR s:
TListScanner;
dialogImage:
TDialogImage;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.isShowing := TRUE; {update event triggered this}
SELF.rootDialog.Draw; {draw dialogs}
SELF.XDraw;
{draw other stuff}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TDialogView.EachActualPart(PROCEDURE DoToObject(filteredObj: TObject));
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.rootDialogImage.EachActualPart(doToObject);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TDialogView.MouseMove(mouseLPt: LPoint);
VAR currentDialogImage: TDialogImage;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
currentDialogImage := SELF.currentDialogImage;
IF currentDialogImage <> NIL THEN
IF NOT currentDialogImage.StillMyMouse(mouseLPt) THEN
currentDialogImage := NIL;
IF currentDialogImage = NIL THEN
BEGIN
currentDialogImage := SELF.rootDialog.DownAt(mouseLPt);
IF currentDialogImage = NIL THEN
SELF.XMouseMove(mouseLPt);
END;
SELF.currentDialogImage := currentDialogImage;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TDialogView.MousePress(mouseLPt: LPoint);
VAR panel:
TPanel;
takenBySelection:
BOOLEAN;
currentDialogImage: TDialogImage;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
panel := SELF.panel;
SELF.startedPainting := FALSE;
takenBySelection := FALSE;
SELF.mouseIsDown := TRUE;
SELF.magnetCursor := noCursor;
currentDialogImage := SELF.currentDialogImage;
IF (currentDialogImage <> NIL) AND (SELF.panel.selection.kind <> nothingKind) THEN
IF currentDialogImage.Hit(mouseLPt) THEN
BEGIN
SELF.panel.selection.MousePress(mouseLPt);
takenBySelection := TRUE;
END;
{$S DlgAlloc}
PROCEDURE TDialogView.RecalcExtent;
VAR newExtent: LRect;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF NOT EmptyLRect(SELF.rootDialog.extentLRect) THEN
BEGIN
IF NOT EmptyLRect(SELF.nonDialogExtent) THEN
UnionLRect(SELF.rootDialog.extentLRect, SELF.nonDialogExtent, newExtent);
SELF.Resize(newExtent);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
PROCEDURE TDialogView.RemoveDialog(dialog: TDialog; andFree: BOOLEAN);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.rootDialog.DeleteImage(dialog, andFree);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
PROCEDURE TDialogView.ReplaceDialog(oldDialog, newDialog: TDialog);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.rootDialog.ReplaceImage(oldDialog, newDialog);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
PROCEDURE TDialogView.SetDefaultButton(button: TButton);
VAR thickPnSize:
point;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.defaultButton := button;
SetPt(thickPnSize, 3, 2);
IF button <> NIL THEN
button.buttonMetrics.penState.pnSize := thickPnSize;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
FUNCTION TDialogView.XCursorAt(mouseLPt: LPoint): TCursorNumber;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
XCursorAt := arrowCursor;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TDialogView.XDraw;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TDialogView.XMousePress(mouseLPt: LPoint);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TDialogView.XMouseMove(mouseLPt: LPoint);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TDialogView.XMouseRelease;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
{----------------------------------------------------------------------------------------------------------}
METHODS OF TDialogImage;
{$S TK2Start}
FUNCTION TDialogImage.CREATE(object: TObject; heap: THeap; itsExtent: LRect; itsId: S255;
itsView: TView; withChildren: BOOLEAN): TDialogImage;
VAR newList:
TList;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TDialogImage(TImage.CREATE(object, heap, itsExtent, itsView));
WITH SELF DO
BEGIN
parent := NIL;
isActive := TRUE;
isEditable := TRUE;
withID := FALSE;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TDialogImage.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('parent: TDialogImage');
Field('isActive: BOOLEAN');
Field('isEditable: BOOLEAN');
Field('withID: BOOLEAN');
Field('');
END;
{$ENDC}
{$S DlgCold}
PROCEDURE TDialogImage.AddImage(dialogImage: TDialogImage);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
PROCEDURE TDialogImage.ActivateImage(dialogImage: TDialogImage; whichWay: BOOLEAN);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF dialogImage.isActive <> whichWay THEN {state needs to change}
BEGIN
dialogImage.isActive := whichWay;
SELF.view.panel.InvalLRect(dialogImage.extentLRect); {??? Want to recalc my extent here???}
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgCold}
PROCEDURE TDialogImage.BringToFront(dialogImage: TDialogImage);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgCold}
PROCEDURE TDialogImage.ComeForward;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.parent <> NIL THEN
SELF.parent.BringToFront(SELF);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TDialogImage.ControlHit(control: TDialogImage; toggleDirection: BOOLEAN);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.parent <> NIL THEN
SELF.parent.ControlHit(control, toggleDirection);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
PROCEDURE TDialogImage.DeleteImage(dialogImage: TDialogImage; andFree: BOOLEAN);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
FUNCTION TDialogImage.DownAt(mouseLPt: LPoint):
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.Hit(mouseLPt) THEN
BEGIN
SELF.MousePress(mouseLPt);
DownAt := SELF;
END
ELSE
DownAt := NIL;
{$IFC fTrace}EP;{$ENDC}
END;
TDialogImage;
{$S DlgHot}
PROCEDURE TDialogImage.Draw;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.DrawJustMe;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgDbg} {by design}
PROCEDURE TDialogImage.DrawJustMe;
BEGIN
{$IFC fTrace}BP(113);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TDialogImage.EachActualPart(PROCEDURE DoToObject(filteredObj: TObject));
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
{overrides TImage's version, does specifically Nothing; TImageWithID redefines}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
FUNCTION TDialogImage.HasId(id: S255): BOOLEAN;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
HasID := FALSE;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgLayout}
FUNCTION TDialogImage.LaunchLayoutBox(view: TView): TImage;
VAR myLayoutBox:
TLayoutBox;
plannerView:
TPlannerView;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF NOT SELF.isActive THEN
LaunchLayoutBox := NIL
ELSE
LaunchLayoutBox := TLayoutBox.CREATE(NIL, view.Heap, SELF.extentLRect, '', NIL,
view, SELF, stdPlainBorders, FALSE, FALSE, FALSE);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
FUNCTION TDialogImage.ObjectWithIDNumber(idNumber: INTEGER):
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
ObjectWithIDNumber := NIL;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
FUNCTION TDialogImage.ObjWithId(id: S255):
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
ObjWithId := NIL;
{$IFC fTrace}EP;{$ENDC}
END;
TDialogImage;
TDialogImage;
{$S DlgHot}
PROCEDURE TDialogImage.PrepareToAppear;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TDialogImage.RecalcExtent;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.parent <> NIL THEN
SELF.parent.RecalcExtent;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgCold}
PROCEDURE TDialogImage.ReplaceImage(replacee, newValue: TDialogImage);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
FUNCTION TDialogImage.StillMyMouse(mouseLPt: LPoint): BOOLEAN;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.Hit(mouseLPt) THEN
StillMyMouse := TRUE {I've handled it}
ELSE
StillMyMouse := FALSE; {give it to someone else}
{default; this will usually be overridden in subclass}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
METHODS OF TImageWithID;
{$S DlgHot}
FUNCTION TImageWithID.CREATE(object: TObject; heap: THeap; itsExtent: LRect; itsId: S255;
itsView: TView; withChildren: BOOLEAN): TImageWithID;
VAR newList:
TList;
newID:
TId;
cState:
TConvResult;
newIDNumber:
INTEGER;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TImageWithID(TDialogImage.CREATE(object, heap, itsExtent, itsID, itsView, withChildren));
newID := Copy(itsId, 1, MIN(idLength, LENGTH(itsId)));
StrUpperCased(@newID);
StrToInt(@newID, newIDNumber, cState);
IF cState <> cvValid THEN
newIDNumber := noIDNumber;
WITH SELF DO
BEGIN
id := newID;
idNumber := newIDNumber;
withId := TRUE;
END;
IF withChildren THEN
BEGIN
newList := TList.CREATE(NIL, heap, 0);
SELF.children := newList;
END
ELSE
SELF.children := NIL;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgWarm}
FUNCTION TImageWithID.Clone(heap: THeap): TObject;
VAR children:
TList;
copyOfMyself:
TImageWithID;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
copyOfMyself := TImageWithID(SUPERSELF.Clone(heap));
IF SELF.children <> NIL THEN
BEGIN
children := TList(SELF.children.Clone(heap));
copyOfMyself.children := children;
END;
Clone := copyOfMyself;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgWarm}
PROCEDURE TImageWithID.Free;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
Free(SELF.children);
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TImageWithID.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('children: TList');
Field('id: STRING[9]');
Field('idNumber: INTEGER');
Field('');
END;
{$ENDC}
{$S DlgHot}
PROCEDURE TImageWithID.ActivateImage(dialogImage: TDialogImage; whichWay: BOOLEAN);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF dialogImage.isActive <> whichWay THEN {state needs to change}
BEGIN
dialogImage.isActive := whichWay;
SELF.view.panel.InvalLRect(dialogImage.extentLRect);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TImageWithID.AddImage(dialogImage: TDialogImage);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.children.InsLast(dialogImage);
dialogImage.parent := SELF;
dialogImage.HaveView(SELF.view);
IF EmptyLRect(SELF.extentLRect) THEN
SELF.extentLRect := dialogImage.extentLRect
ELSE
{$H-}
UnionLRect(SELF.extentLRect, dialogImage.extentLRect, SELF.extentLRect); {$H+}
IF SELF.parent <> NIL THEN
SELF.parent.RecalcExtent;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TImageWithID.BringToFront(dialogImage: TDialogImage);
VAR s:
TListScanner;
image: TDialogImage;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.children <> NIL THEN
BEGIN
s := SELF.children.Scanner;
WHILE s.Scan(image) DO
IF image = dialogImage THEN
BEGIN
s.Delete(FALSE);
s.Done;
SELF.children.insLast(dialogImage);
END;
END;
IF SELF.parent <> NIL THEN
SELF.parent.BringToFront(SELF);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
FUNCTION TImageWithID.CursorAt(mouseLPt: LPoint): TCursorNumber;
VAR s:
TListScanner;
dialogImage:
TDialogImage;
cursorNumber:
TCursorNumber;
{default: just passes the request on to children until one sets it}
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
cursorNumber := noCursor;
IF LRectHasLPt(SELF.extentLRect, mouseLPt) THEN
IF SELF.children <> NIL THEN
BEGIN
s := SELF.children.Scanner;
WHILE s.Scan(dialogImage) DO
IF dialogImage.isActive THEN
BEGIN
cursorNumber := dialogImage.CursorAt(mouseLPt);
IF cursorNumber <> noCursor THEN
s.Done;
END;
END;
CursorAt := cursorNumber;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgCold}
PROCEDURE TImageWithID.DeleteImage(dialogImage: TDialogImage; andFree: BOOLEAN);
{deletes the indicated dialogImage from my children}
VAR s:
TListScanner;
aDialogImage:
TDialogImage;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
s:= SELF.children.Scanner;
WHILE s.Scan(aDialogImage) DO
IF aDialogImage = dialogImage THEN
BEGIN
IF (TDialogView(SELF.view).isShowing) AND (dialogImage.isActive) THEN
SELF.view.panel.InvalLRect(dialogImage.extentLRect);
s.Delete(andFree);
s.Done;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TImageWithID.Draw;
PROCEDURE YouDraw(obj: TObject);
VAR dialogImage: TDialogImage;
BEGIN
dialogImage := TDialogImage(obj);
IF dialogImage.isActive THEN
dialogImage.Draw;
END;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF LRectIsVisible(SELF.extentLRect) THEN
BEGIN
SELF.EachActualPart(YouDraw);
SELF.DrawJustMe;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TImageWithID.EachActualPart(PROCEDURE DoToObject(filteredObj: TObject));
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.children <> NIL THEN
SELF.children.Each(DoToObject);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TImageWithID.EachVirtualPart(PROCEDURE DoToObject(filteredObj: TObject));
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.EachActualPart(DoToObject); {???}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
FUNCTION TImageWithID.HasId(id: S255): BOOLEAN;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
{$H-} id := Copy(id, 1, MIN(idLength, LENGTH(id))); {$H+}
StrUpperCased(@id);
IF SELF.id = id THEN
HasId := TRUE
ELSE
HasId := FALSE;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TImageWithID.HaveView(view: TView);
PROCEDURE YouHaveView(obj: TObject);
VAR dialogImage: TDialogImage;
BEGIN
dialogImage := TDialogImage(obj);
dialogImage.HaveView(view);
END;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.view := view;
SELF.EachActualPart(YouHaveView);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgLayout}
FUNCTION TImageWithID.LaunchLayoutBox(view: TView): TImage;
VAR dialogImage:
TDialogImage;
newExtent:
LRect;
boxTitle:
S255;
theString:
TLegend;
childsLayoutBox:
TLayoutBox;
myLayoutBox:
TLayoutBox;
plannerView:
TPlannerView;
postChildExtent:
LRect;
withChildren:
BOOLEAN;
PROCEDURE YouMakeLayoutBoxes(obj: TObject);
VAR dialogImage:
TDialogImage;
interimImage:
TImage;
BEGIN
dialogImage := TDialogImage(obj);
interimImage := dialogImage.LaunchLayoutBox(view);
IF interimImage <> NIL THEN
BEGIN
childsLayoutBox := TLayoutBox(interimImage);
myLayoutBox.AddImage(childsLayoutBox);
UnionLRect(postChildExtent, childsLayoutBox.extentLRect, postChildExtent);
END;
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
FUNCTION TImageWithID.ObjWithId(id: S255): TDialogImage;
VAR s:
TListScanner;
dialogImage:
TDialogImage;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
id := Copy(id, 1, MIN(idLength, LENGTH(id)));
StrUpperCased(@id);
ObjWithId := NIL;
IF SELF.children <> NIL THEN
BEGIN
s := SELF.children.Scanner;
WHILE s.Scan(dialogImage) DO
IF dialogImage.withID THEN
IF TImageWithID(dialogImage).id = id THEN
BEGIN
ObjWithId := dialogImage;
s.Done;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TImageWithID.OffSetBy(deltaLPt: LPoint);
PROCEDURE YouOffset(obj: TObject);
BEGIN
TDialogImage(obj).OffsetBy(deltaLPt);
END;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
{$H-} OffsetLRect(SELF.extentLRect, deltaLPt.h, deltaLPt.v); {$H+}
SELF.EachActualPart(YouOffset); {tells children}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgWarm}
PROCEDURE TImageWithID.RecalcExtent;
VAR s:
TListScanner;
dialogImage:
newExtent:
TDialogImage;
LRect;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
{can be speeded up}
IF SELF.children <> NIL THEN
IF SELF.children.Size > 0 THEN
BEGIN
newExtent := zeroLRect;
s := SELF.children.Scanner;
WHILE s.Scan(dialogImage) DO
IF EmptyLRect(newExtent) THEN
newExtent := dialogImage.extentLRect
ELSE
UnionLRect(newExtent, dialogImage.extentLRect, newExtent);
SELF.Resize(newExtent);
END;
IF SELF.parent <> NIL THEN
SELF.parent.RecalcExtent;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgCold}
PROCEDURE TImageWithID.ReplaceImage(replacee, newValue: TDialogImage);
{make this such that it puts back at same place; or use Become}
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.DeleteImage(replacee, TRUE);
SELF.AddImage(newValue);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
FUNCTION TImageWithID.StillMyMouse(mouseLPt : LPoint): BOOLEAN;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.Hit(mouseLPt) THEN
StillMyMouse := TRUE {I've handled it}
ELSE
StillMyMouse := FALSE; {give it to someone else}
{default; this will usually be overridden in subclass}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
METHODS OF TDialog;
{$S DlgAlloc}
FUNCTION TDialog.CREATE(object: TObject; heap: THeap; itsKey: S4; itsView: TView): TDialog;
VAR itsStringKey:
TStringKey;
itsExtent:
LRect;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
WITH stdButtonMetrics DO
BEGIN
height := stdBtnHeight;
curvH := stdCurvH;
curvV := stdCurvV;
typeStyle := sysTypeStyle;
penState := normalPen;
expandNum := 4;
expandDen := 3;
absMinWidth := 80;
END;
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TDialog(TImageWithID.CREATE(object, heap, zeroLRect, itsKey, itsView, TRUE));
XferLeft(Ptr(ORD(@itsKey)+1), @itsStringKey.trueKey, 4); {get it into LONGINT form}
itsStringKey.key := itsKey;
SELF.stringKey := itsStringKey;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TDialog.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('stringKey: RECORD trueKey: LONGINT; key: STRING[4] END');
Field('');
END;
{$ENDC}
{$S DlgAlloc}
FUNCTION TDialog.NewButton(itsPhrase: INTEGER; itsMetrics: TButtonMetrics; sameSizedButton: TButton;
itsCmdNumber: TCmdNumber): TButton;
VAR itsID:
S255;
itsLocation:
button:
LPoint;
TButton;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
GetTextAndLocation(itsPhrase, itsID, itsLocation);
button := SELF.AddButton(itsID, itsLocation, itsMetrics, sameSizedButton, itsCmdNumber);
button.idNumber := itsPhrase;
NewButton := button;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
FUNCTION TDialog.NewCluster(itsPhrase: INTEGER): TCluster;
VAR itsID:
S255;
itsLocation:
LPoint;
cluster:
TCluster;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
GetTextAndLocation(itsPhrase, itsID, itsLocation);
cluster := SELF.AddStdCluster(itsID, itsLocation.h, itsLocation.v);
cluster.idNumber := itsPhrase;
NewCluster := cluster;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
FUNCTION TDialog.NewFreeCheckbox(itsPhrase: INTEGER; boxWidth: INTEGER;
boxHeight: INTEGER; wantLabel: BOOLEAN; labelOffset: Point; itsTypeStyle: TTypeStyle): TCheckBox;
VAR itsID:
S255;
itsLocation:
LPoint;
checkbox:
TCheckbox;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
GetTextAndLocation(itsPhrase, itsID, itsLocation);
checkbox := SELF.AddFreeCheckbox(itsID, itsLocation.h, itsLocation.v, boxWidth, boxHeight,
wantLabel, labelOffset, itsTypeStyle);
checkbox.idNumber := itsPhrase;
NewFreeCheckbox := checkbox;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
FUNCTION TDialog.NewInputFrame(itsPhrase: INTEGER; promptTypeStyle: TTypeStyle;
inputOffset: Point; inputTypeStyle: TTypeStyle;
maxInputChars: INTEGER; itsBorders: Rect; drawInputLRect: BOOLEAN;
{$S DlgAlloc}
FUNCTION TDialog.AddButton(itsId: S255; itsLocation: LPoint; itsMetrics: TButtonMetrics;
sameSizedButton: TButton; itsCmdNumber: TCmdNumber): TButton;
VAR button: TButton;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
button := TButton.CREATE(NIL, SELF.Heap, itsId, SELF.view, itsLocation, itsMetrics,
sameSizedButton, itsCmdNumber);
SELF.AddImage(button);
AddButton := button;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
FUNCTION TDialog.AddStdButton(itsId: S255; itsXLoc, itsYLoc: LONGINT; sameSizedButton: TButton;
itsCmdNumber: TCmdNumber): TButton;
VAR location:
LPoint;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SetLPt(location, itsXLoc, itsYLoc);
AddStdButton := SELF.AddButton(itsID, location, stdButtonMetrics, sameSizedButton, itsCmdNumber);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
FUNCTION TDialog.AddStdFreeCheckbox(itsId: S255; itsXLoc, itsYLoc: LONGINT): TCheckBox;
VAR legend:
TLegend;
location:
LPoint;
checkbox:
TCheckbox;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SetLPt (location, itsXLoc, itsYLoc);
checkbox := TCheckbox.CREATE(NIL, SELF.Heap, itsId, SELF.view, location, stdBoxWidth,
stdBoxHeight, TRUE, stdLabelOffset, sysTypeStyle);
SELF.AddImage(checkbox);
AddStdFreeCheckbox := checkbox;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
FUNCTION TDialog.AddStdCluster(itsId: S255; itsXLoc, itsYLoc: LONGINT): TCluster;
VAR location:
LPoint;
cluster:
TCluster;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SetLPt(location, itsXLoc, itsYLoc);
cluster :=TCluster.CREATE(NIL, SELF.Heap, itsId, SELF.view, location);
SELF.AddImage(cluster);
AddStdCluster := cluster;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
FUNCTION TDialog.AddFreeCheckbox(itsID: S255; itsXLoc, itsYLoc: LONGINT; boxWidth: INTEGER;
boxHeight: INTEGER; wantLabel: BOOLEAN; labelOffset: Point; itsTypeStyle: TTypeStyle): TCheckbox;
VAR location:
LPoint;
checkbox:
TCheckbox;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SetLPt(location, itsXLoc, itsYLoc);
checkbox := TCheckbox.CREATE(NIL, SELF.Heap, itsID, SELF.view, location, boxWidth, boxHeight,
wantLabel, labelOffset, itsTypeStyle);
SELF.AddImage(checkbox);
AddFreeCheckbox := checkbox;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
FUNCTION TDialog.AddInputFrame(itsId: S255;
promptLocation: LPoint; promptTypeStyle: TTypeStyle;
inputLocation: LPoint; inputTypeStyle: TTypeStyle;
maxInputChars: INTEGER; itsBorders: Rect; drawInputLRect: BOOLEAN;
drawHitLRect: BOOLEAN): TInputFrame;
VAR inputFrame: TInputFrame;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
inputFrame := TInputFrame.CREATE(NIL, SELF.Heap, itsID, SELF.view, promptLocation, promptTypeStyle,
inputLocation, inputTypeStyle, maxInputChars, itsBorders,
drawInputLRect, drawHitLRect);
SELF.AddImage(inputFrame);
AddInputFrame := inputFrame;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
FUNCTION TDialog.AddRowOfBoxes(itsID: S255; itsXLoc, itsYLoc: LONGINT; numberOfBoxes: INTEGER;
startingIDNumber: INTEGER; boxWidth: INTEGER; boxHeight: INTEGER; boxSpacing: INTEGER): TCluster;
VAR currentIDNumber: INTEGER;
checkbox:
newLocation:
newID:
cluster:
TCheckbox;
LPoint;
S255;
TCluster;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
cluster := SELF.AddStdCluster(itsID, itsXLoc, itsYLoc);
FOR currentIDNumber := startingIDNumber TO (startingIDNumber + numberOfBoxes - 1) DO
BEGIN
IF cluster.lastBox = NIL THEN {this is the first to be inserted}
newLocation := cluster.location
ELSE { There is already at least one box in the cluster -- align to right of it}
WITH newLocation DO
BEGIN
h := cluster.lastBox.rectImage.extentLRect.right + boxSpacing; {??}
v := cluster.lastBox.rectImage.extentLRect.top;
END;
IntToString(currentIDNumber, @newID);
checkbox := cluster.AddCheckbox(newID, newLocation, boxWidth, boxHeight, FALSE, zeroPt,
sysTypeStyle, FALSE);
checkBox.IDNumber := currentIDNumber;
END;
AddRowOfBoxes := cluster;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
FUNCTION TDialog.AddStdInputFrame(itsId: S255; itsXLoc: LONGINT;
itsYLoc: LONGINT; maxInputChars : INTEGER): TInputFrame;
VAR promptLocation: LPoint;
inputLocation: LPoint;
inputFrame:
TInputFrame;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SetLPt(promptLocation, itsXLoc, itsYLoc);
SetQDTypeStyle(sysTypeStyle);
WITH inputLocation DO
BEGIN
h := itsXLoc + StringWidth(itsID) + 20;
v := itsYLoc;
END;
inputFrame := TInputFrame.CREATE(NIL, SELF.Heap, itsId, SELF.view, promptLocation, sysTypeStyle,
inputLocation, stdInputTypeStyle, maxInputChars,
stdFrameBorders, TRUE {draw input LRect}, TRUE {draw HitLRect});
SELF.AddImage(inputFrame);
AddStdInputFrame := inputFrame;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
FUNCTION TDialog.AddStdLegend(itsId: S255; itsXLoc, itsYLoc: LONGINT;
itsTypeStyle: TTypeStyle): TLegend;
VAR newString: TLegend;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
newString := NewStdLegend(SELF.Heap, itsID, itsXLoc, itsYLoc, SELF.view, itsTypeStyle);
SELF.AddImage(newString);
AddStdLegend := newString;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
FUNCTION TDialog.AddSysLegend(itsId: S255; itsXLoc, itsYLoc: LONGINT): TLegend;
VAR newString: TLegend;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
newString := NewSysLegend(SELF.Heap, itsID, itsXLoc, itsYLoc, SELF.view);
SELF.AddImage(newString);
AddSysLegend := newString;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TDialog.ButtonPushed(button: TButton); {usually'll be called through SUPERSELF}
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.parent <> NIL THEN
TDialog(SELF.parent).ButtonPushed(button)
ELSE
TDialogView(SELF.view).ButtonPushed(button);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TDialog.CheckboxHit(checkbox: TCheckbox; toggleDirection: BOOLEAN);
{default--passes up the line; client can reimplement}
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
{$S DlgHot}
PROCEDURE TDialog.PushButton(button: TButton);
PROCEDURE TurnOnTheJuice;
BEGIN
button.Highlight(hOffToOn);
END;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF NOT button.isHighlighted THEN
SELF.view.panel.OnAllPadsDo(TurnOnTheJuice);
TDialogView(SELF.view).hitButton := button;
SELF.ButtonPushed(button);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgWarm}
PROCEDURE TDialog.RecalcExtent;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SUPERSELF.RecalcExtent; {build up my size as the sum of the sizes of my children}
IF SELF.parent = NIL THEN
SELF.view.RecalcExtent;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
PROCEDURE TDialog.SetDefaultButton(button: TButton);
VAR thickPnSize:
point;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.parent <> NIL THEN
TDialog(SELF.parent).SetDefaultButton(button)
ELSE
TDialogView(SELF.view).SetDefaultButton(button);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TDialog.SelectInputFrame(inputFrame: TInputFrame);
VAR panel:
TPanel;
newFrameSel:
TFrameSelection;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
panel := SELF.view.panel;
panel.BeginSelection;
newFrameSel := TFrameSelection(panel.selection.FreedAndReplacedBy(
TFrameSelection.CREATE(NIL, SELF.Heap, inputFrame)));
newFrameSel.coSelection.Become(
inputFrame.textDialogImage.textImage.text.SelectAll(
inputFrame.textDialogImage.textImage));
panel.Highlight(panel.selection.coSelection, hOffToOn);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
{-------------------------------------------------------------------------------------------------------}
METHODS OF TButton;
{$S DlgAlloc}
FUNCTION TButton.CREATE(object: TObject; heap: THeap; itsId: S255; itsView: TView;
itsLocation: LPoint; itsMetrics: TButtonMetrics;
sameSizedButton: TButton; itsCmdNumber: TCmdNumber): TButton;
VAR buttonLRect:
LRect;
itsLegend:
TLegend;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SetLRect(buttonLRect, -1, 0, 1, 1);
OffsetLRect(buttonLRect, itsLocation.h, itsLocation.v);
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TButton(TImageWithID.CREATE(object, heap, buttonLRect, itsId, itsView, TRUE));
WITH SELF DO
BEGIN
cmdNumber := itsCmdNumber;
buttonMetrics := itsMetrics;
isHighlighted := FALSE;
{minWidth will be set by RecalcExtent}
END;
IF sameSizedButton <> NIL THEN {weave me into chain of same-sized buttons}
BEGIN
SELF.nextSameSizedButton := sameSizedButton.nextSameSizedButton;
sameSizedButton.nextSameSizedButton := SELF;
END
ELSE
SELF.nextSameSizedButton := SELF;
itsLegend := NewStdLegend(heap, itsID, itsLocation.h, itsLocation.v, SELF.view,
itsMetrics.typeStyle);
SELF.AddImage(itsLegend);
SELF.Resize(buttonLRect); {the AddImage will've made things out of balance}
SELF.legend := itsLegend;
itsLegend.wouldBeDraggable := FALSE; {as an entity unto itself during layout}
SELF.RecalcExtent;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TButton.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('cmdNumber: INTEGER');
Field('minWidth: INTEGER');
Field('isHighlighted: BOOLEAN');
Field('nextSameSizedButton: TButton');
Field('legend: TLegend');
Field(CONCAT('buttonMetrics: RECORD height: INTEGER; curvH: INTEGER; curvV: INTEGER;',
'typeStyle: LONGINT; expandNum: INTEGER; expandDen: INTEGER;',
'absMinWidth: INTEGER; penState: ARRAY[1..18] OF Byte END'));
Field('');
END;
{$ENDC}
{$S DlgHot}
PROCEDURE TButton.DrawJustMe;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SetPenState(SELF.buttonMetrics.penState);
FrameLRRect(SELF.extentLRect, SELF.buttonMetrics.curvH, SELF.buttonMetrics.curvV);
IF SELF.isHighlighted THEN
InvrtLRRect(SELF.extentLRect, SELF.buttonMetrics.curvH, SELF.buttonMetrics.curvV);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TButton.Highlight(highTransit: THighTransit);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
InvrtLRRect(SELF.extentLRect, SELF.buttonMetrics.curvH, SELF.buttonMetrics.curvV);
SELF.isHighLighted := (highTransit = hOffToOn);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgLayout}
FUNCTION TButton.LaunchLayoutBox(view: TView): TImage;
VAR layoutBox:
TLayoutBox;
layBoxExtent:
LRect;
s:
TListScanner;
childLayoutBox: TLayoutBox;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
LaunchLayoutBox := TButtonLayoutBox.CREATE(NIL, SELF.Heap, SELF, view);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TButton.MousePress(mouseLPt: LPoint);
PROCEDURE TurnOnButton;
BEGIN
SELF.HighLight(hOffToOn);
END;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.view.panel.OnAllPadsDo(TurnOnButton);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TButton.MouseRelease;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
TDialog(SELF.parent).PushButton(SELF);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
PROCEDURE TButton.RecalcExtent;
VAR dialogView:
TDialogView;
curWidth:
INTEGER;
timesThrough:
INTEGER;
nextButton:
TButton;
legend:
TLegend;
paraImage:
TParaImage;
width:
INTEGER;
styleIndex:
INTEGER;
oldLegendLoc:
LPoint;
lRectToInval:
LRect;
legLength:
INTEGER;
textDialogImage:
TTextDialogImage;
editLegendSelection:TEditLegendSelection;
paraExtent:
LRect;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
lRectToInval := SELF.extentLRect;
legend := TLegend(SELF.children.First);
oldLegendLoc := legend.location;
WITH legend.extentLRect DO
legLength := right - left;
WITH SELF, buttonMetrics DO
{$H-}
minWidth := MAX(absMinWidth, (legLength * expandNum) DIV expandDen);
{$H+}
curWidth := SELF.minWidth;
FOR timesThrough := 1 TO 2 DO
BEGIN
nextButton := SELF.nextSameSizedButton;
WHILE nextButton <> SELF DO {send this round my circle of same-sized buttons}
BEGIN
nextButton.Recompute(curWidth);
WITH nextButton.extentLRect DO
curWidth := right - left;
nextButton := nextButton.nextSameSizedButton;
END;
SELF.Recompute(curWidth);
END;
UnionLRect(lRectToInval, SELF.extentLRect, lRectToInval);
IF TDialogView(SELF.view).isShowing THEN
SELF.view.panel.InvalLRect(lRectToInval);
IF SELF.parent <> NIL THEN
SELF.parent.RecalcExtent;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
PROCEDURE TButton.Recompute(minWidth: INTEGER);
VAR buttonWidth:
INTEGER;
labelWidth:
INTEGER;
legend:
TLegend;
topLeft:
LPoint;
shape:
LRect;
offset:
LPoint;
width:
INTEGER;
curLegendWidth: INTEGER;
textExtent:
LRect;
topCenter:
LPoint;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
legend := SELF.legend;
topLeft := SELF.extentLRect.topLeft;
WITH topCenter, SELF.extentLRect DO
BEGIN
v := top;
h := (left + right) DIV 2;
END;
buttonWidth := SELF.minWidth;
IF buttonWidth < minWidth THEN
buttonWidth := minWidth;
SetParaExtent(legend.paragraph, SELF.view, zeroLPt, textExtent);
curLegendWidth := textExtent.right;
SetLPt(offset, (topCenter.h - (curLegendWidth DIV 2)) - legend.location.h,
(topCenter.v +
((SELF.buttonMetrics.height DIV 2) + 3)) - legend.location.v);
legend.OffsetBy(offset);
SetLRect(shape, 0, 0, buttonWidth, SELF.buttonMetrics.height);
OffSetLRect(shape, topCenter.h - (buttonWidth DIV 2), topCenter.v);
SELF.Resize(shape);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
FUNCTION TButton.StillMyMouse(mouseLPt: LPoint): BOOLEAN;
{Called when the mouse which went down in me has moved; possibly it is no longer in me}
PROCEDURE TurnOffButton;
BEGIN
SELF.Highlight(hOnToOff);
END;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.Hit(mouseLPt) THEN
StillMyMouse := TRUE {still in same button -- do nothing}
ELSE { no longer in the button ; need to unhilight and remove claim }
BEGIN
SELF.view.panel.OnAllPadsDo(TurnOffButton);
StillMyMouse := FALSE; {see if anyone else wants this guy}
END ;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
{-------------------------------------------------------------------------------------------------------}
METHODS OF TCheckbox;
{$S DlgAlloc}
FUNCTION TCheckbox.CREATE(object: TObject; heap: THeap; itsId: S255; itsView: TView;
itsLocation: LPoint; boxWidth: INTEGER; boxHeight: INTEGER; wantLabel: BOOLEAN;
labelOffset: Point; itsTypeStyle: TTypeStyle): TCheckbox;
VAR extentLRect:
LRect;
tempLRect:
LRect;
rectImage:
TRectImage;
stringLoc:
LPoint;
itsString:
TLegend;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SetLRect(extentLRect, 0, 0, boxWidth, boxHeight);
OffsetLRect(extentLRect, itsLocation.h, itsLocation.v);
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TCheckbox(TImageWithID.CREATE(object, heap, extentLRect, itsId, itsView, TRUE));
SELF.isSelected := FALSE;
rectImage := TRectImage.CREATE(NIL, heap, extentLRect, noID, itsView, normalPen, FALSE);
SELF.AddImage(rectImage);
SELF.rectImage := rectImage;
IF wantLabel THEN
BEGIN
itsString := NewStdLegend(SELF.Heap, itsID, extentLRect.right + labelOffset.h,
extentLRect.bottom + labelOffset.v, itsView, itsTypeStyle);
SELF.AddImage(itsString);
SELF.legend := itsString;
END
ELSE
SELF.legend := NIL;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TCheckbox.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('isSelected: BOOLEAN');
Field('rectImage: TRectImage');
Field('legend: TLegend');
Field('');
END;
{$ENDC}
{$S DlgHot}
PROCEDURE TCheckbox.ChangeLabel(newS255: S255);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.legend = NIL THEN
{$IFC fDbgOK}
ABCBreak('No legend to chg', 0) {later could perhaps launch a new label}
{$ENDC}
ELSE
SELF.legend.ChangeString(newS255);
SELF.RecalcExtent;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
FUNCTION TCheckbox.CursorAt(mouseLPt: LPoint): TCursorNumber;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.Hit(mouseLPt) THEN
CursorAt := checkCursor
ELSE
CursorAt := noCursor;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TCheckbox.Draw;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
PenNormal;
IF SELF.IsSelected THEN
FillLRect(SELF.rectImage.extentLRect, lPatBlack)
{fill with black if selected}
ELSE
FillLRect(SELF.rectImage.extentLRect, lPatWhite);
SELF.rectImage.Draw;
{draw the outline box in any case}
IF SELF.legend <> NIL THEN
SELF.legend.Draw;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgLayout}
FUNCTION TCheckbox.LaunchLayoutBox(view: TView): TImage;
VAR layoutBox:
TLayoutBox;
childLayoutBox: TLayoutBox;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.legend <> NIL THEN {has string; use normal layout box}
LaunchLayoutBox := SUPERSELF.LaunchLayoutBox(view)
ELSE
BEGIN {a checkbox without an associated string}
childLayoutBox := TLayoutBox(SELF.rectImage.LaunchLayoutBox(view));
layoutBox := TLayoutBox.CREATE(NIL, SELF.Heap, childLayoutBox.extentLRect, noID, NIL,
view, SELF, zeroRect, FALSE, FALSE, TRUE);
layoutBox.AddImage(childLayoutBox);
LaunchLayoutBox := layoutBox;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TCheckbox.MousePress(mouseLPt: LPoint);
{This proc is only called for mouspresses within "free check boxes", which is to say Checkboxes
which are componenents of a dialogView -- NOT for Checkboxes which are subdialogImages of another dialogImage}
VAR carryOutTheToggle: BOOLEAN;
dialogView:
TDialogView;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
carryOutTheToggle := TRUE;
dialogView := TDialogView(SELF.view);
IF dialogView.paintFreeBoxes THEN {need to worry about only toggling if in current sense}
BEGIN
IF dialogView.startedPainting THEN {have already started 'painting' free checkboxes}
BEGIN
IF dialogView.paintSense = SELF.isSelected THEN
carryOutTheToggle := FALSE {already in the sense being painted--do nothing}
END
ELSE {just starting painting; establish the painting sense}
BEGIN
dialogView.startedPainting := TRUE;
dialogView.paintSense := NOT SELF.isSelected;
END;
END;
IF carryOutTheToggle THEN
BEGIN
SELF.Toggle;
dialogView.panel.InvalLRect(SELF.rectImage.extentLRect);
SELF.ControlHit(SELF, SELF.isSelected); {pass it up to cluster and Dialog and even DialogView}
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TCheckbox.Toggle;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.isSelected := NOT SELF.isSelected;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
{-------------------------------------------------------------------------------------------------------}
METHODS OF TCluster;
{$S DlgAlloc}
FUNCTION TCluster.CREATE(object: TObject; heap: THeap; itsId: S255; itsView: TView;
itsLocation: LPoint): TCluster;
VAR extentLRect: LRect;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
WITH itsLocation DO
SetLRect(extentLRect, h, v, h + 1, v + 1); {include that pt in ultimate extent}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TCluster(TImageWithID.CREATE(object, heap, extentLRect, itsId, itsView, TRUE));
WITH SELF DO
BEGIN
location := itsLocation;
hitBox := NIL;
hiLitBox := NIL;
lastBox := NIL;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TCluster.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('location: LPoint');
Field('hitBox: TCheckBox');
Field('hiLitBox: TCheckBox');
Field('lastBox: TCheckBox');
Field('');
END;
{$ENDC}
{$S DlgAlloc}
FUNCTION TCluster.AddAlignedCheckbox(itsId: S255; selectThisOne: BOOLEAN): TCheckbox;
CONST
stdIncrement = 20;
VAR lastBox:
TCheckbox;
location:
LPoint;
itsBoxWidth:
INTEGER;
itsBoxHeight:
INTEGER;
checkBox:
TCheckbox;
wantLabel:
BOOLEAN;
labelOffset:
Point;
vhs:
VHSelect;
itsTypeStyle:
TTypeStyle;
styleChange:
TStyleChange;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
itsTypeStyle := sysTypeStyle;
wantLabel := (itsID <> noID);
labelOffset := stdLabelOffset;
itsBoxWidth := stdBoxWidth;
itsBoxHeight := stdBoxHeight;
lastBox := SELF.lastBox;
IF lastBox = NIL THEN {this is the first to be inserted}
location := SELF.location
ELSE
{there is already at least one box in the cluster -- align to right of it & use its params}
BEGIN
WITH location DO
BEGIN
h := lastBox.extentLRect.right + stdIncrement;
v := lastBox.rectImage.extentLRect.top;
END;
WITH lastBox.rectImage.extentLRect DO
BEGIN
itsBoxWidth := right - left;
itsBoxHeight := bottom - top;
END;
IF wantLabel THEN
BEGIN
IF lastBox.legend <> NIL THEN
{use same type style and label Offset as prev guy}
BEGIN
lastBox.legend.paragraph.typeStyles.GetAt(1, @styleChange);
WITH lastBox, legend DO
BEGIN
itsTypeStyle := styleChange.newStyle;
FOR vhs := v TO h DO
labelOffset.vh[vhs] := location.vh[vhs] rectImage.extentLRect.botRight.vh[vhs];
END;
END
ELSE
wantLabel := FALSE; {last box did not have a label, so I won't either}
END;
END;
checkBox := SELF.AddCheckbox(itsID, location, itsBoxWidth, itsBoxHeight,
wantLabel, labelOffset, itsTypeStyle, selectThisOne);
IF lastBox <> NIL THEN
checkbox.idNumber := lastBox.idNumber + 1;
AddAlignedCheckbox := checkbox;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
FUNCTION TCluster.NewAlignedCheckbox(itsPhrase: INTEGER; selectThisOne: BOOLEAN): TCheckbox;
VAR itsID:
S255;
itsLocation:
LPoint;
checkbox:
TCheckbox;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
GetTextAndLocation(itsPhrase, itsID, itsLocation);
checkbox := SELF.AddAlignedCheckbox(itsID, selectThisOne);
checkbox.idNumber := itsPhrase;
NewAlignedCheckbox := checkbox;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
FUNCTION TCluster.AddCheckbox(itsID: S255; itsLocation: LPoint; boxWidth: INTEGER;
boxHeight: INTEGER; wantLabel: BOOLEAN; labelOffset: Point;
itsTypeStyle: TTypeStyle; selectThisOne: BOOLEAN): TCheckbox;
VAR location:
LPoint;
checkbox:
TCheckbox;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
checkbox := TCheckbox.CREATE(NIL, SELF.Heap, itsID, SELF.view, itsLocation, boxWidth,
boxHeight, wantLabel, labelOffset, itsTypeStyle);
SELF.AddImage(checkbox);
SELF.lastBox := checkbox;
IF selectThisOne THEN
BEGIN
IF NOT checkbox.isSelected THEN
checkbox.Toggle;
SELF.hiLitBox := checkbox;
END;
AddCheckbox := checkbox;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
FUNCTION TCluster.NewCheckbox(itsPhrase: INTEGER; boxWidth: INTEGER;
boxHeight: INTEGER; wantLabel: BOOLEAN; labelOffset: Point; itsTypeStyle: TTypeStyle;
selectThisOne: BOOLEAN): TCheckbox;
VAR itsID:
S255;
itsLocation:
LPoint;
checkbox:
TCheckbox;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
labelOffset,
{$S DlgAlloc}
PROCEDURE TCluster.AddRowOfBoxes(numberOfBoxes: INTEGER; startingIDNumber: INTEGER;
boxWidth: INTEGER; boxHeight: INTEGER; boxSpacing: INTEGER);
VAR currentIDNumber: INTEGER;
checkbox:
TCheckbox;
newLocation:
LPoint;
newID:
S255;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
FOR currentIDNumber := startingIDNumber TO (startingIDNumber + numberOfBoxes - 1) DO
BEGIN
IF SELF.lastBox = NIL THEN {this is the first to be inserted}
newLocation := SELF.location
ELSE { There is already at least one box in the cluster -- align to right of it}
WITH newLocation DO
BEGIN
h := SELF.lastBox.rectImage.extentLRect.right + boxSpacing; {??}
v := SELF.lastBox.rectImage.extentLRect.top;
END;
IntToString(currentIDNumber, @newID);
checkbox := SELF.AddCheckbox(newID, newLocation, boxWidth, boxHeight, FALSE, zeroPt,
sysTypeStyle, FALSE);
checkBox.IDNumber := currentIDNumber;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
FUNCTION TCluster.Hit(mouseLPt: LPoint): BOOLEAN;
VAR checkbox:
TCheckbox;
s:
TListScanner;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
Hit := FALSE;
IF LRectHasLPt(SELF.extentLRect, mouseLPt) THEN
BEGIN
s := SELF.children.Scanner;
WHILE s.Scan(checkbox) DO
IF checkbox.Hit(mouseLPt) THEN
BEGIN
Hit := TRUE;
SELF.hitBox := checkbox;
s.Done;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TCluster.MousePress(mouseLPt: LPoint);
{We are assured that when this is called, it will have been immediately
preceded by a successful call to TCluster.Hit . Hence, the field
TCluster.hitBox will correctly point to which guy was hit.}
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.SelectBox(SELF.hitBox); {will deselect any other}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TCluster.SelectBox(checkbox: TCheckbox); {select this box, deselecting others}
PROCEDURE DrawUnHiLitBoxOnThePad;
BEGIN
SELF.hiLitBox.Draw; {redraw old box unhilit}
END;
PROCEDURE DrawHiLitBoxOnThePad;
BEGIN
checkbox.Draw;
{toggle the newly selected one on}
END;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF (SELF.hiLitBox <> checkbox) AND (checkbox <> NIL) THEN
BEGIN
IF SELF.hiLitBox <> NIL THEN
BEGIN
SELF.hiLitBox.Toggle;
SELF.view.panel.OnAllPadsDo(DrawUnHiLitBoxOnThePad);
SELF.ControlHit(SELF.hiLitBox, FALSE);
END;
SELF.hiLitBox := checkbox;
{set new box as the currently hilit one}
checkbox.Toggle;
SELF.view.panel.OnAllPadsDo(DrawHiLitBoxOnThePad);
SELF.ControlHit(checkbox, TRUE);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
FUNCTION TCluster.StillMyMouse(mouseLPt: LPoint): BOOLEAN;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.Hit(mouseLPt) THEN {mouse is in a box of the cluster}
BEGIN
SELF.SelectBox(SELF.hitBox);
{will toggle any alternate box off}
StillMyMouse := TRUE;
END
ELSE {mouse not in any of my box's hit areas at the moment}
StillMyMouse := FALSE;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
METHODS OF TInputFrame;
{$S DlgAlloc}
FUNCTION TInputFrame.CREATE(object: TObject; heap: THeap; itsId: S255; itsView: TView;
promptLocation: LPoint; promptTypeStyle: TTypeStyle;
inputLocation: LPoint; inputTypeStyle: TTypeStyle; maxInputChars: INTEGER;
itsBorders: Rect; drawInputLRect: BOOLEAN; drawHitLRect: BOOLEAN): TInputFrame;
VAR textExtent:
LRect;
myOwnExtentLRect:
LRect;
prompt:
TLegend;
textDialogImage:
TTextDialogImage;
{$IFC libraryVersion <= 20}
{* * * P E P S I * * *}
fInfo:
TFInfo;
{$ELSEC}
{* * S P R I N G * *}
fInfo:
FontInfo;
{$ENDC}
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
prompt := TLegend.CREATE(NIL, heap, itsID, itsView, promptLocation, promptTypeStyle);
SetQDTypeStyle(inputTypeStyle);
GetFontInfo(fInfo);
WITH fInfo DO
descent + leading);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.Hit(mouseLPt) THEN
CursorAt := textCursor
ELSE
CursorAt := noCursor;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgText}
PROCEDURE TInputFrame.Draw;
VAR tempLRect: LRect;
pat:
pattern;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.prompt <> NIL THEN
SELF.prompt.Draw;
SELF.textDialogImage.Draw;
{draw the current input characters lying there...}
IF SELF.drawInputLRect THEN
BEGIN
tempLRect := SELF.textDialogImage.textImage.extentLRect;
InsetLRect(tempLRect, -6, -4);
PenNormal;
thePad.LPatToPat(lPatGray, pat);
PenPat(pat);
PenSize(1,1);
FrameLRect(tempLRect); {mostly for debugging reassurance...}
END;
IF SELF.drawHitLRect THEN
FrameLRect(SELF.extentLRect);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgLayout}
FUNCTION TInputFrame.LaunchLayoutBox(view: TView): TImage;
{In the future, if there were one, we would want to allow resizing of the hit area during
layout, and would here launch a special type of layout box, TInptFrmLayoutBox, to do layout just right}
VAR layoutBox:
TLayoutBox;
layBoxExtent:
LRect;
s:
TListScanner;
childLayoutBox: TLayoutBox;
newBorders:
Rect;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
layoutBox := TLayoutBox(SUPERSELF.LaunchLayoutBox(view)); {i.e., TImageWithID's launch}
WITH layoutBox.borders DO
BEGIN
top := SELF.borders.top;
right := SELF.borders.right - right;
bottom := SELF.borders.bottom - bottom;
left := SELF.borders.left - left;
END;
layoutBox.RecalcExtent;
LaunchLayoutBox := layoutBox;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgText}
PROCEDURE TInputFrame.MousePress(mouseLPt: LPoint);
VAR frameSelection: TFrameSelection;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
LRectHaveLPt(SELF.textDialogImage.textImage.extentLRect, mouseLPt);
TDialogView(SELF.view).magnetCursor := textCursor;
frameSelection := TFrameSelection(SELF.view.panel.selection.FreedAndReplacedBy(
TFrameSelection.CREATE(NIL, SELF.Heap, SELF)));
SELF.textDialogImage.textImage.MousePress(mouseLPt);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgText}
PROCEDURE TInputFrame.GetContents(VAR theStr: S255);
VAR paraImage: TParaImage;
paragraph: TParagraph;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
paraImage := TParaImage(SELF.textDialogImage.textImage.imageList.First);
paragraph := paraImage.paragraph;
paragraph.ToPStr(@theStr);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgLayout}
PROCEDURE TInputFrame.RecalcExtent;
VAR newExtent: LRect;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.prompt <> NIL THEN
UnionLRect(SELF.prompt.extentLRect, SELF.textDialogImage.extentLRect, newExtent)
ELSE
newExtent := SELF.textDialogImage.extentLRect;
LRectAddBorders(newExtent, SELF.borders, newExtent);
SELF.Resize(newExtent);
IF SELF.parent <> NIL THEN
SELF.parent.RecalcExtent;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgText}
FUNCTION TInputFrame.StillMyMouse(mouseLPt: LPoint): BOOLEAN;
{in this implementation, once the insertion point has been dropped, we don't give up
control even if user now strays outside our hit area}
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
LRectHaveLPt(SELF.textDialogImage.textImage.extentLRect, mouseLPt);
SELF.view.panel.selection.coSelection.MouseMove(mouseLPt); {currently, just pass it on to the
text selection}
StillMyMouse := TRUE;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgText}
PROCEDURE TInputFrame.SupplantContents(newStr: S255);
VAR paragraph: TParagraph;
paraImage: TParaImage;
textImage: TTextImage;
oldCount:
INTEGER;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
textImage := SELF.textDialogImage.textImage;
paraImage := TParaImage(textImage.imageList.First);
paragraph := paraImage.paragraph;
oldCount := paragraph.size;
paragraph.ReplPString(0, oldCount, @newStr);
paraImage.changed := TRUE;
paraImage.InvalLinesWith(0, MAXINT);
textImage.RecomputeImages(actionNone, TRUE);
IF TDialogView(SELF.view).isShowing THEN
SELF.view.panel.InvalLRect(SELF.textDialogImage.extentLRect);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
METHODS OF TLegend;
{$S TK2Start}
FUNCTION TLegend.CREATE(object: TObject; heap: THeap; itsChars: S255; itsView: TView;
itsLocation: LPoint; itsTypeStyle: TTypeStyle): TLegend;
VAR itsExtent:
LRect;
height:
INTEGER;
itsParagraph:
TParagraph;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
itsParagraph := TParagraph.CREATE(NIL, heap, LENGTH(itsChars), itsTypeStyle);
itsParagraph.InsPStrAt(1, @itsChars);
SetParaExtent(itsParagraph, itsView, itsLocation, itsExtent);
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TLegend(TDialogImage.CREATE(object, heap, itsExtent, noID, itsView, FALSE));
WITH SELF DO
BEGIN
location := itsLocation;
paragraph := itsParagraph;
wouldBeDraggable := TRUE;
usesSysFont := (itsTypeStyle.font.fontFamily = famSystem);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgCold}
PROCEDURE TLegend.Free;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
Free(SELF.paragraph);
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TLegend.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('location: LPoint');
Field('paragraph: TParagraph');
Field('wouldBeDraggable: BOOLEAN');
Field('usesSysFont: BOOLEAN');
Field('');
END;
{$ENDC}
{$S DlgHot}
PROCEDURE TLegend.ChangeToPhrase(newPhrase: INTEGER);
VAR newString: S255;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
process.GetAlert(newPhrase, newString);
SELF.ChangeString(newString);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TLegend.ChangeString(newString: S255);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.view.panel.InvalLRect(SELF.extentLRect); {invalidate old string's bounding box}
SELF.paragraph.DelAll;
SELF.paragraph.InsPStrAt(1, @newString);
SELF.GetBoxRight;
SELF.view.panel.InvalLRect(SELF.extentLRect); {invalidate new string's bounding box}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TLegend.Draw;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
MoveToL(SELF.location.h, SELF.location.v);
SELF.paragraph.Draw(1, SELF.paragraph.size);
{$IFC fTrace}EP;{$ENDC}
END;
{$S TK2Start}
PROCEDURE TLegend.GetBoxRight;
VAR newExtent:
LRect;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SetParaExtent(SELF.paragraph, SELF.view, SELF.location, newExtent);
SELF.Resize(newExtent);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TLegend.GetString(VAR itsString: S255);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.paragraph.ToPStr(@itsString);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgLayout}
FUNCTION TLegend.LaunchLayoutBox(view: TView): TImage;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.isEditable THEN
LaunchLayoutBox := TLegendLayoutBox.CREATE(NIL, SELF.Heap, view, SELF)
ELSE
LaunchLayoutBox := SUPERSELF.LaunchLayoutBox(view);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TLegend.OffsetBy(deltaLPt: LPoint);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
{$H-} LPtPlusLPt(SELF.location, deltaLPt, SELF.location); {$H+}
SUPERSELF.OffsetBy(deltaLPt);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TLegend.RecalcExtent;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.GetBoxRight;
IF SELF.parent <> NIL THEN
SELF.parent.RecalcExtent;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
{UDialog3}
(*
TPicObject -- TRectImage -- TTextDialogImage - TFrameSelection TPlannerView - TLayoutBox - TLegendLayoutBox - ButtonLayoutBox - TTitleTab TLayPickSelection - TLayMoveCommand - TEditLegendSelection - TDialogDesignWindow
*)
{04/25/84 1610
{04/25/84 0015
{04/23/84 1210
{04/17/84 2130
{04/17/84
{04/15/84
{01/29/84
{12/22/83
2000
2000
1754
1927
Switched back to using a paraImage in call to FilterAndDo, as per JKD's latest change,
in TLegendLayoutBox.RecalcExtent
Removed the inval in TLegendLayoutBox.MousePress, fExperimenting or not}
Added TEditLegendSelection.MousePress, MouseMove and MouseRelease and field tripleClick,
to trap triple-click and do a SelectAll with it}
Removed all references to 'underEdit' field of TDialogImage
TEditLegendSelection.Deselect, Free, and Restore changed.
Removed some commented-out code and some unused VAR declarations in the TEditLegendSel
methods changed}
In TEditLegendSelection.CREATE doesn't inval unless fExperimenting
Removed ABCBreak calls in TEditLegendSelection.CREATE, TFrameSelection.KeyChar
TLegendLayoutBox.Draw always keys on existence of SELF.textDialogImage, ignoring
underEdit flag; underEdit, if this is okay, can vanish completely from the architecture}
In TLegendLayoutBox.RecalcExtent, try to use TImage.FilterAndDo correctly}
Spring Prelim Release}
RELEASE TK8D}
RELEASE TK8A}
METHODS OF TPicObject;
{$S DlgCold}
FUNCTION TPicObject.CREATE(object: TObject; heap: THeap; itsId: S255;
itsView: TView; itsLocation: LPoint; itsPicHandle: PicHandle):
VAR tempHz:
THeap;
frameInView:
LRect;
myPicHandle:
PicHandle;
boxAtCreation: Rect;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
boxAtCreation:= itsPicHandle^^.picFrame;
noPad.rectToLRect(boxAtCreation, frameInView);
OffsetLRect(frameInView, itsLocation.h, itsLocation.v);
TPicObject;
{$S DlgCold}
PROCEDURE TPicObject.Free;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
KillPicture(SELF.picture);
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TPicObject.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('picHandle: LONGINT');
Field('boxAtCreation: Rect');
Field('');
END;
{$ENDC}
{$S DlgCold}
PROCEDURE TPicObject.Draw;
VAR boxOnPad:
Rect;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
thePad.LRectToRect(SELF.extentLRect, boxOnPad);
DrawPicture(SELF.picture, boxOnPad);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
METHODS OF TRectImage;
{$S DlgAlloc}
FUNCTION TRectImage.CREATE(object: TObject; heap: THeap; itsExtent: LRect; itsId: S255;
itsView: TView; itsPenState: PenState; withChildren: BOOLEAN): TRectImage;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TRectImage(TDialogImage.CREATE(object, heap, itsExtent, itsId, itsView, withChildren));
SELF.penState := itsPenState;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TRectImage.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field(CONCAT('penState: RECORD pnLoc: Point; pnSize: Point; pnMode: INTEGER;',
'pnPat: ARRAY[0..7] OF Byte END'));
{actually a packed array--fix}
Field('');
END;
{$ENDC}
{$S DlgHot}
PROCEDURE TRectImage.Draw;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SetPenState(SELF.penState); {could first want to scale the pen size, via the Pad...}
FrameLRect(SELF.extentLRect);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgLayout}
FUNCTION TRectImage.LaunchLayoutBox(view: TView): TImage;
VAR newBox: TLayoutBox;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
newBox := TLayoutBox.CREATE(NIL, SELF.Heap, SELF.extentLRect, noID, NIL,
view, SELF, stdThinBorders, TRUE, TRUE, FALSE);
LaunchLayoutBox := newBox;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
{-------------------------------------------------------------------------------------------------------}
METHODS OF TTextDialogImage;
{$S DlgText}
FUNCTION TTextDialogImage.CREATE(object: TObject; heap: THeap; itsExtent: LRect; itsId: S255;
itsView: TView; itsTypeStyle: TTypeStyle; itsInitialChars: S255): TTextDialogImage;
VAR textimage: TTextImage;
editPara:
TEditPara;
paraFormat: TParaFormat;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TTextDialogImage(TImageWithID.CREATE(object, heap, itsExtent, itsId, itsView, FALSE));
textImage := TTextImage.CREATE(NIL, heap, itsView, itsExtent,
TText.CREATE(NIL, heap, TDialogView(itsView).styleSheet), TRUE);
textImage.text.txtImgList.InsLast(textImage);
paraFormat := TParaFormat.CREATE(NIL, heap, NIL);
paraFormat.dfltTStyle := itsTypeStyle;
editPara := TEditPara.CREATE(NIL, heap, 0, paraFormat);
textImage.imageList.InsLast(textImage.NewParaImage(editPara, itsExtent, 0, 0));
textImage.text.paragraphs.InsLast(editPara);
editPara.ReplPString(0, editPara.size, @itsInitialChars);
SELF.textImage := textImage;
textImage.RecomputeImages(actionNone, TRUE);
SELF.wouldBeDraggable := TRUE;
SELF.refCount := 1;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtRes}
PROCEDURE TTextDialogImage.Free;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.textImage.text.Free;
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TTextDialogImage.ChangeRefCountBy(delta: INTEGER);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.refCount := SELF.refCount + delta;
IF SELF.refCount <= 0 THEN
SELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TTextDialogImage.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('textImage: TTextImage');
Field('wouldBeDraggable: BOOLEAN');
Field('refCount: INTEGER');
Field('');
END;
{$ENDC}
{$S DlgHot}
FUNCTION TTextDialogImage.CursorAt(mouseLPt: LPoint): TCursorNumber;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.Hit(mouseLPt) THEN
CursorAt := textCursor
ELSE {not mine}
CursorAt := noCursor;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtRes}
PROCEDURE TTextDialogImage.Draw;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.textImage.Draw;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgLayout}
FUNCTION TTextDialogImage.LaunchLayoutBox(view: TView): TImage;
VAR borders:
Rect;
newBox:
TLayoutBox;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
{dubious--formerly intended uses in abeyance}
IF SELF.wouldBeDraggable THEN
borders := stdPlainBorders
ELSE
borders := zeroRect;
newBox := TLayoutBox.CREATE(NIL, SELF.Heap, SELF.extentLRect, noID, NIL {parent},
view, SELF, borders, FALSE, FALSE, FALSE);
newBox.wouldMakeSelection := TRUE;
newBox.suppressDrawingManipulee := FALSE;
newBox.isDraggable := SELF.wouldBeDraggable;
LaunchLayoutBox := newBox;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtRes}
PROCEDURE TTextDialogImage.MousePress(mouseLPt: LPoint);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.textImage.MousePress(mouseLPt);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtRes}
PROCEDURE TTextDialogImage.OffsetBy(deltaLPt: LPoint);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.textImage.OffsetBy(deltaLPt);
SUPERSELF.OffsetBy(deltaLPt);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
METHODS OF TFrameSelection;
{$S DlgHot}
FUNCTION TFrameSelection.CREATE(object: TObject; heap: THeap;
itsInputFrame: TInputFrame): TFrameSelection;
VAR coSelection:
TSelection;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TFrameSelection(TSelection.CREATE(object, heap, itsInputFrame.view,
frameKind, zeroLPt));
SELF.inputFrame := itsInputFrame;
SELF.boundLRect := itsInputFrame.textDialogImage.extentLRect;
coSelection := itsInputFrame.view.NoSelection; {put non-NIL coSelection}
SELF.coSelection := coSelection;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
FUNCTION TFrameSelection.CanDoCommand(cmdNumber: TCmdNumber; VAR checkIt: BOOLEAN): BOOLEAN;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
CASE cmdNumber OF
uModern, uClassic,u20Pitch, u15Pitch, u12Pitch, u10Pitch, u12Point, u14Point, u18Point, u24Point,
uPlain, uBold, uItalic, uUnderline, uShadow, uOutline:
CanDoCommand := FALSE;
{before coSelection could set to TRUE}
OTHERWISE
CanDoCommand := SUPERSELF.CanDoCommand(cmdNumber, checkIt);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TFrameSelection.KeyChar(ch: CHAR);
VAR paraImage:
TParaImage;
maxCharsString: S255;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
paraImage := TParaImage(SELF.inputFrame.textDialogImage.textImage.imageList.First);
IF (SELF.inputFrame.maxInputChars > paraImage.paragraph.size) OR
(NOT InClass(SELF.coSelection, TInsertionPoint)) THEN {can accept more}
SELF.coSelection.KeyChar(ch)
ELSE
BEGIN
IntToStr(SELF.inputFrame.maxInputChars, @maxCharsString);
process.ArgAlert(1, maxCharsString);
process.Stop(phTooManyChars);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TFrameSelection.KeyEnter(dh, dv: INTEGER);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF (dh <> 0) OR (dv <> 0) THEN
SELF.KeyTab((dh < 0) OR (dv < 0)); {right and down keys are Forward}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TFrameSelection.KeyReturn;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.KeyTab(FALSE);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TFrameSelection.KeyTab(fBackward: BOOLEAN);
VAR dialogView:
TDialogView;
dialogImage:
TDialogImage;
s:
TListScanner;
passedGo:
BOOLEAN;
foundSuccessor: BOOLEAN;
prevInputFrame: TInputFrame;
nextInputFrame: TInputFrame;
newFrameSel:
TFrameSelection;
dialog:
TDialog;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
dialogView := TDialogView(SELF.view);
prevInputFrame := NIL;
passedGo := FALSE;
foundSuccessor := FALSE;
dialog := TDialog(SELF.inputFrame.parent);
s := dialog.children.Scanner;
WHILE s.Scan(dialogImage) DO
BEGIN
IF dialogImage = SELF.inputFrame THEN {found current frame}
BEGIN
IF not fBackward THEN
passedGo := TRUE
ELSE {back-tab; use most recent input frame, if any}
BEGIN
IF prevInputFrame = NIL THEN {there is none; can't do anything}
s.Done {with foundSuccessor still FALSE}
ELSE {found somebody!}
BEGIN
nextInputFrame := prevInputFrame;
foundSuccessor := TRUE;
END;
END;
END;
IF InClass(dialogImage, TInputFrame) THEN
IF (passedGo AND (dialogImage <> SELF.inputFrame)) OR foundSuccessor THEN
BEGIN
IF passedGo THEN
nextInputFrame := TInputFrame(dialogImage); {else it's already set, if back-tab}
SELF.KeyPause;
dialog.SelectInputFrame(nextInputFrame);
foundSuccessor := TRUE;
s.Done;
END
{forward tabbing actually done}
ELSE
prevInputFrame := TInputFrame(dialogImage);
END; {scan of dialogImages}
IF NOT foundSuccessor THEN
SELF.CantDoIt;
{ELSE
SELF.window.CommitLast};
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TFrameSelection.MousePress(mouseLPt: LPoint);
{called only if mouse comes BACK down inside alredy-selected Input Frame}
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SUPERSELF.MousePress(mouseLPt);
TDialogView(SELF.view).magnetCursor := textCursor;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TFrameSelection.PerformCommand(command: TCommand; cmdPhase: TCmdPhase);
VAR paragraph:
TParagraph;
textImage:
TTextImage;
paraImage:
TParaImage;
noSelection:
TSelection;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
textImage := SELF.inputFrame.textDialogImage.textImage;
SUPERSELF.PerformCommand(command, cmdPhase);
paraImage := TParaImage(textImage.imageList.First);
paragraph := paraImage.paragraph;
paragraph.NewStyle(0, paragraph.Size, SELF.inputFrame.inputTypeStyle);
IF paragraph.size > SELF.inputFrame.maxInputChars THEN
BEGIN {may need temp para here}
paragraph.ReplPara(0, paragraph.size, paragraph, 0, SELF.inputFrame.maxInputChars);
paraImage.changed := TRUE;
paraImage.InvalLinesWith(0, MAXINT);
textImage.RecomputeImages(actionNone, TRUE);
SELF.window.CommitLast;
noSelection := SELF.FreedAndReplacedBy(SELF.view.NoSelection);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgHot}
PROCEDURE TFrameSelection.Restore;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
TDialogView(SELF.view).currentDialogImage := SELF.inputFrame;
SUPERSELF.Restore;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
METHODS OF TPlannerView;
{$S SgLayout}
FUNCTION TPlannerView.CREATE(object: TObject; heap: THeap; itsViewBeingPlanned: TView;
itsPanel: TPanel; itsAllowSketching: BOOLEAN;
itsRetainPickedBox: BOOLEAN): TPlannerView;
VAR newList:
TList;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TPlannerView(TDialogView.CREATE(object, heap, itsViewBeingPlanned.extentLRect, itsPanel,
NIL, itsViewBeingPlanned.res));
WITH SELF DO
BEGIN
viewBeingPlanned := itsViewBeingPlanned;
allowSketching := itsAllowSketching;
retainPickedBox := itsRetainPickedBox;
currentLayoutBox := NIL;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TPlannerView.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('viewBeingPlanned: TView');
Field('allowSketching: BOOLEAN');
Field('retainPickedBox: BOOLEAN');
Field('currentLayoutBox: TLayoutBox');
Field('');
END;
{$ENDC}
{$S SgLayout}
FUNCTION TPlannerView.CursorAt(mouseLPt: LPoint): TCursorNumber;
VAR s:
TListScanner;
layoutBox: TLayoutBox;
curCursor: TCursorNumber;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.mouseIsDown AND (SELF.magnetCursor <> noCursor) THEN
CursorAt := SELF.magnetCursor
ELSE
BEGIN
curCursor := noCursor;
s := SELF.rootDialog.children.Scanner;
WHILE s.Scan(layoutBox) DO
BEGIN
curCursor := layoutBox.CursorAt(mouseLPt);
IF curCursor <> noCursor THEN
s.Done
END;
CursorAt := curCursor;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgLayout}
PROCEDURE TPlannerView.Draw;
PROCEDURE DrawLayoutBox(obj: TObject);
VAR layoutBox:
TLayoutBox;
BEGIN
layoutBox := TLayoutBox(obj);
layoutBox.Draw;
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.EachActualPart(DrawLayoutBox);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgLayout}
PROCEDURE TPlannerView.EachActualPart(PROCEDURE DoToObject(filteredObj: TObject));
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.rootDialog.children.Each(DoToObject);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
PROCEDURE TPlannerView.Init(itsListOfImages: TList);
VAR s:
TListScanner;
t:
TListScanner;
image:
TImage;
layoutBox:
TLayoutBox;
otherLayoutBox:
TLayoutBox;
nextButton:
TButton;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF itsListOfImages <> NIL THEN
BEGIN
s := itsListOfImages.Scanner;
{create parallel structure}
WHILE s.Scan(image) DO
BEGIN
layoutBox := SELF.NewLayoutBox(image);
IF layoutBox <> NIL THEN
SELF.rootDialog.AddImage(layoutBox); {it may well have its own children, already created}
END;
END;
IF InClass(SELF.viewBeingPlanned, TDialogView) THEN {get buttonLayoutBoxes correctly entwined}
BEGIN
s := SELF.rootDialog.children.Scanner;
WHILE s.Scan(layoutBox) DO
IF InClass(layoutBox, TButtonLayoutBox) THEN
BEGIN
nextButton := TButton(layoutBox.manipulee).nextSameSizedButton;
t := SELF.rootDialog.children.Scanner;
WHILE t.Scan(otherLayoutBox) DO
IF otherLayoutBox.manipulee = nextButton THEN {found it}
BEGIN
TButtonLayoutBox(layoutBox).nextSameSizedBox := TButtonLayoutBox(otherLayoutBox);
t.Done;
END;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
FUNCTION TPlannerView.NewLayoutBox(image: TImage): TLayoutBox;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
NewLayoutBox := TLayoutBox(image.LaunchLayoutBox(SELF));
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgLayout}
PROCEDURE TPlannerView.MousePress(mouseLPt: LPoint);
VAR panel:
TPanel;
layPickSelection:
TLayPickSelection;
pickedBox:
TLayoutBox;
s:
TListScanner;
layoutBox:
TLayoutBox;
madeSelection:
BOOLEAN;
editLegendSelection:
TEditLegendSelection;
PROCEDURE InvrtOnThePad;
BEGIN
pickedBox.Highlight(hOffToOn);
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.mouseIsDown := TRUE;
SELF.magnetCursor := noCursor;
panel := SELF.panel;
madeSelection := FALSE;
IF (panel.selection.kind <> nothingKind) AND (panel.selection.kind <> layPickKind) THEN
BEGIN
IF clickState.fShift THEN
madeSelection := TRUE
ELSE
IF InClass(panel.selection, TEditLegendSelection) THEN
BEGIN
editLegendSelection := TEditLegendSelection(panel.selection);
IF LPtInLRect(mouseLPt, editLegendSelection.legendLayoutBox.extentLRect) THEN
IF NOT LPtInLRect(mouseLPt, editLegendSelection.legendLayoutBox.titleTab.extentLRect) THEN
BEGIN
madeSelection := TRUE;
SELF.magnetCursor := textCursor;
END;
END;
END;
IF madeSelection THEN
panel.selection.MousePress(mouseLPt)
ELSE
BEGIN
panel.BeginSelection;
pickedBox := NIL; {find who wants the mouse}
s := SELF.rootDialog.children.Scanner;
WHILE s.Scan(layoutBox) DO
BEGIN
layoutBox.ConsiderMouse(mouseLPt, madeSelection, pickedBox);
IF pickedBox <> NIL THEN
pickedBox.ComeForward;
IF madeSelection THEN
s.Done
ELSE
IF (pickedBox <> NIL) THEN {got the title tab of somebody}
BEGIN
pickedBox.ChangeDragState(TRUE);
(*
layPickSelection := TLayPickSelection(panel.selection.FreedAndReplacedBy(
TLayPickSelection.CREATE(NIL, SELF.Heap, SELF, layPickKind, pickedBox,
mouseLPt)));
panel.OnAllPadsDo(InvrtOnThePad);
SELF.magnetCursor := arrowCursor;
s.Done;
END
END;
NB: Here, when/if we allow sketching in layout, we would add code like:
IF pickedBox = NIL THEN
IF SELF.allowSketching THEN
LaySketchSelection := TLaySketchSelection(panel.selection.FreedAndReplacedBy(
TLaySketchSelection.CREATE(NIL, SELF.Heap, SELF, mouseLPt)))
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgLayout}
PROCEDURE TPlannerView.MouseMove(mouseLPt: LPoint);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
TView.MouseMove(mouseLPt); {do NOT do what TDialogView would do}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgLayout}
PROCEDURE TPlannerView.MouseRelease;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.mouseIsDown := FALSE;
SELF.magnetCursor := noCursor;
TView.MouseRelease;
{do NOT do what TDialogView would do except for the above}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
METHODS OF TLayoutBox;
{$S SgLayout}
FUNCTION TLayoutBox.CREATE(object: TObject; heap: THeap; baseExtent: LRect; itsID: S255;
*)
- itsBorders.bottom - itsBorders.top + 1,
WITH SELF DO
BEGIN
parent := itsParent;
titleTab := itsTitleTab;
manipulee := itsManipulee;
suppressDrawingManipulee := itsSuppression;
wouldMakeSelection := FALSE;
isResizable := itsResizable;
isDraggable := TRUE;
shouldFrame := TRUE;
borders := itsBorders;
hasDraggee := FALSE;
END;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TLayoutBox.Free;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
Free(SELF.titleTab);
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TLayoutBox.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('manipulee: TImage');
Field('titleTab: TTitleTab');
Field('suppressDrawingManipulee: BOOLEAN');
Field('isResizable: BOOLEAN');
Field('borders: Rect');
Field('wouldMakeSelection: BOOLEAN');
Field('isDraggable: BOOLEAN');
Field('shouldFrame: BOOLEAN');
Field('hasDraggee: BOOLEAN');
Field('');
END;
{$S SgLayout}
{$ENDC}
PROCEDURE TLayoutBox.ChangeDragState(enteringDrag: BOOLEAN);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.hasDraggee := enteringDrag;
IF SELF.parent <> NIL THEN
IF InClass(SELF.parent, TLayoutBox) THEN
TLayoutBox(SELF.parent).ChangeDragState(enteringDrag);
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TLayoutBox.ConsiderMouse(mouseLPt: LPoint; VAR madeSelection: BOOLEAN;
VAR pickedLayoutBox: TLayoutBox);
VAR s:
TListScanner;
layoutBox: TLayoutBox;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
pickedLayoutBox := NIL;
madeSelection := FALSE;
IF NOT SELF.Hit(mouseLPt) THEN
{it ain't me}
ELSE
BEGIN
IF LRectHasLPt(SELF.titleTab.extentLRect, mouseLPt) THEN
BEGIN
pickedLayoutBox := SELF;
SELF.TabGrabbed;
{so that page status dialog can react now}
END
ELSE
IF SELF.wouldMakeSelection THEN
BEGIN
madeSelection := TRUE;
pickedLayoutBox := SELF;
SELF.MousePress(mouseLPt);
END
ELSE
{not my title tab, and I myself don't make selections; how about it, kids?}
BEGIN
IF SELF.children <> NIL THEN
BEGIN
s := SELF.children.Scanner;
WHILE s.Scan(layoutBox) DO
BEGIN
layoutBox.ConsiderMouse(mouseLPt, madeSelection, pickedLayoutBox);
IF madeSelection OR (pickedLayoutBox <> NIL) THEN
s.Done;
END;
END;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
FUNCTION TLayoutBox.CursorAt(mouseLPt: LPoint): TCursorNumber;
VAR s:
TListScanner;
layoutBox: TLayoutBox;
curCursor: TCursorNumber;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
curCursor := noCursor;
IF SELF.Hit(mouseLPt) THEN
BEGIN
IF SELF.titleTab <> NIL THEN
IF SELF.titleTab.Hit(mouseLPt) THEN
curCursor := arrowCursor;
IF curCursor = noCursor THEN
IF SELF.children <> NIL THEN
BEGIN
s := SELF.children.Scanner;
WHILE s.Scan(layoutBox) DO
BEGIN
curCursor := layoutBox.CursorAt(mouseLPt);
IF curCursor <> noCursor THEN
s.Done;
END;
END;
END;
CursorAt := curCursor;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TLayoutBox.Draw;
PROCEDURE YouDraw(obj: TObject);
VAR dialogImage: TDialogImage;
BEGIN
dialogImage := TDialogImage(obj);
IF dialogImage.isActive THEN
dialogImage.Draw;
END;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF LRectIsVisible(SELF.extentLRect) OR SELF.hasDraggee THEN
BEGIN
SELF.EachActualPart(YouDraw);
SELF.DrawJustMe;
END;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TLayoutBox.DrawJustMe;
VAR titleTab:
TTitleTab;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF LRectIsVisible(SELF.extentLRect) THEN
BEGIN
titleTab := SELF.titleTab;
IF titleTab <> NIL THEN {currently every layout box MUST have a title tab, so this is
unnecessary}
IF NOT EmptyLRect(titleTab.extentLRect) THEN
titleTab.Draw;
IF NOT SELF.suppressDrawingManipulee THEN
IF SELF.manipulee <> NIL THEN
SELF.manipulee.Draw;
PenNormal;
IF SELF.IsDraggable AND SELF.shouldFrame THEN
FrameLRect(SELF.extentLRect); {draw overall box}
END;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TLayoutBox.FreeManipulee;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
Free(SELF.manipulee);
SELF.manipulee := NIL;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TLayoutBox.Highlight(highTransit: THighTransit);
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF (SELF.titleTab <> NIL) THEN
BEGIN
InvrtLRect(SELF.titleTab.extentLRect);
PenNormal;
FrameLRect(SELF.titleTab.extentLRect);
END;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TLayoutBox.MousePress(mouseLPT: LPoint);
VAR layoutBox: TLayoutBox;
s:
TListScanner;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.children <> NIL THEN
BEGIN
s := SELF.children.Scanner;
WHILE s.Scan(layoutBox) DO
IF layoutBox.DownAt(mouseLPt) <> NIL THEN
s.Done;
END;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TLayoutBox.Move(deltaLPt: LPoint);
VAR oldLRect:
LRect;
newLRect:
LRect;
heading:
THeading;
PROCEDURE InvalOnThePad;
BEGIN
thePad.InvalLRect(oldLRect);
thePad.InvalLRect(newLRect);
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
oldLRect := SELF.extentLRect;
SELF.OffsetBy(deltaLPt);
newLRect := SELF.extentLRect;
SELF.view.panel.OnAllPadsDo(InvalOnThePad);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgDbg}
FUNCTION TLayoutBox.NoTitleTab(heap: THeap): TTitleTab;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
NoTitleTab := TTitleTab.CREATE(NIL, heap, SELF, 0, noID);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgLayout}
PROCEDURE TLayoutBox.OffsetBy(deltaLPt: LPoint);
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF SELF.manipulee <> NIL THEN
SELF.manipulee.OffsetBy(deltaLPt);
{offset MY manipulee, but not my children's, since my
my manipulee's OffsetBy will have done that already}
SELF.OffsetLayoutBoxBy(deltaLPt, TRUE);
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TLayoutBox.OffsetLayoutBoxBy(deltaLPt: LPoint; textImageAsWell: BOOLEAN);
{does NOT offset manipulee}
PROCEDURE YouOffset(obj: TObject);
VAR layoutBox: TLayoutBox;
BEGIN
layoutBox := TLayoutBox(obj);
layoutBox.OffsetLayoutBoxBy(deltaLPt, textImageAsWell);
END;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.titleTab <> NIL THEN
SELF.titleTab.OffsetBy(deltaLPt);
{$H-} OffsetLRect(SELF.extentLRect, deltaLPt.h, deltaLPt.v); {$H+}
SELF.EachActualPart(YouOffset); {tells children}
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TLayoutBox.RecalcExtent;
VAR s:
TListScanner;
newExtent:
LRect;
layoutBox:
TLayoutBox;
oldExtent:
LRect;
PROCEDURE InvalOldAndNew;
BEGIN
thePad.InvalLRect(oldExtent);
thePad.InvalLRect(newExtent);
END;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
oldExtent := SELF.extentLRect;
newExtent := SELF.manipulee.extentLRect;
IF SELF.children <> NIL THEN
IF SELF.children.Size > 0 THEN
BEGIN
newExtent := zeroLRect;
s := SELF.children.Scanner;
WHILE s.Scan(layoutBox) DO
IF EmptyLRect(newExtent) THEN
newExtent := layoutBox.extentLRect
ELSE
UnionLRect(newExtent, layoutBox.extentLRect, newExtent);
END;
LRectAddBorders(newExtent, SELF.borders, newExtent);
IF NOT equalLRect(oldExtent, newExtent) THEN
BEGIN
SELF.Resize(newExtent);
SELF.view.panel.OnAllPadsDo(InvalOldAndNew);
END;
IF SELF.parent <> NIL THEN
SELF.parent.RecalcExtent;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TLayoutBox.Resize(newExtent: LRect);
VAR newTitleExtent: LRect;
titleTab:
TTitleTab;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
titleTab := SELF.titleTab;
IF titleTab <> NIL THEN
BEGIN
newTitleExtent := newExtent;
newTitleExtent.bottom := newTitleExtent.top +
(titleTab.extentLRect.bottom - titleTab.extentLRect.top); {i.e., preserve old height}
titleTab.Resize(newTitleExtent);
END;
SUPERSELF.Resize(newExtentLRect);
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TLayoutBox.TabGrabbed;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
METHODS OF TLegendLayoutBox;
{$S SgLayout}
FUNCTION TLegendLayoutBox.CREATE(object: TObject; heap: THeap; itsView: TView; itsLegend: TLegend
): TLegendLayoutBox;
VAR itsTitleTab:
TTitleTab;
itsExtentLRect: LRect;
myBorders:
Rect;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF itsLegend.wouldBeDraggable THEN
myBorders := stdPlainBorders
ELSE
myBorders := zeroRect;
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TLegendLayoutBox(TLayoutBox.CREATE(object, heap, itsLegend.extentLRect, noID, NIL,
itsView, itsLegend, myBorders, FALSE, FALSE, FALSE));
WITH SELF DO
BEGIN
isDraggable := itsLegend.wouldBeDraggable;
shouldFrame := itsLegend.wouldBeDraggable;
textDialogImage := NIL;
wouldMakeSelection := TRUE;
{client could override, somehow?}
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TLegendLayoutBox.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('textDialogImage: TTextDialogImage');
Field('');
END;
{$S SgLayout}
{$ENDC}
FUNCTION TLegendLayoutBox.CursorAt(mouseLPt: LPoint): TCursorNumber;
VAR curCursor: TCursorNumber;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
curCursor := noCursor;
IF SELF.Hit(mouseLPt) THEN
IF SELF.titleTab.Hit(mouseLPt) THEN
curCursor := arrowCursor
ELSE
IF SELF.wouldMakeSelection THEN
curCursor := textCursor;
CursorAt := curCursor;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TLegendLayoutBox.Draw;
VAR titleTab:
TTitleTab;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF LRectIsVisible(SELF.extentLRect) THEN
BEGIN
IF SELF.isDraggable THEN
SELF.titleTab.Draw;
IF SELF.textDialogImage <> NIL THEN {+SW+}
SELF.textDialogImage.Draw
ELSE
SELF.manipulee.Draw;
PenNormal;
IF SELF.IsDraggable AND SELF.shouldFrame THEN
FrameLRect(SELF.extentLRect); {draw overall box}
END;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TLegendLayoutBox.MousePress(mouseLPT: LPoint);
VAR editLegendSelection:
TEditLegendSelection;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
TPlannerView(SELF.view).magnetCursor := textCursor;
LRectHaveLPt(SELF.manipulee.extentLRect, mouseLPt);
editLegendSelection := TEditLegendSelection(SELF.view.panel.selection.FreedAndReplacedBy(
TEditLegendSelection.CREATE(NIL, SELF.Heap, SELF, mouseLPT)));
editLegendSelection.textDialogImage.MousePress(mouseLPt);
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TLegendLayoutBox.OffsetLayoutBoxBy(deltaLPt: LPoint; textImageAsWell: BOOLEAN);
{does NOT offset manipulee}
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SUPERSELF.OffsetLayoutBoxBy(deltaLPt, textImageAsWell);
IF NOT textImageAsWell THEN
deltaLPt.v := 0; {don't do it vertically}
IF SELF.textDialogImage <> NIL THEN
SELF.textDialogImage.OffsetBy(deltaLPt);
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TLegendLayoutBox.RecalcExtent;
VAR newExtent:
LRect;
oldExtent:
LRect;
paraImage:
TParaImage;
textDialogImage:
TTextDialogImage;
legPara:
TParagraph;
PROCEDURE InvalOldAndNew;
BEGIN
thePad.InvalLRect(oldExtent);
thePad.InvalLRect(newExtent);
END;
PROCEDURE PourItBack(obj: TObject);
VAR paragraph: TParagraph;
BEGIN
paragraph := TParaImage(obj).paragraph;
legPara.ReplPara(0, legPara.size, paragraph, 0, paragraph.size);
END;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
textDialogImage := SELF.textDialogImage;
IF textDialogImage <> NIL THEN
BEGIN
paraImage := TParaImage(textDialogImage.textImage.imageList.First);
legPara := TLegend(SELF.manipulee).paragraph;
textDialogImage.textImage.FilterAndDo(paraImage, PourItBack);
END;
TLegend(SELF.manipulee).RecalcExtent;
oldExtent := SELF.extentLRect;
newExtent := SELF.manipulee.extentLRect;
LRectAddBorders(newExtent, SELF.borders, newExtent);
IF NOT equalLRect(oldExtent, newExtent) THEN
BEGIN
SELF.Resize(newExtent);
SELF.view.panel.OnAllPadsDo(InvalOldAndNew);
END;
IF SELF.parent <> NIL THEN
SELF.parent.RecalcExtent;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
METHODS OF TButtonLayoutBox;
{$S DlgLayout}
FUNCTION TButtonLayoutBox.CREATE(object: TObject; heap: THeap; itsButton: TButton;
itsView: TView): TButtonLayoutBox;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TButtonLayoutBox(TLayoutBox.CREATE(object, heap, itsButton.extentLRect, itsButton.id, NIL,
itsView, itsButton, stdIDBorders, FALSE, TRUE, TRUE));
SELF.nextSameSizedBox := SELF; {will be correctly set by TPlannerView.CREATE after all layout
boxes made}
SELF.oldLegendTopLeft := itsButton.legend.extentLRect.topLeft;
SELF.AddImage(TDialogImage(itsButton.legend.LaunchLayoutBox(itsView)));
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TButtonLayoutBox.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('nextSameSizedBox: TButtonLayoutBox');
Field('oldLegendTopLeft: LPoint');
Field('');
END;
{$ENDC}
{$S DlgLayout}
PROCEDURE TButtonLayoutBox.ConsiderMouse(mouseLPt: LPoint; VAR madeSelection: BOOLEAN;
VAR pickedLayoutBox: TLayoutBox);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
pickedLayoutBox := NIL;
madeSelection := FALSE;
IF SELF.Hit(mouseLPt) THEN
BEGIN
pickedLayoutBox := SELF;
IF NOT LRectHasLPt(SELF.titleTab.extentLRect, mouseLPt) THEN
{hit on interior -- hence, editing button text}
BEGIN
madeSelection := TRUE;
LRectHaveLPt(TLayoutBox(SELF.children.First).extentLRect, mouseLPt);
SELF.MousePress(mouseLPt);
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgLayout}
FUNCTION TButtonLayoutBox.CursorAt(mouseLPt: LPoint): TCursorNumber;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF NOT SELF.Hit(mouseLPt) THEN
CursorAt := noCursor
ELSE
IF SELF.titleTab.Hit(mouseLPt) THEN
CursorAt := arrowCursor
ELSE
CursorAt := textCursor;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgLayout}
PROCEDURE TButtonLayoutBox.DrawJustMe;
VAR s:
TListScanner;
layoutBox: TLayoutBox;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF LRectIsVisible(SELF.extentLRect) THEN
BEGIN
SELF.titleTab.Draw;
TButton(SELF.manipulee).DrawJustMe; {draws just the roundRect; my child will draw the text}
PenNormal;
FrameLRect(SELF.extentLRect); {draw overall box}
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgLayout}
PROCEDURE TButtonLayoutBox.OffsetBy(deltaLPt: LPoint);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SUPERSELF.OffsetBy(deltaLPt);
{$H-} LPtPlusLPt(SELF.oldLegendTopLeft, deltaLPt, SELF.oldLegendTopLeft); {$H+}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgLayout}
PROCEDURE TButtonLayoutBox.RecalcExtent;
VAR nextBox:
TButtonLayoutBox;
oldLegendTopLeft: LPoint;
newLegendTopLeft: LPoint;
deltaLPt:
LPoint;
legendBox:
TLegendLayoutBox;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
legendBox := TLegendLayoutBox(SELF.children.First);
newLegendTopLeft := legendBox.manipulee.extentLRect.topLeft;
oldLegendTopLeft := SELF.oldLegendTopLeft;
IF NOT EqualLPt(oldLegendTopLeft, newLegendTopLeft) THEN
BEGIN
LPtMinusLPt(newLegendTopLeft, oldLegendTopLeft, deltaLPt);
legendBox.OffsetLayoutBoxBy(deltaLPt, TRUE);
SELF.oldLegendTopLeft := newLegendTopLeft;
END;
nextBox := SELF;
REPEAT
nextBox.RecalcJustMe;
nextBox := nextBox.nextSameSizedBox;
UNTIL
nextBox = SELF;
IF SELF.parent <> NIL THEN
SELF.parent.RecalcExtent;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgLayout}
PROCEDURE TButtonLayoutBox.RecalcJustMe; {my manipulee's size may've changed}
VAR nextBox:
TButtonLayoutBox;
oldExtent: LRect;
newExtent: LRect;
PROCEDURE InvalOldAndNew;
BEGIN
thePad.InvalLRect(oldExtent);
thePad.InvalLRect(newExtent);
END;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
oldExtent := SELF.extentLRect;
newExtent := SELF.manipulee.extentLRect;
LRectAddBorders(newExtent, SELF.borders, newExtent);
SELF.Resize(newExtent);
SELF.view.panel.OnAllPadsDo(InvalOldAndNew);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
METHODS OF TTitleTab;
{$S SgLayout}
FUNCTION TTitleTab.CREATE(object: TObject; heap: THeap; itsLayoutBox: TLayoutBox; itsHeight: INTEGER;
itsCaption: S255): TTitleTab;
VAR extentLRect:
LRect;
legend:
TLegend;
location:
LPoint;
{$IFC libraryVersion <= 20}
{* * * P E P S I * * *}
{$ELSEC}
{$ENDC}
fInfo:
fInfo:
TFInfo;
{* * S P R I N G
FontInfo;
width:
newLegTopLeft:
INTEGER;
LPoint;
* *}
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
WITH itsLayoutBox.extentLRect DO
{$H-}
SetLRect(extentLRect, left, top, right, top + itsHeight);
{$H+}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TTitleTab.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('layoutBox: TLayoutBox');
Field('legend: TLegend');
Field('shouldDrawLegend: BOOLEAN');
Field('');
END;
{$S SgLayout}
{$ENDC}
{$S SgLayout}
PROCEDURE TTitleTab.Draw;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
PenNormal;
FillLRect(SELF.extentLRect, lPatWhite);
FrameLRect(SELF.extentLRect);
IF SELF.shouldDrawLegend THEN
{it exists and is small enough to fit}
SELF.legend.Draw;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgLayout}
PROCEDURE TTitleTab.OffsetBy(deltaLPt: LPoint);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.legend <> NIL THEN
SELF.legend.OffsetBy(deltaLPt);
SUPERSELF.OffsetBy(deltaLPt);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgLayout}
PROCEDURE TTitleTab.Resize{(newExtent: LRect)};
VAR myCaption:
S255;
{$IFC libraryVersion <= 20}
{* * * P E P S I * * *}
fInfo:
TFInfo;
{$ELSEC}
{* * S P R I N G * *}
fInfo:
FontInfo;
{$ENDC}
strLocation:
captionWidth:
deltaLPt:
typeStyle:
LPoint;
INTEGER;
LPoint;
TTypeStyle;
BEGIN
{$IFC fTrace}BP(11);{$ENDC} {this does the wrong thing for high view resolutions; must fix}
IF SELF.legend <> NIL THEN
BEGIN
SELF.legend.GetString(myCaption);
SELF.legend.paragraph.StyleAt(0, typeStyle);
SetQDTypeStyle(typeStyle);
GetFontInfo(fInfo);
captionWidth := StringWidth(myCaption);
{$H-}
WITH newExtentLRect, fInfo DO
SetLPt(strLocation, ((left + right - captionWidth) DIV 2),
bottom - descent);
{had had a -2 here}
{$H+}
SetLPt(deltaLPt, strLocation.h - SELF.legend.location.h,
strLocation.v - SELF.legend.location.v);
SELF.legend.OffsetBy(deltaLPt); {do more cleverly -- maybe TLegend.OffsetTo}
WITH SELF.legend.extentLRect DO
IF right - left > newExtent.right - newExtent.left THEN
SELF.shouldDrawLegend := FALSE
ELSE
SELF.shouldDrawLegend := TRUE;
END;
SELF.extentLRect := newExtentLRect;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
METHODS OF TLayPickSelection;
{$S SgLayout}
FUNCTION TLayPickSelection.CREATE(object: TObject; heap: THeap; itsView: TPlannerView; itsKind: INTEGER;
itsLayoutBox: TLayoutBox; itsAnchorLPt: LPoint): TLayPickSelection;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TLayPickSelection(TSelection.CREATE(object, heap, itsView, itsKind, itsAnchorLPt));
SELF.layoutBox := itsLayoutBox;
SELF.boundLRect := itsLayoutBox.extentLRect;
itsView.currentLayoutBox := itsLayoutBox;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TLayPickSelection.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('layoutBox: TLayoutBox');
Field('');
END;
{$S SgLayout}
{$ENDC}
{$S SgLayout}
FUNCTION TLayPickSelection.CanDoCommand(cmdNumber: TCmdNumber; VAR checkIt: BOOLEAN): BOOLEAN;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
CASE cmdNumber OF
uClear:
CanDoCommand := TRUE;
OTHERWISE
CanDoCommand := SUPERSELF.CanDoCommand(cmdNumber, checkIt);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgLayout}
PROCEDURE TLayPickSelection.Deselect;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
TPlannerView(SELF.view).currentLayoutBox := NIL;
SELF.layoutBox.ChangeDragState(FALSE);
SUPERSELF.Deselect;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgLayout}
PROCEDURE TLayPickSelection.Highlight(highTransit: THighTransit);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.layoutBox.Highlight(highTransit);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgLayout}
PROCEDURE TLayPickSelection.MouseMove(mouseLPt: LPoint);
VAR diffLPt:
LPoint;
diffLRect:
LRect;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
{How far did mouse move?}
LPtMinusLPt(mouseLPt, SELF.currLPt, diffLPt);
{Don't move past view boundaries}
LRectMinusLRect(SELF.view.extentLRect, SELF.layoutBox.extentLRect, diffLRect);
LRectHaveLPt(diffLRect, diffLPt);
{Move it if delta is nonzero}
IF NOT EqualLPt(diffLPt, zeroLPt) THEN
BEGIN
{$H-} OffsetLRect(SELF.boundLRect, diffLPt.h, diffLPt.v); {$H+}
LPtPlusLPt(SELF.currLPt, diffLPt, mouseLPt);
SELF.currLPt := mouseLPt;
{probably discard}
SELF.layoutBox.Move(diffLPt);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgLayout}
PROCEDURE TLayPickSelection.MouseRelease;
VAR deltaLPt:
LPoint;
noSelection:
TSelection;
manipulee:
TImage;
parent:
TDialogImage;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF NOT EqualLPt(SELF.currLPt, SELF.anchorLPt) THEN
BEGIN
LPtMinusLPt(SELF.currLPt, SELF.anchorLPt, deltaLPt);
SELF.window.PerformCommand(TLayMoveCmd.CREATE(NIL, SELF.Heap,
SELF.layoutBox, deltaLPt.h, deltaLPt.v));
END;
manipulee := SELF.layoutBox.manipulee;
IF manipulee <> NIL THEN
manipulee.RecalcExtent; {will send it up the line to its parents}
parent := SELF.layoutBox.parent;
IF parent <> NIL THEN {now send it up the line to my own parents}
IF InClass(parent, TLayoutBox) THEN
parent.RecalcExtent;
IF NOT TPlannerView(SELF.layoutBox.view).retainPickedBox THEN
SELF.Deselect;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgLayout}
PROCEDURE TLayPickSelection.Restore;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
TPlannerView(SELF.view).currentLayoutBox := SELF.layoutBox;
SUPERSELF.Restore;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
METHODS OF TLayMoveCmd;
{$S SgLayout}
FUNCTION TLayMoveCmd.CREATE{(object: TObject; heap: THeap; itsLayoutBox: TLayoutBox;
itsHOffset, itsVOffset: LONGINT): TLayMoveCmd};
VAR retainPickedBox:
BOOLEAN;
cmdPhase:
TCmdPhase;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TLayMoveCmd(TCommand.CREATE(object, heap, uMoveLayoutBoxes, itsLayoutBox.view,
TRUE, revealSome));
WITH SELF DO
BEGIN
layoutBox := itsLayoutbox;
hOffset := itsHOffset;
vOffset := itsVOffset;
retainPickedBox := TPlannerView(itsLayoutBox.view).retainPickedBox;
WITH SELF DO
BEGIN
unHiliteBefore[doPhase] := FALSE;
hiliteAfter[doPhase] := FALSE;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TLayMoveCmd.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('layoutBox: TLayoutBox');
Field('hOffset: LONGINT');
Field('vOffset: LONGINT');
Field('');
END;
{$ENDC}
{$S SgLayout}
PROCEDURE TLayMoveCmd.Perform(cmdPhase: TCmdPhase);
VAR plannerView:
TPlannerView;
panel:
TPanel;
diffLPt:
LPoint;
BEGIN
{$IFC fTrace}BP(12);{$ENDC}
IF cmdPhase <> doPhase THEN
BEGIN
WITH SELF DO {$H-}
CASE cmdPhase OF
redoPhase:
SetLPt(diffLPt, hOffset, vOffset);
undoPhase:
SetLPt(diffLPt, -hOffset, -vOffset);
END; {$H+}
SELF.layoutBox.Move(diffLPt);
SELF.layoutBox.manipulee.RecalcExtent;
SELF.layoutBox.RecalcExtent;
IF NOT TPlannerView(SELF.layoutBox.view).retainPickedBox THEN
SELF.layoutBox.view.panel.selection.Deselect;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
METHODS OF TEditLegendSelection;
{$S SgLayout}
FUNCTION TEditLegendSelection.CREATE(object: TObject; heap: THeap; itsLegendLayoutBox:
TLegendLayoutBox; itsAnchorLPt: LPoint): TEditLegendSelection;
VAR coSelection:
TSelection;
paragraph:
TParagraph;
paraImage:
TParaImage;
hostLegend:
TLegend;
textDialogImage:
TTextDialogImage;
textImage:
TTextImage;
textExtent:
LRect;
typeStyle:
TTypeStyle;
hostParagraph:
TParagraph;
PROCEDURE FindBiggestFont(VAR biggestTypeStyle: TTypeStyle);
VAR styleChange:
TStyleChange;
{$IFC libraryVersion <= 20}
{* * * P E P S I * * *}
fInfo:
TFInfo;
{$ELSEC}
{* * S P R I N G * *}
fInfo:
FontInfo;
{$ENDC}
i:
INTEGER;
oldTallest:
INTEGER;
BEGIN
oldTallest := 0;
FOR i := 1 TO hostParagraph.typeStyles.size - 1 DO
BEGIN
hostParagraph.typeStyles.GetAt(i, @styleChange);
hostParagraph.SetTypeStyle(styleChange.newStyle);
GetFontInfo(fInfo);
WITH fInfo DO
IF oldTallest < ascent + descent + leading THEN
BEGIN
oldTallest := ascent + descent + leading;
biggestTypeStyle := styleChange.newStyle;
END;
END;
END;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
Clone := TEditLegendSelection(SUPERSELF.Clone(heap));
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgLayout}
PROCEDURE TEditLegendSelection.Deselect;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.legendLayoutBox.textDialogImage := NIL; {+SW+}
SUPERSELF.Deselect;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgLayout}
PROCEDURE TEditLegendSelection.Free;
VAR textDialogImage:
TTextDialogImage;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
textDialogImage := SELF.textDialogImage; {+SW+} {five lines out}
SUPERSELF.Free;
textDialogImage.ChangeRefCountBy(-1);
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TEditLegendSelection.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('legendLayoutBox: TLegendLayoutBox');
Field('hostLegend: TLegend');
Field('textDialogImage: TTextDialogImage');
Field('suppressHost: BOOLEAN');
Field('tripleClick: BOOLEAN'); {+SW+}
Field('');
END;
{$ENDC}
{$S SgLayout}
FUNCTION TEditLegendSelection.CanDoCommand(cmdNumber: TCmdNumber; VAR checkIt: BOOLEAN): BOOLEAN;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
CASE cmdNumber OF
uModern, uClassic,u20Pitch, u15Pitch, u12Pitch, u10Pitch, u12Point, u14Point, u18Point, u24Point,
END;
{$S SgLayout}
PROCEDURE TEditLegendSelection.KeyEnter(dh, dv: INTEGER);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF (dh <> 0) OR (dv <> 0) THEN
SELF.KeyTab((dh < 0) OR (dv < 0)); {right and down keys are Forward}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgLayout}
PROCEDURE TEditLegendSelection.KeyReturn;
VAR selection: TSelection;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.Deselect;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgLayout}
PROCEDURE TEditLegendSelection.MousePress(mouseLPT: LPoint); {+SW+}
VAR selection: TSelection;
textImage: TTextImage;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF clickState.clickCount < 3 THEN
SUPERSELF.MousePress(mouseLPt)
ELSE {triple click; force SelectAll}
BEGIN
SELF.tripleClick := TRUE;
textImage := SELF.textDialogImage.textImage;
SELF.Highlight(hOnToOff);
SELF.coSelection.Become(
textImage.text.SelectAll(textImage));
SELF.Highlight(hOffToOn);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgLayout}
PROCEDURE TEditLegendSelection.MouseMove(mouseLPT: LPoint); {+SW+}
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
VAR lr:
LRect;
hMin:
INTEGER;
vMin:
INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.coselection.boundLRect := SELF.boundLRect;
SUPERSELF.Reveal(asMuchAsPossible);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
METHODS OF TDialogDesignWindow;
{$S DlgAlloc}
FUNCTION TDialogDesignWindow.CREATE(object: TObject; heap: THeap;
itsHostDialogView: TDialogView): TDialogDesignWindow;
VAR fromBox:
BOOLEAN;
window:
TWindow;
htLPt:
LPoint;
height:
INTEGER;
htPt:
Point;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
window := itsHostDialogView.panel.window;
fromBox := InClass(window, TDialogBox);
IF fromBox THEN
height := window.outerRect.bottom - window.outerRect.top + 15
ELSE
BEGIN
WITH itsHostDialogView.extentLRect DO
{$H-}
SetLPt(htLPt, 0, bottom - top); {$H+}
itsHostDialogView.screenPad.LPtToPt(htLPt, htPt);
height := MIN(htPt.v + 15, screenBits.bounds.bottom - 30);
END;
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TDialogDesignWindow(TDialogWindow.CREATE(object, heap, TRUE, height,
diAccept, diAccept, diRefuse));
WITH SELF DO
BEGIN
hostWindow := window;
hostDialogView := itsHostDialogView;
fromDialogBox := fromBox;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TDialogDesignWindow.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('hostWindow: TWindow');
Field('hostDialogView: TDialogView');
Field('fromDialogBox: BOOLEAN');
Field('');
END;
{$ENDC}
{$S DlgLayout}
FUNCTION TDialogDesignWindow.CanDoCommand(cmdNumber: TCmdNumber; VAR checkIt: BOOLEAN): BOOLEAN;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
CASE cmdNumber OF
uEditDialog:
CanDoCommand := FALSE; {override SUPERSELF}
uStopEditDialog:
CanDoCommand := TRUE;
OTHERWISE
CanDoCommand := SUPERSELF.CanDoCommand(cmdNumber, checkIt);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgLayout}
FUNCTION TDialogDesignWindow.NewCommand(cmdNumber: TCmdNumber): TCommand;
BEGIN
{$IFC fTrace}BP(12);{$ENDC}
CASE cmdNumber OF
uStopEditDialog:
BEGIN
SELF.RelinquishControl;
NewCommand := NIL;
END;
OTHERWISE
NewCommand := SUPERSELF.NewCommand(cmdNumber);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgLayout}
PROCEDURE TDialogDesignWindow.RelinquishControl;
{not yet: install in resourceFile}
VAR panel:
TPanel;
plannerView:
TPlannerView;
dialogWindow:
TDialogWindow;
newHeight:
INTEGER;
noSelection:
TSelection;
newBotRight:
point;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
panel := SELF.selectPanel;
panel.selection.Deselect;
{should incorporate last text edit, if any}
panel.window.CommitLast;
panel.BeginSelection;
{previous didn't really quite do it yet}
currentWindow.TakeDownDialogBox;
IF SELF.fromDialogBox THEN {editing a dialog box--copy the resizing back to the dialog Window}
BEGIN
plannerView := TPlannerView(panel.currentView);
newHeight := panel.innerRect.bottom;
dialogWindow := TDialogWindow(plannerView.viewBeingPlanned.panel.window);
SetPt(newBotRight, screenBits.bounds.right, newHeight);
{transfer its current...}
currentWindow.PutUpDialogBox(dialogWindow);
dialogWindow.ResizeTo(newBotRight);
{height to main dialog}
IF dialogWindow.selectPanel.selection.kind <> nothingKind THEN
currentWindow.selectWindow := dialogWindow; {=}
END;
SELF.selectPanel.view := NIL;
{kludge to avoid clobbering the main view}
currentWindow.Focus; {necessary to avoid a later popFocus trying to focus our now departed
DialogDesignWindow}
SELF.Free; {!}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgLayout}
PROCEDURE TDialogDesignWindow.Resize(moving: BOOLEAN);
VAR view:
TView;
extentLRect:
LRect;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SUPERSELF.Resize(moving); {moving is always FALSE of course}
IF SELF.hostWindow.isResizable THEN
{do nothing, I guess}
ELSE
BEGIN
view := SELF.selectPanel.currentView;
extentLRect := view.extentLRect;
extentLRect.bottom := SELF.selectPanel.innerRect.bottom;
view.Resize(extentLRect);
{that'll be the layout view}
SELF.hostDialogView.Resize(extentLRect);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgLayout}
PROCEDURE TDialogDesignWindow.SeizeControl;
VAR dialogView:
TDialogView;
panel:
TPanel;
children:
TList;
imageList:
TList;
dialogBox:
TDialogBox;
savedSetting:
BOOLEAN;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
dialogView := SELF.hostDialogView;
children := dialogView.rootDialog.children;
IF SELF.fromDialogBox THEN
BEGIN
dialogBox := currentWindow.dialogBox;
savedSetting := dialogBox.freeOnDismissal;
dialogBox.freeOnDismissal := FALSE;
currentWindow.TakeDownDialogBox;
dialogBox.freeOnDismissal := savedSetting;
END;
panel := TPanel.CREATE(NIL, SELF.Heap, SELF, 0, SELF.innerRect.right - 23, [aScroll, aBar],
[aScroll, aBar]);
SELF.controlPanel := panel;
CASE children.Size OF
0:
ABCBreak('SeizeControl, empty children of dialog view', 0);
1:
imageList := TDialog(children.First).children;
OTHERWISE
imageList := children;
END; {case}
{UDialog4}
(*
ORDER OF METHODS:
CLASS
-----------------TStdPrintManager
TLegendHeading
TPageDesignWindow
TPagePlannerView
TPageLayoutBox
TLgHdngLayoutBox
TPageStatusDialog
SUBCLASS OF
------------TPrintManager
THeading
TDialogWindow
TPlannerView
TLayoutBox
TPageLayoutBox
TDialog
WHICH IS IN
----------UABC3
UABC3
UDialog2
UDialog3
UDialog3
UDialog4
UDialog2
*)
{04/25/84 19:00 TLgHdngLayoutBox.MousePress -- don't invalidate the layout box
TPageStatusDialog.CREATE explicitly sets extentLRect's topLeft to zeroLPt}
{04/24/84 23:51 TPageDesignWindow.CREATE sets the status view's scrollPastEnd to zeroPt}
{04/24/84 18:00 TPageDesignWindow.CREATE allows scrolling in the status panel}
{04/23/84 12:18 In TStdPrintManager.SetDfltHeadings, supply a blank space before and after the
the '{TITLE)', so that a select-all followed by a font change will result in
the new font applying to the substituted string at print or page-preview time}
{04/17/84 17:16 Make the TPagePlannerView show no gray at the end.}
{04/15/84 0200
TPageDesignWindow.NewCommand frees panel's undoSelection as well as main selection}
{04/14/84 03:00 Removed pilotHeading from TPageLayoutBox; removed TPageLayoutBox.Free, consequently,
as well as TPageLayoutBox.Fields
Offset master as well as current Legend in TLegendHeading.OffsetBy}
{changed 04/14/84 0102 Major rewrite of TLgHdngLayoutBox.RecalcExtent & TP }
{changed 04/13/84 2230 TLgHdngLayoutBox.RecalcExtent doesn't call SetParaExtent; just uses legend's extent
& TPageLayoutBox.FreeManipulee sets SELF.manipulee to NIL after freeing
& TPageDesignWindow.NewCommand sets plannerView.currentLayoutBox to NIL
after freeing the LgHdngLayoutBox...}
{changed 04/13/84 1630 Changed to not using bolding on the margins-dialog heading}
{changed 04/11/84 2315 Do TopToBaseLine stuff in hdngs recalculation only if not fExperimenting...}
{changed 04/11/84 1700 Use dfltNewHeading global var in laucnhing new heading in TDialogDesignWindow.NewCmd,
and varPage and varTitle in TStdPrintManager.SetDfltHeadings;
In TPageStatusDialog.CREATE, use a CONST depending on libraryVersion to determine
the spacing between the boxes in the margins checkbox dialog}
{04/04/84 2300 Spring Prelim Release}
{01/29/84 1800 RELEASE TK8D}
{12/21/83 1657 RELEASE TK8A}
METHODS OF TStdPrintManager;
{$S DlgAlloc}
FUNCTION TStdPrintManager.CREATE(object: TObject; heap: THeap): TStdPrintManager;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TStdPrintManager(TPrintManager.CREATE(object, heap));
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
PROCEDURE
CONST
TStdPrintManager.SetDfltHeadings;
topFudge = 0;
bottomFudge = 0;
VAR anOffset:
LPoint;
margins:
LRect;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
margins := SELF.pageMargins;
SetLPt(anOffset, 0, (margins.top + topFudge) DIV 2);
SELF.headings.InsLast(TLegendHeading.CREATE(NIL, SELF.Heap, SELF, CONCAT(' {', varTitle, '} '), {+SW+}
stdHdngTypeStyle, aTopCenter, anOffset, stdHdngBorders));
SetLPt(anOffset, 0, - (ABS(margins.bottom + bottomFudge) DIV 2));
SELF.headings.InsLast(TLegendHeading.CREATE(NIL, SELF.Heap, SELF,
stdHdngTypeStyle, aBottomCenter, anOffset, stdHdngBorders));
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgAlloc}
PROCEDURE TStdPrintManager.Init(itsMainView: TView; itsDfltMargins: LRect);
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SUPERSELF.Init(itsMainView, itsDfltMargins);
SELF.canEditPages := TRUE;
{$IFC fTrace}EP;{$ENDC}
END;
{$S HdgMarg}
PROCEDURE TStdPrintManager.EnterPageEditting;
VAR window:
TWindow;
pageDesignWindow:
TPageDesignWindow;
pagePlannerView:
TPagePlannerView;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
window := SELF.view.panel.window;
window.CommitLast;
IF SELF.layoutDialogBox = NIL THEN
BEGIN
pageDesignWindow := TPageDesignWindow.CREATE(NIL, SELF.Heap, SELF.view);
SELF.layoutDialogBox := pageDesignWindow;
END;
window.PutUpDialogBox(SELF.layoutDialogBox);
{$IFC fTrace}EP;{$ENDC}
END;
{$S TK2Start}
PROCEDURE TStdPrintManager.ReactToPrinterChange;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SUPERSELF.ReactToPrinterChange;
IF SELF.layoutDialogBox <> NIL THEN
TPageDesignWindow(SELF.layoutDialogBox).layoutPanel.view.Resize(SELF.pageView.extentLRect);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
METHODS OF TLegendHeading;
{$S DlgAlloc}
FUNCTION TLegendHeading.CREATE(object: TObject; heap: THeap; itsPrintManager: TPrintManager;
itsString: S255; itsTypeStyle: TTypeStyle;
itsPageAlignment: TPageAlignment; itsOffsetFromAlignment: LPoint;
itsBorders: Rect): TLegendHeading;
VAR newMaster: TLegend;
newCurrent: TLegend;
extent:
LRect;
view:
TView;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
view := itsPrintManager.pageView;
SetLRect(extent, 0, 0, 100, 100); {meaningless at this point}
Field('topToBaseline: INTEGER');
Field('borders: Rect');
Field('');
END;
{$ENDC}
{$S DlgRes}
PROCEDURE TLegendHeading.AdjustForPage(pageNumber: LONGINT; editing: BOOLEAN);
VAR currS255:
S255;
aVariable:
S255;
leftBracePos:
INTEGER;
rightBracePos:
INTEGER;
newValue:
S255;
restOfString:
S255;
newExtent:
LRect;
currentParagraph:
TParagraph;
masterParagraph:
TParagraph;
substituted:
BOOLEAN;
lastPosition:
INTEGER;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
substituted := FALSE; {still flawed}
lastPosition := 0;
SELF.masterLegend.GetString(currS255);
currentParagraph := SELF.currentLegend.paragraph;
masterParagraph := SELF.masterLegend.paragraph;
currentParagraph.ReplPara(0, currentParagraph.size, masterParagraph, 0,
masterParagraph.size); {download entire master into current}
IF NOT editing THEN
BEGIN
REPEAT
leftBracePos := POS('{', currS255);
IF leftBracePos > 0 THEN
IF leftBracePos < lastPosition THEN {was within the previous variable}
currS255[leftBracePos] := '$'
{... so we won't get it next time}
ELSE
BEGIN
restOfString := COPY(currS255, leftBracePos + 1, LENGTH(currS255) - leftBracePos);
rightBracePos := POS('}', restOfString);
IF rightBracePos > 0 THEN
BEGIN
aVariable := COPY(restOfString, 1, rightBracePos - 1);
SELF.printManager.view.SetFunctionValue(aVariable, newValue);
substituted := TRUE;
currentParagraph.ReplPString(leftBracePos - 1, rightBracePos + 1,
@newValue);
UNTIL
leftBracePos = 0;
END
{not editing}
ELSE {editing}
SELF.masterLegend.GetBoxRight;
SELF.RecalcExtent; {tells currentLegend to get box right, then adds in my borders}
{we only need worry about our extentLRect, our location, and our current legend all
being in synch; THeading.LocateOnPage will then find the exact page location,
taking into account my offsetFromAlignment}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgRes}
PROCEDURE TLegendHeading.Draw;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
IF SELF.ShouldFrame THEN
FrameLRect(SELF.extentLRect);
SELF.currentLegend.Draw;
{$IFC fTrace}EP;{$ENDC}
END;
{$S HdgMarg}
FUNCTION TLegendHeading.LaunchLayoutBox(view: TView): TImage;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
LaunchLayoutBox := TLgHdngLayoutBox.CREATE(NIL, SELF.Heap, view, SELF);
{$IFC fTrace}EP;{$ENDC}
END;
{$S HdgMarg}
PROCEDURE TLegendHeading.OffsetBy(deltaLPt: LPoint);
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
SELF.currentLegend.OffsetBy(deltaLPt);
SUPERSELF.OffsetBy(deltaLPt);
{$IFC fTrace}EP;{$ENDC}
END;
{$S TK2Start}
PROCEDURE TLegendHeading.RecalcExtent;
VAR newExtent: LRect;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
SELF.currentLegend.GetBoxRight;
LRectAddBorders(SELF.currentLegend.extentLRect, SELF.borders, newExtent);
SELF.Resize(newExtent);
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgRes}
FUNCTION TLegendHeading.ShouldFrame;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
ShouldFrame := FALSE;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
METHODS OF TPageDesignWindow;
{$S DlgAlloc}
FUNCTION TPageDesignWindow.CREATE(object: TObject; heap: THeap; itsHostView: TView): TPageDesignWindow;
CONST
cPgWindowHeight = 340;
cPgControlHeight = 130; {height of the control (status) panel}
cHtStatusView = 220;
VAR controlPanel:
layoutPanel:
hdngDialog:
plannerView:
dialogView:
extentLRect:
BEGIN
TPanel;
TPanel;
THeadingDialog;
TPlannerView;
TDialogView;
LRect;
{$IFC fTrace}BP(11);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TPageDesignWindow(TDialogWindow.CREATE(object, heap, TRUE, cPgWindowHeight, diAccept,
diAccept, diRefuse));
SELF.hostView := itsHostView;
layoutPanel := TPanel.CREATE(NIL, heap, SELF, 0, 0, [aScroll, aSplit], [aScroll, aSplit]);
plannerView := TPagePlannerView.CREATE(NIL, heap, itsHostView.printManager, layoutPanel);
SELF.layoutPanel := layoutPanel;
controlPanel := layoutPanel.Divide(v, cPgControlHeight, pixelsFromEdge,
[userCanResizeIt], 10 {min size}, [aScroll], [aScroll]); {+SW+}
SELF.controlPanel := controlPanel;
SetLRect(extentLRect, 0, 0, screenBits.bounds.right, cHtStatusView);
dialogView := TDialogView.CREATE(NIL, heap, extentLRect, controlPanel, NIL, screenRes);
dialogView.scrollPastEnd := zeroPt; {+SW+}
dialogView.AddDialog(TPageStatusDialog.CREATE(NIL, heap, dialogView.panel));
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
PROCEDURE TPageDesignWindow.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('hostView: TView');
Field('layoutPanel: TPanel');
Field('');
END;
{$ENDC}
PROCEDURE TPageDesignWindow.Disappear;
VAR panel: TPanel;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
panel := TPagePlannerView(SELF.layoutPanel.view).viewBeingPlanned.panel;
IF panel.previewMode = mPrvwMargins THEN {make sure headings are updated}
panel.Invalidate;
SUPERSELF.Disappear;
{$IFC fTrace}EP;{$ENDC}
END;
{$S HdgMarg}
{$S DlgAlloc}
FUNCTION TPagePlannerView.CREATE(object: TObject; heap: THeap; itsPrintManager: TPrintManager;
itsPanel: TPanel): TPagePlannerView;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TPagePlannerView(TPlannerView.CREATE(object, heap, itsPrintManager.pageView, itsPanel,
FALSE, TRUE));
PushFocus;
TPane(itsPrintManager.view.panel.panes.First).Focus; {so that thePad will be set to something}
SELF.Init(itsPrintManager.headings);
PopFocus;
SELF.scrollPastEnd := zeroPt;
{$IFC fTrace}EP;{$ENDC}
END;
{$S HdgMarg}
PROCEDURE TPagePlannerView.Draw;
VAR contentLRect:
LRect;
pat:
Pattern;
contentRect:
Rect;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
contentLRect := SELF.viewBeingPlanned.printManager.contentLRect;
thePad.LPatToPat(marginPattern, pat);
thePad.LRectToRect(contentLRect, contentRect);
FillRect(contentRect, pat);
{screen embellishments}
PenNormal;
FrameLRect(SELF.extentLRect);
FrameLRect(contentLRect);
SUPERSELF.Draw;
{draw LayoutBoxes}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
METHODS OF TPageLayoutBox;
{$S HdgMarg}
FUNCTION
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
baseExtent := itsHeading.extentLRect;
baseExtent.top := baseExtent.top + stdSlimTitleHeight;
IF object = NIL THEN
object := NewObject(itsHeading.Heap, THISCLASS);
SELF := TPageLayoutBox(TLayoutBox.CREATE(object, heap, baseExtent, noID, NIL,
itsView, itsHeading, stdPlainBorders, itsResizable,
TRUE, TRUE));
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TPageLayoutBox.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('');
END;
{$ENDC}
{$S HdgMarg}
PROCEDURE TPageLayoutBox.FreeManipulee;
VAR s:
TListScanner;
heading:
THeading;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
s := TPlannerView(SELF.view).viewBeingPlanned.view.printManager.headings.Scanner;
WHILE s.Scan(heading) DO
IF heading = SELF.manipulee THEN
BEGIN
s.Delete(TRUE);
s.Done;
SELF.manipulee := NIL;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S HdgMarg}
PROCEDURE TPageLayoutBox.TabGrabbed;
VAR heading:
THeading;
pageStatusDialog:
TPageStatusDialog;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
heading := THeading(SELF.manipulee);
pageStatusDialog := TPageStatusDialog(TDialogView(TDialogWindow(SELF.view.panel.window
).controlPanel.view).rootDialog.children.First);
IF heading <> pageStatusDialog.currentHeading THEN
BEGIN
WITH heading DO
{$H-}
pageStatusDialog.SetHeadingParms(oddOnly, evenOnly, pageAlignment, minPage, maxPage); {$H+}
pageStatusDialog.currentHeading := heading;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
METHODS OF TLgHdngLayoutBox;
{$S HdgMarg}
FUNCTION
stdSlimTitleHeight, noID);
WITH SELF DO
BEGIN
titleTab := itsTitleTab;
manipulee := itsLegendHeading;
suppressDrawingManipulee := TRUE;
wouldMakeSelection := TRUE;
isResizable := FALSE;
isDraggable := TRUE;
shouldFrame := TRUE;
borders := zeroRect;
END;
legendLayoutBox := TLegendLayoutBox(itsLegendHeading.masterLegend.LaunchLayoutBox(itsView));
SELF.legendLayoutBox := legendLayoutBox;
SELF.AddImage(legendLayoutBox);
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S DlgDbg}
PROCEDURE TLgHdngLayoutBox.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('legendLayoutBox: TLegendLayoutBox');
Field('');
END;
{$ENDC}
{$S HdgMarg}
FUNCTION TLgHdngLayoutBox.CursorAt(mouseLPt: LPoint): TCursorNumber;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF SELF.Hit(mouseLPt) THEN
IF SELF.titleTab.Hit(mouseLPt) THEN
CursorAt := arrowCursor
ELSE
CursorAt := textCursor
ELSE
CursorAt := noCursor;
{$IFC fTrace}EP;{$ENDC}
END;
{$S HdgMarg}
PROCEDURE TLgHdngLayoutBox.Draw;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF LRectIsVisible(SELF.extentLRect) THEN
BEGIN
SELF.titleTab.Draw;
PenNormal;
FrameLRect(SELF.extentLRect);
SELF.legendLayoutBox.Draw;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S HdgMarg}
PROCEDURE TLgHdngLayoutBox.MousePress(mouseLPT: LPoint);
VAR layoutBox:
TLayoutBox;
s:
TListScanner;
editLegendSelection:
TEditLegendSelection;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
LRectHaveLPt(SELF.legendLayoutBox.extentLRect, mouseLPt);
editLegendSelection := TEditLegendSelection(SELF.view.panel.selection.FreedAndReplacedBy(
TEditLegendSelection.CREATE(NIL, SELF.Heap,
SELF.legendLayoutBox,
mouseLPT)));
SELF.TabGrabbed; {get report on me right in the page status panel}
editLegendSelection.textDialogImage.MousePress(mouseLPt);
{$IFC fTrace}EP;{$ENDC}
END;
{$S HdgMarg}
PROCEDURE TLgHdngLayoutBox.Move(deltaLPt: LPoint);
VAR legendHeading: TLegendHeading;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SUPERSELF.Move(deltaLPt); {offsets and invalidates}
legendHeading := TLegendHeading(SELF.manipulee);
legendHeading.masterLegend.OffsetBy(deltaLPt);
{$H-} LPtPlusLPt(legendHeading.offsetFromAlignment, deltaLPt, legendHeading.offsetFromAlignment);
{$IFC fTrace}EP;{$ENDC}
END;
{$S HdgMarg}
PROCEDURE TLgHdngLayoutBox.RecalcExtent;
VAR newExtent:
LRect;
oldExtent:
LRect;
deltaLPt:
LPoint;
newBaseLPoint:
LPoint;
borders:
Rect;
{$H+}
masterLegend:
TLegend;
oldTopToBaseline:
LONGINT;
newTopToBaseline:
LONGINT;
legendHeading:
TLegendHeading;
textExtent:
LRect;
alignedToTop:
BOOLEAN;
oldDescent:
INTEGER;
PROCEDURE InvalOldAndNew;
BEGIN
thePad.InvalLRect(oldExtent);
thePad.InvalLRect(newExtent);
END;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
oldExtent := SELF.extentLRect;
legendHeading := TLegendHeading(SELF.manipulee);
masterLegend := legendHeading.masterLegend;
borders := legendHeading.borders;
oldTopToBaseline := legendHeading.topToBaseline;
SetParaExtent(masterLegend.paragraph, SELF.view, zeroLpt, textExtent);
newTopToBaseline := - borders.top - textExtent.top;
alignedToTop := legendHeading.pageAlignment IN [aTopLeft, aTopCenter, aTopRight];
IF newTopToBaseline <> oldTopToBaseline THEN
BEGIN
IF alignedToTop THEN
legendHeading.offsetFromAlignment.v := legendHeading.offsetFromAlignment.v +
oldTopToBaseline - newTopToBaseline
ELSE {bottom alignment}
BEGIN
WITH oldExtent DO
oldDescent := bottom - top - oldTopToBaseline;
legendHeading.offsetFromAlignment.v := legendHeading.offsetFromAlignment.v textExtent.bottom + oldDescent;
END;
legendHeading.topToBaseline := newTopToBaseline;
END;
LRectAddBorders(SELF.legendLayoutBox.extentLRect, borders, newExtent);
legendHeading.Resize(newExtent);
legendHeading.LocateOnPage(TRUE);
newExtent := legendHeading.extentLRect;
SetLPt(newBaseLPoint, newExtent.left - borders.left, newExtent.top + newTopToBaseline);
masterLegend.location := newBaseLPoint;
masterLegend.GetBoxRight;
SELF.Resize(newExtent);
LPtMinusLPt(newExtent.topLeft, oldExtent.topLeft, deltaLPt);
SELF.legendLayoutBox.OffsetLayoutBoxBy(deltaLPt, FALSE);
{its manipulee already ok}
IF NOT equalLRect(oldExtent, newExtent) THEN
SELF.view.panel.OnAllPadsDo(InvalOldAndNew);
SELF.TabGrabbed; {update page-status-dialog report panel}
{$IFC fTrace}EP;{$ENDC}
END;
{$S DlgInit}
END;
METHODS OF TPageStatusDialog;
{$S DlgAlloc}
FUNCTION TPageStatusDialog.CREATE(object: TObject; heap: THeap; itsPanel: TPanel): TPageStatusDialog;
CONST
{$IFC libraryVersion <= 20}
spcAdjustment = -1;
{$ELSEC}
{ S P R I N G }
spcAdjustment = -1;
{$ENDC}
VAR cluster:
TCluster;
aNumberString: S255;
inputFrame:
TInputFrame;
button:
TButton;
promptLoc:
LPoint;
inputLoc:
LPoint;
borders:
Rect;
checkbox:
TCheckbox;
newImage:
TDialogImage;
typeStyle:
TTypeStyle;
labelOffset:
Point;
legend:
TLegend;
boxSpacing:
INTEGER;
itsID:
S255;
itsLocation:
LPoint;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TPageStatusDialog(TDialog.CREATE(object, heap, 'PAGE', itsPanel.view));
SELF.currentHeading := NIL;
MakeTypeStyle(famModern, size12Pitch, [], typeStyle);
SetPt(labelOffset, 6, 0);
cluster := SELF.NewCluster(phOddEven);
checkbox := cluster.NewCheckbox(phOddOnly, stdBoxWidth - 3, stdBoxHeight - 2,
TRUE, labelOffset, typeStyle, FALSE);
checkbox := cluster.NewAlignedCheckbox(phEvenOnly, FALSE);
checkbox := cluster.NewAlignedCheckbox(phOddOrEven, TRUE);
SELF.oddEvenCluster := cluster;
SetRect(borders, -18, -2, 18, 2);
inputFrame := SELF.NewInputFrame(phMinPage, typeStyle, stdFrmeOffset, stdInputTypeStyle, 6,
borders, FALSE, FALSE);
LIntToStr(2, @aNumberString);
inputFrame.SupplantContents(aNumberString);
SELF.minPageFrame := inputFrame;
inputFrame := SELF.NewInputFrame(phMaxPage, typeStyle, stdFrmeOffset, stdInputTypeStyle, 6,
borders, FALSE, FALSE);
inputFrame.SupplantContents('------');
SELF.maxPageFrame := inputFrame;
cluster := SELF.NewCluster(phAlignment);
checkbox := cluster.NewCheckbox(phTopLeft, stdBoxWidth - 3, stdBoxHeight - 2, TRUE,
labelOffset, typeStyle, FALSE);
checkbox := cluster.NewAlignedCheckbox(phTopCenter, TRUE);
checkbox := cluster.NewAlignedCheckbox(phTopRight, FALSE);
checkbox := cluster.NewCheckbox(phBotLeft, stdBoxWidth - 3, stdBoxHeight - 2, TRUE,
labelOffset, typeStyle, FALSE); {for second row}
checkbox := cluster.NewAlignedCheckbox(phBotCenter, FALSE);
checkbox := cluster.NewAlignedCheckbox(phBotRight, FALSE);
SELF.alignCluster := cluster;
button := SELF.NewButton(phLaunchHeading, stdButtonMetrics, NIL, NoCmdNumber);
SELF.AddOKButton(noCmdNumber);
MakeTypeStyle(famModern, size10Pitch, [bold], typeStyle);
legend := SELF.NewLegend(phPageMargins, typeStyle);
MakeTypeStyle(famModern, size12Pitch, [bold], typeStyle);
cluster := SELF.NewCluster(phUnits);
SELF.unitsCluster := cluster;
checkbox := cluster.NewCheckbox(phInches, stdBoxWidth - 3, stdBoxHeight - 2, TRUE,
labelOffset, typeStyle, TRUE);
checkbox := cluster.NewAlignedCheckbox(phCentimeters, FALSE);
MakeTypeStyle(famModern, size15Pitch, [], typeStyle);
legend := SELF.AddStdLegend('0.25 0.50 0.75 1.00 1.25
96, 140, typeStyle);
SELF.marginTitle := legend;
1.50
1.75
2.00
2.25
2.50',
Field('maxPageFrame: TInputFrame');
Field('alignCluster: TCluster');
Field('unitsCluster: TCluster');
Field('marginTitle: TLegend');
Field('leftCluster: TCluster');
Field('topCluster: TCluster');
Field('rightCluster: TCluster');
Field('bottomCluster: TCluster');
Field('');
END;
{$ENDC}
{$S HdgMarg}
PROCEDURE TPageStatusDialog.ButtonPushed(button: TButton);
VAR heading:
THeading;
cluster:
TCluster;
hitBoxID:
INTEGER;
theS255:
S255;
inputFrame:
TInputFrame;
minPage:
LONGINT;
maxPage:
LONGINT;
pane:
TPane;
pageDesignWindow:
TPageDesignWindow;
plannerView:
TPlannerView;
offset:
LPoint;
layoutBox:
TLayoutBox;
pageAlignment: TPageAlignment;
checkbox:
TCheckbox;
oddOnly:
BOOLEAN;
evenOnly:
BOOLEAN;
newMargins:
LRect;
panel:
TPanel;
inches:
BOOLEAN;
plannerPanel:
TPanel;
editLegendSelection: TEditLegendSelection;
noSelection:
TSelection;
FUNCTION Margin(cluster: TCluster; baseID: INTEGER; vhs: vhSelect): INTEGER;
VAR hitBox: TCheckbox;
boxOrd: INTEGER;
BEGIN
hitBox := cluster.hiLitBox;
IF hitBox = NIL THEN
boxOrd := 1
ELSE
boxOrd := hitBox.idNumber - baseID + 1;
IF inches THEN
Margin := (pageDesignWindow.hostView.res.vh[vhs] * boxOrd) DIV 4
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
pageDesignWindow := TPageDesignWindow(SELF.view.panel.window);
plannerView := TPlannerView(pageDesignWindow.layoutPanel.view);
IF button.idNumber = phLaunchHeading THEN {launch a heading AND a corresponding new layout box}
BEGIN
offset := zeroLPt; {default in case no ...}
cluster := SELF.alignCluster;
IF cluster.hiLitBox = NIL THEN
cluster.SelectBox(TCheckbox(cluster.ObjectWithIDNumber(phTopCenter)));
{bulletproofing?}
80, 30);
0, 30);
-80, 30);
80, -30);
0, -30);
-80, -30);
pageDesignWindow.hostView.printManager.headings.InsLast(heading);
heading.AdjustForPage(0, TRUE);
heading.LocateOnPage(TRUE);
SELF.currentHeading := heading;
layoutBox := plannerView.NewLayoutBox(heading);
IF layoutBox <> NIL THEN
BEGIN
plannerPanel := plannerView.panel;
plannerView.rootDialog.AddImage(layoutBox);
plannerPanel.BeginSelection;
editLegendSelection := TEditLegendSelection(plannerPanel.selection.FreedAndReplacedBy(
TEditLegendSelection.CREATE(NIL, SELF.Heap,
TLgHdngLayoutBox(layoutBox).legendLayoutBox, zeroLPt)));
editLegendSelection.coSelection.Become(
editLegendSelection.textDialogImage.textImage.text.SelectAll(
editLegendSelection.textDialogImage.textImage));
plannerPanel.InvalLRect(layoutBox.extentLRect);
plannerView.currentLayoutBox := layoutBox;
END;
TDialogView(SELF.view).AbandonThatButton; {turn off highlighting}
PopFocus;
currentWindow.PerformCommand(TCommand.CREATE(NIL, SELF.Heap, uCmdLaunchHeading, plannerView,
FALSE, revealAll));
END
ELSE
IF button.idNumber = phInstallMargins THEN
BEGIN
inches := SELF.unitsCluster.hilitBox.idNumber = phInches;
newMargins.left := Margin(SELF.leftCluster, 100, h);
newMargins.top := Margin(SELF.topCluster, 200, v);
newMargins.right := Margin(SELF.rightCluster, 300, h);
newMargins.bottom := Margin(SELF.bottomCluster, 400, v);
pageDesignWindow.hostView.printManager.ChangeMargins(newMargins);
TDialogView(SELF.view).AbandonThatButton; {turn off highlighting}
plannerView.panel.InvalLRect(plannerView.extentLRect);
{redraw layout panel with chgd margins}
currentWindow.PerformCommand(TCommand.CREATE(NIL, SELF.Heap, uCmdInstallMargins, plannerView,
FALSE, revealNone));
END
ELSE
{ok button}
BEGIN
panel := plannerView.panel;
panel.window.CommitLast;
noSelection := panel.undoSelection.FreedAndReplacedBy(panel.view.NoSelection);
panel.selection.Deselect;
SUPERSELF.ButtonPushed(button);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S HdgMarg}
PROCEDURE TPageStatusDialog.InspectHeadingParms(VAR oddOnly, evenOnly: BOOLEAN;
VAR pageAlignment: TPageAlignment; VAR minPage, maxPage: LONGINT);
VAR heading:
THeading;
newPageAlignment:
TPageAlignment;
theS255:
S255;
checkbox:
TCheckbox;
cState:
TConvResult;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
checkbox := SELF.oddEvenCluster.hiLitBox;
IF checkbox = NIL THEN
BEGIN
oddOnly := FALSE;
evenOnly := FALSE;
END
ELSE
BEGIN
oddOnly := (checkbox.idNumber = phOddOnly);
evenOnly := (checkbox.idNumber = phEvenOnly);
END;
checkbox := SELF.alignCluster.hiLitBox;
IF checkbox = NIL THEN
pageAlignment := aTopCenter
ELSE
CASE checkbox.idNumber OF
phTopLeft:
pageAlignment := aTopLeft;
phTopCenter:
pageAlignment := aTopCenter;
phTopRight:
pageAlignment := aTopRight;
phBotLeft:
pageAlignment := aBottomLeft;
phBotCenter:
pageAlignment := aBottomCenter;
phBotRight:
pageAlignment := aBottomRight;
END;
SELF.maxPageFrame.GetContents(theS255);
StrToLInt(@theS255, maxPage, cState);
IF (cState <> cvValid) OR (maxPage <= 0) THEN
BEGIN
maxPage := MAXLINT;
SELF.maxPageFrame.SupplantContents('------');
END;
SELF.minPageFrame.GetContents(theS255);
StrToLInt(@theS255, minPage, cState);
IF (cState <> cvValid) OR (minPage > maxPage) THEN
BEGIN
minPage := 1;
SELF.minPageFrame.SupplantContents('1');
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S HdgMarg}
PROCEDURE TPageStatusDialog.SetHeadingParms(oddOnly, evenOnly: BOOLEAN;
pageAlignment: TPageAlignment; minPage, maxPage: LONGINT);
VAR heading:
THeading;
newPageAlignment:
TPageAlignment;
theS255:
S255;
checkbox:
TCheckbox;
targetID:
INTEGER;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF oddOnly THEN
targetID := phOddOnly
ELSE
IF evenOnly THEN
targetID := phEvenOnly
ELSE
targetID := phOddOrEven;
SELF.oddEvenCluster.SelectBox(TCheckbox(SELF.oddEvenCluster.ObjectWithIDNumber(targetID)));
CASE pageAlignment OF
aTopLeft:
targetID
aTopCenter:
targetID
aTopRight:
targetID
aBottomLeft:
targetID
aBottomCenter: targetID
aBottomRight:
targetID
END;
:=
:=
:=
:=
:=
:=
phTopLeft;
phTopCenter;
phTopRight;
phBotLeft;
phBotCenter;
phBotRight;
SELF.alignCluster.SelectBox(TCheckbox(SELF.alignCluster.ObjectWithIDNumber(targetID)));
IntToStr(minPage, @theS255);
SELF.minPageFrame.SupplantContents(theS255);
{$S DlgInit}
END;
UNIT UDraw;
{Copyright 1983, 1984, Apple Computer, Inc.}
{changed 05/01 1503 Changes to allow people to use Clascal on the Workshop}
{$Setc IsIntrinsic := TRUE }
{$IFC IsIntrinsic}
INTRINSIC;
{$ENDC}
INTERFACE
USES
{$U UnitStd
} UnitStd,
{Client should not USE UnitStd}
{$U UnitHz
} UnitHz,
{Client should not USE UnitHz and MUST NOT USE Storage}
{$U libtk/UObject} UObject,
{Client must USE UObject}
{$U -#BOOT-SysCall} SysCall,
{Client may USE SysCall}
{$IFC LibraryVersion > 10}
{$U LIBPL/PaslibCall} PaslibCall,
{$U LIBPL/PPasLibc } PPasLibC,
{$ENDC}
{$IFC LibraryVersion <= 20}
{$U FontMgr
} FontMgr,
{Client should USE UFont instead of FontMgr before QuickDraw}
{$ENDC}
{$U QuickDraw
} QuickDraw,
{Client must USE QuickDraw (unless we provide a type-stub for it)}
{$IFC LibraryVersion > 20}
{$U FontMgr
} FontMgr,
{Client should USE UFont instead of FontMgr after QuickDraw}
{$ENDC}
{$U WM.Events
} Events,
{$U WM.Folders } Folders,
{$U FilerComm
} FilerComm;
{$SETC fDbgDraw
{$SETC fRngDraw
{$SETC fSymDraw
:= fDbgOK}
:= fDbgOK}
:= fSymOK}
{$SETC fDebugMethods := fDbgDraw} {if VAR also true, trace entries and/or exits}
CONST
{there should be at most 10 families and they should be in consecutive order; otherwise
the command number constants in UABC should be changed}
famSystem
=
0;
famMin
famModern
famClassic
famMax
=
=
=
=
{there should be at
the command
sizeMin
=
size20Pitch
=
size15Pitch
=
size12Pitch
=
size10Pitch
=
size12Point
=
size14Point
=
size18Point
=
size24Point
=
sizeMax
=
1;
1;
2;
2;
25;
{Ruler Icons}
{fontIDs below this line are to be used only in special cases, there is no guarantee that these
will print properly}
fIDSysPatterns =
2;
{System Patterns, ie. LisaDraw}
fIDSysCursors
=
3;
{System Cursors}
fIDLT20Graphics =
23;
{LisaTerminal 20 Pitch VT100 graphics}
fIDLT12Graphics =
17;
{LisaTerminal 12 Pitch VT100 graphics}
fIDLT20Text
=
27;
{LisaTerminal 20 Pitch VT100 text}
fIDLT12Text
=
26;
{LisaTerminal 12 Pitch VT100 text}
fIDDeskIcons
=
22;
{Desktop Icon font}
fIDWM
fIDCalculator
fIDIconName
fIDMarker
fIDLisaGuide
=
=
=
=
=
1;
18;
21;
20;
24;
TYPE
TFontIDArray = ARRAY[famMin..famMax, sizeMin..sizeMax] OF INTEGER;
TScaler =
RECORD
{scale-definition}
numerator:
point; {numerator.h DIV denominator.h is the scale factor in horiz direction}
denominator:
point; {numerator.v DIV denominator.v is the scale factor in the vert. direction}
END;
TRectCoords = ARRAY[FALSE..TRUE] OF Point; {TRectCoords(aRect)[FALSE] = aRect.topLeft; [TRUE] = botRight}
LPoint =
RECORD
CASE INTEGER OF
0: (v, h: LONGINT);
1: (vh: ARRAY [VHSelect] OF LONGINT)
END;
LRect =
RECORD
CASE INTEGER OF
0: (top, left, bottom, right: LONGINT);
1: (topLeft, botRight: LPoint)
END;
CASE BOOLEAN OF
FALSE: (fontNum:
TRUE:
(fontFamily:
fontSize:
END;
INTEGER);
Byte;
Byte)
TTypeStyle =
RECORD
{$IFC LibraryVersion <= 20}
onFaces:
TSeteface;
{$ELSEC}
onFaces:
Style;
{$ENDC}
font:
TFontRecord;
END;
TArea = SUBCLASS OF TObject
{Variables}
innerRect:
outerRect:
parentBranch:
Rect;
Rect;
TBranchArea;
{Creation/Destruction}
FUNCTION TArea.CREATE(object: TObject; heap: THeap; itsRect: Rect): TArea; ABSTRACT;
{Attributes}
FUNCTION TArea.ChildWithPt(pt: Point; childList: TList; VAR nearestPt: Point): TArea;
PROCEDURE TArea.GetBorder(VAR border: Rect); DEFAULT;
{Return the deltas of the border bars, etc. (outer=inner+border)}
{windows, bands, panes: 1 all around;
panels: 1 on left/top, scroll bars on right/bottom}
PROCEDURE TArea.GetMinExtent(VAR minExtent: Point; windowIsResizingIt: BOOLEAN); ABSTRACT;
PROCEDURE TArea.SetOuterRect(newOuterRect: Rect);
PROCEDURE TArea.SetInnerRect(newInnerRect: Rect);
{Display}
PROCEDURE TArea.Erase;
{Other methods assume grafPort, origin, & clipping were preset by Focus}
{Buttoning}
FUNCTION TArea.DownAt(mousePt: Point): BOOLEAN; ABSTRACT;
{Resizing}
PROCEDURE TArea.ResizeInside(newInnerRect: Rect); ABSTRACT;
PROCEDURE TArea.ResizeOutside(newOuterRect: Rect); ABSTRACT;
END;
TPad = SUBCLASS OF TArea
{Variables}
port:
viewedLRect:
visLRect:
availLRect:
scrollOffset:
origin:
cdOffset:
clippedRect:
GrafPtr;
LRect;
LRect;
LRect;
LPoint;
Point;
LPoint;
rect;
padRes:
viewedRes:
Point;
Point;
scaled:
scaleFactor:
BOOLEAN;
TScaler;
zoomFactor:
TScaler;
{Creation/Destruction}
FUNCTION TPad.CREATE(object: TObject; heap: THeap; itsInnerRect: Rect; itsViewedLRect: LRect;
itsPadRes, itsViewRes: Point;
itsPort: GrafPtr): TPad;
PROCEDURE TPad.Redefine(itsInnerRect: Rect; itsViewedLRect: LRect;
itsPadRes, itsViewRes: Point;
itsZoomFactor: TScaler; itsPort: GrafPtr);
{Coordinate
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
{Coordinate
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
{Scrolling}
PROCEDURE TPad.OffsetBy(deltaLPt: LPoint);
{offset viewedLRect -- no effect on display}
PROCEDURE TPad.SetScrollOffset(VAR newOffset: LPoint);
{recalculates the origin and cdOffset fields; does not change arg}
{Display}
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
{Drawing}
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
VHSelect;
BOOLEAN;
TResizability;
TArea;
TArea;
{Creation/Destruction}
FUNCTION TBranchArea.CREATE(object: TObject; heap: THeap; vhs: VHSelect; hasElderFirst: BOOLEAN;
whoCanResizeIt: TResizability;
itsElderChild, itsYoungerChild: TArea): TBranchArea;
{Attributes}
PROCEDURE TBranchArea.GetMinExtent(VAR minExtent: Point; windowIsResizingIt: BOOLEAN); OVERRIDE;
FUNCTION TBranchArea.OtherChild(child: TArea): TArea;
PROCEDURE TBranchArea.ReplaceChild(child, newChild: TArea);
FUNCTION TBranchArea.TopLeftChild: TArea;
{Resizing}
PROCEDURE TBranchArea.ResizeOutside(newOuterRect: Rect); OVERRIDE;
PROCEDURE TBranchArea.Redivide(newCd: INTEGER);
END;
VAR
amPrinting:
BOOLEAN;
zeroPt:
zeroRect:
hugeRect:
Point;
Rect;
Rect;
{(0,0)}
{(0,0)-(0,0)}
{(0,0)-(MAXINT/2,MAXINT/2)}
zeroLPt:
zeroLRect:
hugeLRect:
LPoint;
LRect;
LRect;
{(0,0)}
{(0,0)-(0,0)}
{(0,0)-(MAXLINT/2,MAXLINT/2)}
orthogonal:
highPen:
lPatWhite:
lPatBlack:
lPatGray:
lPatLtGray:
lPatDkGray:
LPattern;
LPattern;
LPattern;
LPattern;
LPattern;
{Maps
{Maps
{Maps
{Maps
{Maps
focusStack:
focusStkPtr:
focusArea:
focusRgn:
padRgn:
altVisRgn:
useAltVisRgn:
thePad:
noPad:
crashPad:
TPad;
TPad;
to
to
to
to
to
QuickDraw
QuickDraw
QuickDraw
QuickDraw
QuickDraw
pattern
pattern
pattern
pattern
pattern
white}
black}
gray}
ltGray}
dkGray}
screenRes:
Point;
sysTypeStyle:
printerPseudoPort:
GrafPtr;
cArea:
cPad:
cBranchArea:
TClass;
TClass;
TClass;
FUNCTION
FUNCTION
{
p3 := Point(FPtPlusPt(p1, p2));
{ F stands for FUNCTION }
FUNCTION
FUNCTION
FUNCTION
FUNCTION
FUNCTION
{ FPtMinusPt(botRight-topLeft) }
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
FUNCTION
PROCEDURE
PROCEDURE
FUNCTION
FUNCTION
PROCEDURE
FUNCTION
FUNCTION
PROCEDURE
FUNCTION
PROCEDURE
FUNCTION
{Drawing text}
PROCEDURE DrawLText(textBuf: Ptr; startByte, numBytes: INTEGER);
{Drawing lines, rectangles, and ovals}
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
MoveToL(h, v:
MoveL(dh, dv:
LineToL(h, v:
LineL(dh, dv:
LONGINT);
LONGINT);
LONGINT);
LONGINT);
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
FrameLRect(r: LRect);
PaintLRect(r: LRect);
EraseLRect(r: LRect);
InvrtLRect(r: LRect);
FillLRect(r: LRect; lPat: LPattern);
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
FrameLOval(r: LRect);
PaintLOval(r: LRect);
EraseLOval(r: LRect);
InvrtLOval(r: LRect);
FillLOval(r: LRect; lPat: LPattern);
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
FUNCTION
32768;
SetPort(deskPort);
wmIsInitialized := TRUE;
END
ELSE
BEGIN
{move WriteLns to alternate screen}
MoveConsole(error, alscreen);
{$IFC fDbgDraw}
IF error > 0 THEN
ABCBreak('MoveConsole error', error);
{$ENDC}
{ set work directory to boot volume for FMOpen}
Get_Working_Dir(error, workDir);
{$IFC fDbgDraw}
IF error > 0 THEN
ABCBreak('Get_Working_Dir error', error);
{$ENDC}
{$IFC LibraryVersion < 30}
bootPort := OSBootVol(error);
{$IFC fDbgDraw}
IF error > 0 THEN
ABCBreak('OSBootVol error', error);
{$ENDC}
Get_Config_Name(error, bootPort, bootVol);
{$IFC fDbgDraw}
IF error > 0 THEN
ABCBreak('Get_Config_Name error', error);
{$ENDC}
{$ELSEC}
OSBootVol(error, bootVol);
{$IFC fDbgDraw}
IF error > 0 THEN
ABCBreak('OSBootVol error', error);
{$ENDC}
{$ENDC}
bootDir := CONCAT('-', bootVol);
Set_Working_Dir(error, bootDir);
{$IFC fDbgDraw}
IF error > 0 THEN
ABCBreak('Set_Working_Dir to boot vol error', error);
{$ENDC}
FMOpen(error);
{$IFC fDbgDraw}
{$ENDC}
FReason;
noDiskSpace;
noMemory;
badData;
internalError;
{$S SgABCini}
PROCEDURE InitErrorAbort(error: INTEGER);
BEGIN
IF error > 0 THEN
BEGIN
{$IFC fDbgDraw}
ABCbreak('InitErrorAbort', error);
{$ENDC}
IF onDesktop THEN
TellFiler(error, initFailed, FilerReason(error), NIL);
HALT;
END
ELSE
IF wmIsInitialized THEN
IF Abort THEN
BEGIN
IF onDesktop THEN
TellFiler(error, initFailed, aUserAbort, NIL);
HALT;
END;
END;
{$S SgDRWres}
{$S SgDRWres}
PROCEDURE Reduce(VAR numerator, denominator: INTEGER);
{reduce fraction to lowest terms}
VAR factor: INTEGER;
maxFactor: INTEGER; {also makes cosmetics}
smallerNumerator:
INTEGER;
smallerDenominator: INTEGER;
BEGIN {very crude at the moment}
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
maxFactor := MIN(numerator, denominator);
FOR factor := maxFactor DOWNTO 2 DO
BEGIN
smallerNumerator := numerator DIV factor;
smallerDenominator := denominator DIV factor;
IF (factor * smallerNumerator = numerator) AND (factor * smallerDenominator = denominator) THEN
BEGIN
numerator := smallerNumerator;
denominator := smallerDenominator;
END;
END;
END;
{$S SgDRWres}
FUNCTION FPtPlusPt(operand1, operand2: Point): LONGINT;
VAR result: Point;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
{$S SgABCdat}
PROCEDURE PtDivInt(operand1: Point; operand2: INTEGER; VAR result: Point);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
result.h := operand1.h DIV operand2;
result.v := operand1.v DIV operand2;
END;
{$IFC LibraryVersion <= 20}
FUNCTION EqualPt(operand1, operand2: Point): BOOLEAN;
BEGIN
EqualPt := (operand1.h = operand2.h) AND (operand1.v = operand2.v);
END;
{$ENDC}
{$S SgDRWres}
PROCEDURE RectPlusRect(operand1, operand2: Rect; VAR result: Rect);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
result.left := operand1.left + operand2.left;
result.top := operand1.top + operand2.top;
result.right := operand1.right + operand2.right;
result.bottom := operand1.bottom + operand2.bottom;
END;
{$S SgDRWres}
PROCEDURE RectMinusRect(operand1, operand2: Rect; VAR result: Rect);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
result.left := operand1.left - operand2.left;
result.top := operand1.top - operand2.top;
result.right := operand1.right - operand2.right;
result.bottom := operand1.bottom - operand2.bottom;
END;
{$IFC LibraryVersion <= 20}
{$S SgDRWres}
FUNCTION EqualRect(rectA, rectB: Rect): BOOLEAN;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
RectHasPt := (dstRect.left <= pt.h) AND (pt.h <= dstRect.right) AND
(dstRect.top <= pt.v) AND (pt.v <= dstRect.bottom);
END;
{$S SgDRWres}
PROCEDURE RectHavePt(dstRect: Rect; VAR pt: Point);
BEGIN {if dstRect is negative size, left/top is forced}
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
pt.h := Max(dstRect.left, Min(dstRect.right, pt.h));
pt.v := Max(dstRect.top, Min(dstRect.bottom, pt.v));
END;
{$S SgDRWres}
PROCEDURE RectifyRect(VAR dstRect: Rect);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
Pt2Rect(dstRect.topLeft, dstRect.botRight, dstRect);
END;
{$S SgDRWres}
FUNCTION RectIsVisible(rectInPort: Rect): BOOLEAN;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
RectIsVisible := RectInRgn(rectInPort, focusRgn);
END;
{$S SgABCdbg}
PROCEDURE PointToStr(pt: Point; str: TPstring);
VAR s: S255;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
IntToStr(pt.h, str);
IntToStr(pt.v, @s);
str^ := CONCAT('(', str^, ',', s, ')');
END;
{$S SgABCdbg}
PROCEDURE RectToStr(r: Rect; str: TPstring);
VAR s: S255;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
PointToStr(r.topLeft, str);
PointToStr(r.botRight, @s);
str^ := CONCAT('[', str^, ',', s, ']');
END;
{$S SgDRWres}
{$S SgDRWres}
PROCEDURE LPtPlusLPt(operand1, operand2: LPoint; VAR result: LPoint);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
result.h := operand1.h + operand2.h;
result.v := operand1.v + operand2.v;
END;
{$S SgDRWres}
PROCEDURE LPtMinusLPt(operand1, operand2: LPoint; VAR result: LPoint);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
result.h := operand1.h - operand2.h;
result.v := operand1.v - operand2.v;
END;
{$S SgABCdat}
PROCEDURE LPtMulInt(operand1: LPoint; operand2: INTEGER; VAR result: LPoint);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
result.h := operand1.h * operand2;
result.v := operand1.v * operand2;
END;
{$S SgABCdat}
PROCEDURE LPtDivInt(operand1: LPoint; operand2: INTEGER; VAR result: LPoint);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
result.h := LIntDivInt(operand1.h, operand2);
result.v := LIntDivInt(operand1.v, operand2);
END;
{$S SgDRWres}
FUNCTION EqualLPt(operand1, operand2: LPoint): BOOLEAN;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
EqualLPt := (operand1.h = operand2.h) AND (operand1.v = operand2.v);
END;
{$S SgDRWres}
PROCEDURE LRectPlusLRect(operand1, operand2: LRect; VAR result: LRect);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
result.left := operand1.left + operand2.left;
result.top := operand1.top + operand2.top;
result.right := operand1.right + operand2.right;
result.bottom := operand1.bottom + operand2.bottom;
END;
{$S SgDRWres}
PROCEDURE LRectMinusLRect(operand1, operand2: LRect; VAR result: LRect);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
result.left := operand1.left - operand2.left;
result.top := operand1.top - operand2.top;
result.right := operand1.right - operand2.right;
result.bottom := operand1.bottom - operand2.bottom;
END;
{$S SgDRWres}
FUNCTION EqualLRect(rectA, rectB: LRect): BOOLEAN;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
EqualLRect := (rectA.left=rectB.left) AND (rectA.top=rectB.top) AND
(rectA.right=rectB.right) AND (rectA.bottom=rectB.bottom);
END;
{$S SgDRWres}
FUNCTION EmptyLRect(r: LRect): BOOLEAN;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
WITH r DO
EmptyLRect := (left >= right) OR (top >= bottom);
END;
{$S SgDRWres}
PROCEDURE AlignLRect(VAR destLRect: LRect; srcLRect: LRect; vhs: VHSelect);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
destLRect.topLeft.vh[vhs] := srcLRect.topLeft.vh[vhs];
destLRect.botRight.vh[vhs] := srcLRect.botRight.vh[vhs];
END;
{$S SgDRWres}
FUNCTION LengthLRect(r: LRect; vhs: VHSelect): LONGINT;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
LengthLRect := r.botRight.vh[vhs] - r.topLeft.vh[vhs];
END;
{$S SgDRWres}
FUNCTION LRectsNest(outer, inner: LRect): BOOLEAN;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
LRectsNest := LRectHasLPt(outer, inner.topLeft) AND LRectHasLPt(outer, inner.botRight);
END;
{$S SgDRWres}
FUNCTION LRectHasLPt(destLRect: LRect; pt: LPoint): BOOLEAN;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
LRectHasLPt := (destLRect.left <= pt.h) AND (pt.h <= destLRect.right) AND
(destLRect.top <= pt.v) AND (pt.v <= destLRect.bottom);
END;
{$S SgDRWres}
PROCEDURE LRectHaveLPt(destLRect: LRect; VAR pt: LPoint);
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
LPointToStr(r.topLeft, str);
LPointToStr(r.botRight, @s);
str^ := CONCAT('[', str^, ',', s, ']');
END;
{$S SgDRWres}
{$S SgDRWres}
PROCEDURE SetLPt(VAR destPt: LPoint; itsH, itsV: LONGINT);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
WITH destPt DO
BEGIN
h := itsH;
v := itsV;
END;
END;
{$S SgDRWres}
PROCEDURE SetLRect(VAR dstRect: LRect; itsLeft, itsTop, itsRight, itsBottom: LONGINT);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
WITH dstRect DO
BEGIN
left := itsLeft;
top := itsTop;
right := itsRight;
bottom := itsBottom;
END;
END;
{$S SgDRWres}
PROCEDURE OffsetLRect(VAR dstRect: LRect; dh, dv: LONGINT);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
WITH dstRect DO
BEGIN
left := left + dh;
top := top + dv;
right := right + dh;
bottom := bottom + dv;
END;
END;
{$S SgDRWres}
PROCEDURE InsetLRect(VAR dstRect: LRect; dh, dv: LONGINT);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
WITH dstRect DO
BEGIN
left := left + dh;
top := top + dv;
right := right - dh;
bottom := bottom - dv;
IF (left >= right) OR (top >= bottom) THEN
BEGIN
left := 0;
top := 0;
right := 0;
bottom := 0;
END;
END;
END;
{$S SgABCres}
FUNCTION SectLRect(srcRectA, srcRectB: LRect; VAR dstRect: LRect): BOOLEAN;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
WITH dstRect DO
BEGIN
left := Max(srcRectA.left, srcRectB.left);
top := Max(srcRectA.top, srcRectB.top);
right := Min(srcRectA.right, srcRectB.right);
bottom := Min(srcRectA.bottom, srcRectB.bottom);
IF (left >= right) OR (top >= bottom) THEN
BEGIN
SectLRect := FALSE;
left := 0;
top := 0;
right := 0;
bottom := 0;
END
ELSE
SectLRect := TRUE;
END;
END;
{$S SgDRWres}
PROCEDURE UnionLRect(srcRectA, srcRectB: LRect; VAR dstRect: LRect);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
WITH dstRect DO
BEGIN
left := Min(srcRectA.left, srcRectB.left);
top := Min(srcRectA.top, srcRectB.top);
right := Max(srcRectA.right, srcRectB.right);
bottom := Max(srcRectA.bottom, srcRectB.bottom);
END;
END;
{$S SgDRWres}
FUNCTION LPtInLRect(pt: LPoint; r: LRect): BOOLEAN;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
LPtInLRect := (r.left <= pt.h) AND (pt.h < r.right) AND
(r.top <= pt.v) AND (pt.v < r.bottom);
END;
{$S SgABCdat}
FUNCTION IsSmallPt(srcPt: LPoint): BOOLEAN;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
IsSmallPt := (ABS(srcPt.h) < MAXINT) AND (ABS(srcPt.v) < MAXINT);
END;
{$S SgABCdat}
FUNCTION IsSmallRect(srcRect: LRect): BOOLEAN;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
IsSmallRect := IsSmallPt(srcRect.topLeft) AND IsSmallPt(srcRect.botRight);
END;
{Drawing Text}
{$S SgABCdat}
PROCEDURE DrawLText(textBuf: Ptr; startByte, numBytes: INTEGER);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
{$IFC libraryVersion > 20}
IF thePad.scaled THEN
thePad.DrawLText(textBuf, startByte, numBytes)
ELSE
DrawText(QDPtr(textBuf), startByte, numBytes);
{$ELSEC}
DrawText(WordPtr(textBuf), startByte, numBytes);
{$ENDC}
END;
{Drawing lines, rectangles, and ovals}
{$S SgDRWres}
PROCEDURE MoveToL(h, v: LONGINT);
VAR lPtInView: LPoint;
ptInPort:
Point;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
SetLPt(lPtInView, h, v);
thePad.LPtToPt(lPtInView, ptInPort);
MoveTo(ptInPort.h, ptInPort.v);
END;
{$S SgDRWres}
PROCEDURE MoveL(dh, dv: LONGINT);
VAR lPtInView: LPoint;
ptInPort:
Point;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
SetLPt(lPtInView, dh, dv);
thePad.LDistToDist(lPtInView, ptInPort);
Move(ptInPort.h, ptInPort.v);
END;
{$S SgDRWres}
PROCEDURE LineToL(h, v: LONGINT);
VAR lPtInView:
LPoint;
BEGIN
END;
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
SetLPt(lPtInView, h, v);
thePad.DrawLLine(lPtInView);
{$S SgDRWres}
PROCEDURE LineL(dh, dv: LONGINT);
VAR lPtInView: LPoint;
ptInPort:
Point;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
SetLPt(lPtInView, dh, dv);
thePad.LDistToDist(lPtInView, ptInPort);
Line(ptInPort.h, ptInPort.v);
END;
{$S SgDRWres}
PROCEDURE FrameLRect(r: LRect);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
thePad.DrawLRect(frame, r);
END;
{$S SgDRWres}
PROCEDURE PaintLRect(r: LRect);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
thePad.DrawLRect(paint, r);
END;
{$S SgDRWres}
PROCEDURE EraseLRect(r: LRect);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
thePad.DrawLRect(erase, r);
END;
{$S SgDRWres}
END;
thePad.DrawLOval(erase, r);
{$S SgDRWres}
PROCEDURE InvrtLOval(r: LRect);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
thePad.DrawLOval(invert, r);
END;
{$S SgDRWres}
PROCEDURE FillLOval(r: LRect; lPat: LPattern);
VAR pat:
Pattern;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
IF amPrinting THEN
thePad.LPatToPat(lPat, pat);
{$IFC LibraryVersion <= 20}
thePat := Pattern(lPat);
{$ELSEC}
thePort^.fillPat := Pattern(lPat);
{$ENDC}
thePad.DrawLOval(fill, r);
END;
PROCEDURE FrameLRRect(r: LRect; ovalWidth, ovalHeight: INTEGER);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
thePad.DrawLRRect(frame, r, ovalWidth, ovalHeight);
END;
PROCEDURE PaintLRRect(r: LRect; ovalWidth, ovalHeight: INTEGER);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
thePad.DrawLRRect(paint, r, ovalWidth, ovalHeight);
END;
PROCEDURE EraseLRRect(r: LRect; ovalWidth, ovalHeight: INTEGER);
BEGIN
END;
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
thePad.DrawLRRect(erase, r, ovalWidth, ovalHeight);
END;
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
thePad.DrawLArc(erase, r, startAngle, arcAngle);
Rect;
Rect;
Point;
INTEGER;
BOOLEAN;
BOOLEAN;
BOOLEAN;
EventRecord;
GrafPtr;
PROCEDURE InitXorFrame;
BEGIN
fTab := TRUE;
fHScroll := TRUE;
fVScroll := TRUE;
{ set up scroll bar and tab widths }
{ the +1 's are to account for enlarging rFrame by one pixel }
IF sbWidth > 0 THEN
sbWidth := sbWidth+1
ELSE
fVScroll := FALSE;
IF sbHeight > 0 THEN
sbHeight := sbHeight+1
ELSE
fHScroll := FALSE;
IF tabHeight > 0 THEN
tabHeight := tabHeight+1
ELSE
fTab := FALSE;
{ setup rFrame - the outer rect for XORing
rFrame := outerRect;
InsetRect(rFrame, -1, -1);
limitRect.topLeft := minPt;
limitRect.botRight := maxPt;
IF fTab THEN innerTop := rFrame.top+tabHeight
ELSE innerTop := rFrame.top;
{ Setup the pen }
PenNormal;
PenPat(gray);
PenMode(notPatXor);
END;
PROCEDURE XorFrame;
BEGIN
rFrame.botRight := newPt;
FrameRect(rFrame);
IF fTab THEN
BEGIN
MoveTo(rFrame.left, innerTop);
LineTo(rFrame.right-1, innerTop);
END;
IF fHScroll THEN
BEGIN
MoveTo(rFrame.left, newPt.v-sbHeight);
LineTo(rFrame.right-1, newPt.v-sbHeight);
END;
IF fVScroll THEN
BEGIN
MoveTo(newPt.h - sbWidth, innerTop);
LineTo(newPt.h - sbWidth, rFrame.bottom-1);
END;
END;
PROCEDURE DoDragFrame;
VAR nxtPt:
Point;
BEGIN
nxtPt := Point(FPtPlusPt(newPt, Point(FPtMinusPt(mousePt, oldMousePt))));
RectHavePt(limitRect, nxtPt);
mousePt := Point(FPtPlusPt(Point(FPtMinusPt(nxtPt, newPt)), oldMousePt));
IF NOT EqualPt(nxtPt, newPt) THEN
BEGIN
XorFrame; { hide old }
newPt := nxtPt;
XorFrame; { draw new }
END;
END;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
InitXorFrame; { sets rFrame }
newPt := rFrame.botRight;
XorFrame;
oldMousePt := mousePt;
WHILE StillDown DO
BEGIN
GetMouse(mousePt);
DoDragFrame;
oldMousePt := mousePt;
END;
IF PeekEvent(event) AND (event.what = buttonUp) THEN
BEGIN
GetPort(savePort);
SetPort(event.who);
mousePt := event.where;
LocalToGlobal(mousePt);
SetPort(savePort);
GlobalToLocal(mousePt);
END
ELSE
GetMouse(mousePt);
DoDragFrame;
XorFrame;
{ hide last }
newPt.h := newPt.h - 1;
newPt.v := newPt.v - 1;
END; { ResizeFeedback }
{$S SgABCres}
PROCEDURE PopFocus;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
SetEmptyRgn(padRgn); {To save memory space}
focusArea := focusStack[focusStkPtr];
thePad := NIL;
IF focusArea <> NIL THEN
focusArea.Focus;
focusStkPtr := focusStkPtr - 1;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
PROCEDURE PushFocus;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
focusStkPtr := focusStkPtr + 1;
focusStack[focusStkPtr] := focusArea;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgDRWres}
PROCEDURE MakeTypeStyle{(itsFamily: INTEGER; itsSize: INTEGER; itsFaces: TSetEFace/Style;
VAR typeStyle: TTypeStyle)};
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
WITH typeStyle DO
BEGIN
onFaces := itsFaces;
font.fontFamily := itsFamily;
font.fontSize := itsSize;
END;
{$IFC fTrace}EP;{$ENDC}
END;
FUNCTION QDFontNumber{(typeStyle: TTypeStyle): INTEGER};
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
WITH typeStyle.font DO
IF fontFamily = famSystem THEN
QDFontNumber := fIDSystem
ELSE
QDFontNumber := fontID[fontFamily, fontSize];
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE SetQDTypeStyle{(typeStyle: TTypeStyle)};
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
TextFont(QDFontNumber(typeStyle));
TextFace(typeStyle.onFaces);
{$IFC fTrace}EP;{$ENDC}
END;
METHODS OF TArea;
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE TArea.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
Field('innerRect: Rect');
Field('outerRect: Rect');
Field('parentBranch: TBranchArea');
END;
{$S SgDRWres}
{$ENDC}
FUNCTION TArea.ChildWithPt(pt: Point; childList: TList; VAR nearestPt: Point): TArea;
VAR foundArea: TArea;
s:
TListScanner;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
RectHavePt(SELF.innerRect, pt);
s := childList.scanner;
WHILE s.Scan(foundArea) DO
IF RectHasPt(foundArea.outerRect, pt) THEN
s.Done;
IF foundArea = NIL THEN
BEGIN
{$IFC fDbgDraw}
ABCbreak('ChildWithPt found no area', 0);
{$ENDC}
foundArea := TArea(childList.First);
END;
RectHavePt(foundArea.innerRect, pt);
nearestPt := pt;
ChildWithPt := foundArea;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TArea.Erase;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
FillRect(SELF.innerRect, white);
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TArea.Frame;
VAR innerRect:
Rect;
borderRect:
Rect;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
innerRect := SELF.innerRect;
IF NOT RectsNest(innerRect, focusRgn^^.rgnBBox) THEN
BEGIN
PenNormal;
PenSize(1, 1);
borderRect := innerRect;
InsetRect(borderRect, -1, -1);
FrameRect(borderRect);
END;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TArea.GetBorder(VAR border: Rect);
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
SetRect(border, -1, -1, 1, 1);
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TArea.SetInnerRect(newInnerRect: Rect);
VAR border: Rect;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.innerRect := newInnerRect;
SELF.GetBorder(border);
{$H-} RectPlusRect(SELF.innerRect, border, SELF.outerRect); {$H+}
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TArea.SetOuterRect(newOuterRect: Rect);
VAR border: Rect;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.outerRect := newOuterRect;
SELF.GetBorder(border);
{$H-} RectMinusRect(SELF.outerRect, border, SELF.innerRect); {$H+}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCini}
BEGIN
fontID[famModern,
fontID[famModern,
fontID[famModern,
fontID[famModern,
fontID[famModern,
fontID[famModern,
fontID[famModern,
size20Pitch]
size15Pitch]
size10Pitch]
size12Pitch]
size12Point]
size14Point]
size18Point]
:=
:=
:=
:=
:=
:=
:=
fID20Pitch;
fID15Pitch;
fIDm10Pitch;
fIDm12Pitch;
fIDm12Point;
fIDm14Point;
fIDm18Point;
size20Pitch]
size15Pitch]
size10Pitch]
size12Pitch]
size12Point]
size14Point]
size18Point]
size24Point]
:=
:=
:=
:=
:=
:=
:=
:=
fID20Pitch;
fID15Pitch;
fIDc10Pitch;
fIDc12Pitch;
fIDc12Point;
fIDc14Point;
fIDc18Point;
fIDc24Point;
TpLongint;
BEGIN
IF dataHandle <> NIL THEN
IF dataSize <> 4 THEN
BEGIN
pData := TpLongint(ORD(dataHandle^));
END;
CASE kind OF
picForeColor:
ForeColor(pData^);
picBackColor:
BackColor(pData^);
END;
END;
WITH thePort^ DO
BEGIN
oldProcsPtr := grafprocs;
IF oldProcsPtr = NIL THEN
BEGIN
SetStdProcs(TKProcs);
grafprocs := @TKProcs;
END;
WITH grafprocs^ DO
BEGIN
oldTextProc := textProc;
oldCommentProc := commentProc;
IF amPrinting THEN
BEGIN
textProc := @TKStdText;
commentProc := @TKStdComment;
END;
END;
END;
SELF.LRectToRect(r, rectInPort);
DrawPicture(pic, rectInPort);
WITH thePort^ DO
BEGIN
IF oldProcsPtr <> NIL THEN
WITH grafprocs^ DO
BEGIN
textProcs := oldTextProc;
commentProc := oldCommentProc;
END;
grafProcs := oldProcsPtr;
END;
END;
{$ENDC}
PROCEDURE TPad.DrawLRect(verb: GrafVerb; r: LRect);
VAR rectInPort: Rect;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
SELF.LRectToRect(r, rectInPort);
StdRect(verb, rectInPort);
END;
PROCEDURE TPad.DrawLRRect(verb: GrafVerb; r: LRect; ovalWidth, ovalHeight: INTEGER);
SetOrigin(0, 0);
RectRgn(padRgn, SELF.clippedRect);
IF useAltVisRgn THEN
visRgn := altVisRgn
{Instigated by TWindow.StashPicture or TClipboard.Publicize}
ELSE
visRgn := thePort^.visRgn;
SectRgn(padRgn, visRgn, padRgn);
origin := SELF.origin;
WITH origin DO {+LSR+}
BEGIN
SetOrigin(h, v);
OffsetRgn(padRgn, h, v);
END;
SetClip(padRgn);
focusRgn := padRgn;
focusArea := SELF;
thePad := SELF;
WITH SELF DO
{$H-} BEGIN
SELF.RectToLRect(focusRgn^^.rgnBBox, visLRect);
IF SectLRect(viewedLRect, visLRect, visLRect) THEN
BEGIN END;
{$H+} END;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TPad.InvalLRect(r: LRect);
VAR rectInPort: Rect;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
SELF.LRectToRect(r, rectInPort);
SELF.InvalRect(rectInPort);
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TPad.InvalRect(r: Rect);
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SectRect(r, focusRgn^^.rgnBBox, r) THEN
InvalRect(r);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgDRWres}
PROCEDURE TPad.LDistToDist(lDistInView: LPoint; VAR distInPort: Point);
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF SELF.scaled THEN
WITH SELF.scaleFactor DO
{$H-} BEGIN
distInPort.h := LIntOvrInt(LIntMulInt(lDistInView.h, numerator.h), denominator.h);
distInPort.v := LIntOvrInt(LIntMulInt(lDistInView.v, numerator.v), denominator.v);
{$H+} END
ELSE
BEGIN
distInPort.h := lDistInView.h;
distInPort.v := lDistInView.v;
END;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TPad.LPatToPat(lPatInView: LPattern; VAR patInPort: Pattern);
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF amPrinting THEN
RotatePattern(@lPatInView, @patInPort, SELF.cdOffset.h, SELF.cdOffset.v)
ELSE
patInPort := Pattern(lPatInView); {+LSR+}
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TPad.LPtToPt(lPtInView: LPoint; VAR ptInPort: Point);
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
LRectHaveLPt(SELF.availLRect, lPtInView);
WITH SELF, cdOffset, scaleFactor DO {+LSR+}
IF scaled THEN
{$H-} BEGIN
ptInPort.h := LIntOvrInt(LIntMulInt(lPtInView.h, numerator.h), denominator.h) - h;
ptInPort.v := LIntOvrInt(LIntMulInt(lPtInView.v, numerator.v), denominator.v) - v;
{$H+} END
ELSE
BEGIN
ptInPort.h := lPtInView.h - h;
ptInPort.v := lPtInView.v - v;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
PROCEDURE TPad.LRectToRect(lRectInView: LRect; VAR rectInPort: Rect);
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
LRectHaveLPt(SELF.availLRect, lRectInView.topLeft);
LRectHaveLPt(SELF.availLRect, lRectInView.botRight);
WITH SELF, cdOffset, scaleFactor DO {+LSR+}
IF scaled THEN
{$H-} BEGIN
rectInPort.left := LIntOvrInt(LIntMulInt(lRectInView.left, numerator.h), denominator.h) - h;
rectInPort.top := LIntOvrInt(LIntMulInt(lRectInView.top, numerator.v), denominator.v) - v;
rectInPort.right := LIntOvrInt(LIntMulInt(lRectInView.right, numerator.h), denominator.h) - h;
rectInPort.bottom := LIntOvrInt(LIntMulInt(lRectInView.bottom, numerator.v), denominator.v)
- v;
{$H+} END
ELSE
BEGIN
rectInPort.left := lRectInView.left - h;
rectInPort.top := lRectInView.top - v;
rectInPort.right := lRectInView.right - h;
rectInPort.bottom := lRectInView.bottom - v;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgDRWres}
PROCEDURE TPad.OffsetBy(deltaLPt: LPoint);
VAR vhs:
VHSelect;
newOffset: LPoint;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
WITH SELF, deltaLPt DO
{$H-} BEGIN
OffsetLRect(viewedLRect, h, v);
OffsetLRect(availLRect, h, v);
{$H+} END;
FOR vhs := v TO h DO {$H-} {+LSR+}
WITH SELF, scaleFactor DO
newOffset.vh[vhs] := LIntOvrInt(LIntMulInt(viewedLRect.topLeft.vh[vhs],
numerator.vh[vhs]),
denominator.vh[vhs]) - innerRect.topLeft.vh[vhs];
{$H+}
SELF.SetScrollOffset(newOffset);
{$IFC fTrace}EP;{$ENDC}
END;
WrObj(SELF, 1, '');
writeln;
ABCbreak('Error in TPad.PtToLPt', 0);
END;
{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCres}
PROCEDURE TPad.RectToLRect(rectInPort: Rect; VAR lRectInView: LRect);
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
WITH SELF, cdOffset, scaleFactor DO {+LSR+}
IF scaled THEN
{$H-} BEGIN
lRectInView.left :=
LIntOvrInt(LIntMulInt(rectInPort.left + h, denominator.h), numerator.h);
lRectInView.top :=
LIntOvrInt(LIntMulInt(rectInPort.top + v, denominator.v), numerator.v);
lRectInView.right :=
LIntOvrInt(LIntMulInt(rectInPort.right + h, denominator.h), numerator.h);
lRectInView.bottom :=
LIntOvrInt(LIntMulInt(rectInPort.bottom + v, denominator.v), numerator.v);
{$H+} END
ELSE
BEGIN
lRectInView.left := rectInPort.left + h;
lRectInView.top := rectInPort.top + v;
lRectInView.right := rectInPort.right + h;
lRectInView.bottom := rectInPort.bottom + v;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgDRWres}
PROCEDURE TPad.SetPen(pen: PenState);
VAR lPat:
LPattern;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF amPrinting THEN
BEGIN
noPad.PatToLPat(pen.pnPat, lPat);
SELF.LPatToPat(lPat, pen.pnPat);
END;
SetPenState(pen);
{$IFC fTrace}EP;{$ENDC}
END;
:=
:=
:=
:=
:=
LPattern(white);
LPattern(black);
LPattern(gray);
LPattern(ltGray);
LPattern(dkGray);
amPrinting := FALSE;
END;
{$S SgDRWres}
METHODS OF TBranchArea;
{$S SgABCcld}
FUNCTION TBranchArea.CREATE(object: TObject; heap: THeap; vhs: VHSelect; hasElderFirst: BOOLEAN;
whoCanResizeIt: TResizability;
itsElderChild, itsYoungerChild: TArea): TBranchArea;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TBranchArea(object);
WITH SELF DO
BEGIN
outerRect := itsElderChild.outerRect;
parentBranch := itsElderChild.parentBranch;
arrangement := vhs;
elderFirst := hasElderFirst;
resizability := whoCanResizeIt;
elderChild := itsElderChild;
youngerChild := itsYoungerChild;
END;
itsElderChild.parentBranch := SELF;
itsYoungerChild.parentBranch := SELF;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgDRWres}
{$IFC fDebugMethods}
{$S SgABCdbg}
PROCEDURE TBranchArea.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
TArea.Fields(Field);
Field('arrangement: Byte');
Field('elderFirst: BOOLEAN');
Field('resizability: Byte');
Field('elderChild: TArea');
Field('youngerChild: TArea');
END;
{$S SgDRWres}
{$ENDC}
{$S SgABCcld}
PROCEDURE TBranchArea.GetMinExtent(VAR minExtent: Point; windowIsResizingIt: BOOLEAN);
VAR elderMinSize:
Point;
youngerMinSize: Point;
vhs:
VHSelect;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
vhs := SELF.arrangement;
SELF.elderChild.GetMinExtent(elderMinSize, TRUE);
SELF.youngerChild.GetMinExtent(youngerMinSize, TRUE);
IF windowIsResizingIt AND NOT (windowCanResizeIt IN SELF.resizability) THEN
youngerMinSize.vh[vhs] := LengthRect(SELF.youngerChild.outerRect, vhs);
minExtent.vh[vhs] := elderMinSize.vh[vhs] + youngerMinSize.vh[vhs];
vhs := orthogonal[vhs];
minExtent.vh[vhs] := Max(elderMinSize.vh[vhs], youngerMinSize.vh[vhs]);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgDRWres}
{$S SgABCcld}
FUNCTION TBranchArea.OtherChild(child: TArea): TArea;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.elderChild = child THEN
OtherChild := SELF.youngerChild
ELSE
{$IFC fDbgDraw}
IF SELF.youngerChild = child THEN
OtherChild := SELF.elderChild
ELSE
ABCBreak('This panel branch does not have a child that is', ORD(child));
{$ELSEC}
OtherChild := SELF.elderChild;
{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgDRWres}
{$S SgABCcld}
PROCEDURE TBranchArea.Redivide(newCd: INTEGER);
VAR elderRect:
Rect;
youngerRect:
Rect;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
elderRect := SELF.elderChild.outerRect;
youngerRect := SELF.youngerChild.outerRect;
TRectCoords(elderRect)[SELF.elderFirst].vh[SELF.arrangement] := newCd;
TRectCoords(youngerRect)[NOT SELF.elderFirst].vh[SELF.arrangement] := newCd;
SELF.elderChild.ResizeOutside(elderRect);
SELF.youngerChild.ResizeOutside(youngerRect);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgDRWres}
{$S SgABCcld}
PROCEDURE TBranchArea.ReplaceChild(child, newChild: TArea);
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.elderChild = child THEN
SELF.elderChild := newChild
ELSE
{$IFC fDbgDraw}
IF SELF.youngerChild = child THEN
SELF.youngerChild := newChild
ELSE
ABCBreak('This panel branch does not have a child that is', ORD(child));
{$ELSEC}
SELF.youngerChild := newChild;
{$ENDC}
newChild.parentBranch := SELF;
IF child.parentBranch = SELF THEN
child.parentBranch := NIL;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgDRWres}
{$S SgABCcld}
PROCEDURE TBranchArea.ResizeOutside(newOuterRect: Rect);
VAR formerRect:
Rect;
elderChild:
TArea;
youngerChild:
TArea;
elderRect:
Rect;
youngerRect:
Rect;
vhs:
VHSelect;
eldFirst:
BOOLEAN;
minExtents:
ARRAY [FALSE..TRUE] OF Point;
newCd:
INTEGER;
deltaRect:
Rect;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
formerRect := SELF.outerRect;
elderChild := SELF.elderChild;
youngerChild := SELF.youngerChild;
elderRect := elderChild.outerRect;
youngerRect := youngerChild.outerRect;
vhs := SELF.arrangement;
eldFirst := SELF.elderFirst;
IF windowCanResizeIt IN SELF.resizability THEN
BEGIN
{both children resize proportionally}
MapRect(elderRect, formerRect, newOuterRect);
MapRect(youngerRect, formerRect, newOuterRect);
elderChild.GetMinExtent(minExtents[NOT eldFirst], TRUE);
youngerChild.GetMinExtent(minExtents[eldFirst], TRUE);
IF (minExtents[FALSE].vh[vhs] + minExtents[TRUE].vh[vhs]) < LengthRect(newOuterRect, vhs) THEN
BEGIN
{It is possible to satisfy both min constraints, so do so}
END
ELSE
BEGIN
{only elder child resizes in my direction}
RectMinusRect(newOuterRect, formerRect, deltaRect);
RectPlusRect(elderRect, deltaRect, elderRect);
TRectCoords(deltaRect)[NOT eldFirst].vh[vhs] := TRectCoords(deltaRect)[eldFirst].vh[vhs];
RectPlusRect(youngerRect, deltaRect, youngerRect);
END;
youngerChild.ResizeOutside(youngerRect);
elderChild.ResizeOutside(elderRect);
SELF.outerRect := newOuterRect;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgDRWres}
{$S SgABCcld}
FUNCTION TBranchArea.TopLeftChild: TArea;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
IF SELF.elderFirst THEN
TopLeftChild := SELF.elderChild
ELSE
TopLeftChild := SELF.youngerChild;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgDRWres}
{$S SgABCini}
END;
{$S SgDRWres}
{$S SgABCini}
UNIT UObject;
{Copyright 1983, 1984, Apple Computer, Inc.}
{Implementation is in UOBJECT2-3-4}
{$SETC IsIntrinsic := TRUE}
{$IFC IsIntrinsic}
INTRINSIC;
{$ENDC}
{$SETC ErrsToFile := TRUE }
{$IFC ErrsToFile}
{$E+}
{****************************************}
{$ENDC}
{$E ERRS.TEXT}
{****************************************}
{NOTE: The implementation of class TObject is quite obscure because this is actually system-type code}
{Segments: SgABCini(tialize), SgABCdat(a structures), SgABCdbg}
{
=========================================== SPECIFICALLY IN UObject =========================================
----------CLASSES------
TObject
TCollection
TList
TArray
recordBytes
TString
TFile
TScanner
path scanners
collection position increment scanDone atEnd
TListScanner
TArrayScanner
TStringScanner
TFileScanner
error actual
accesses refnum
$ = in UObject
@ = in UHuge
* in UDb
# in UMac
$ TObject
$
$
$
$
$
TCollection
@
@
@
*
*
*
*
TList
TLinkList
THugeList
TArray
THugeArray
TString
TFile
TDb
TDbFile
TRsFile
TDbRsFile
#
$
$
$
$
$
TMcRsFile
TScanner
@
@
@
*
*
*
*
*
@ TLink
element next
INTERFACE
{$SETC LibraryVersion := 30 } { 10 = 1.0 libraries; 13 = 1.3 libraries; 20 = Pepsi,
HWInt;
:= fDbgOK}
:= fDbgOK}
:= fSymOK}
prcsLdsn
prcsDsBytes
= 1;
= 15000;
MaxBreaks
= 10;
outputRMargin
erInternal
= 85;
= 4200;
MAXLINT
= $7FFFFFFF;
TYPE
{Aliases needed to compile QuickDraw}
Ptr = ^LONGINT;
ProcPtr = Ptr;
Handle = ^Ptr;
{Aliases for commonly used types}
S8 = STRING[8];
S255 = STRING[255];
TFilePath = S255;
Byte = -128..127;
TPString = ^S255;
TpINTEGER = ^INTEGER;
TpLONGINT = ^LONGINT;
TAuthorName = STRING[32];
TClassName = STRING[8];
TClassWorld = RECORD
infRecs:
TArray
classes:
TArray
authors:
TArray
aliases:
TArray
END;
TEnumAccesses = (fRead, fWrite, fAppend, fPrivate); {not allowing global_refnum at this time}
TObject; ABSTRACT;
{SELF becomes obj and former SELF is freed}
{its class pointer}
{clones just the object, not its dependents}
{clones the object and its known dependents}
{frees just the object, not its dependents}
{frees the object and its known dependents}
{which heap it is in}
{number of bytes occupied in that heap}
{reads the object & its known dependents}
{writes the object & its known dependents}
{Debugging}
{$IFC fDebugMethods}
PROCEDURE TObject.Fields(PROCEDURE Field(nameAndType: S255)); DEFAULT; {See end of file for comment}
PROCEDURE TObject.Debug(numLevels: INTEGER; memberTypeStr: S255); DEFAULT;
{writes an object down to numLevels:
numLevels=0 => write only class;
numLevels=1 => write class, non-Object fields, and class of Object fields
etc.}
{$ENDC}
{Version Conversion}
PROCEDURE TObject.Convert(fromVersion: Byte); {Override it to finish conversion from an old version}
FUNCTION TObject.JoinClass(newClass: TClass): TObject;
{Called for you by version conversion}
END;
TCollecHeader =
classPtr:
size:
dynStart:
RECORD
TClass;
LONGINT;
INTEGER;
holeStart:
holeSize:
holeStd:
END;
INTEGER;
INTEGER;
INTEGER;
TFastString = RECORD
{only access ch[i] when hole is at end & TString is not subclassed}
header:
TCollecHeader;
ch:
PACKED ARRAY[1..32740] OF CHAR;
END;
TPFastString = ^TFastString;
THFastString = ^TPFastString;
TArrayHeader = RECORD
classPtr:
TClass;
size:
LONGINT;
dynStart:
INTEGER;
holeStart:
INTEGER;
holeSize:
INTEGER;
holeStd:
INTEGER;
recordBytes:
INTEGER;
END;
LONGINT;
INTEGER;
INTEGER;
INTEGER;
INTEGER;
{The field "size" is a LONGINT for the benefit of huge collections like remote data bases.
It is always in the INTEGER range for non-subclassed TLists, TArrays, and TStrings.
The field "dynStart" is an offset from Handle(collection)^ and tells where the dynamic part
of the data is stored, if any. This convention allows subclasses to add fields.
When editing a collection, there may be an unused "hole" somewhere in the storage block. The
fields "holeStart" and "holeSize" specify (in member-sized units) the starting index of the
hole and the length of the hole. When holeSize is zero, there is no hole. If members are
added when there is no hole, the storage block is expanded to allow for at least another
"holeStd" members.
CREATE has an argument that lets the initial collection have a hole at the end, so that
Ins- methods can be called to initialize the collection without any storage allocation.
StartEdit sets holeStd to its argument, which forces subsequent edit methods to leave intact
any hole they might form. StopEdit squeezes out the hole and sets holeStd to zero, which
forces subsequent edit methods that get called with no hole to squeeze out any hole they may form.
Thus, every StartEdit that has a nonzero argument should be terminated by a call on StopEdit to
save space.}
{Creation and Destruction}
FUNCTION TCollection.CREATE(object: TObject; heap: THeap; initialSlack: INTEGER): TCollection;
FUNCTION TCollection.Clone(heap: THeap): TObject; OVERRIDE;
{Attributes}
FUNCTION TCollection.MemberBytes: INTEGER; ABSTRACT;
FUNCTION TCollection.Equals(otherCollection: TCollection): BOOLEAN;
{Slack control}
PROCEDURE TCollection.StartEdit(withSlack: INTEGER);
PROCEDURE TCollection.StopEdit;
{Generic Inserts}
PROCEDURE TCollection.InsManyAt(i: LONGINT; otherCollection: TCollection; index, howMany: LONGINT);
PROCEDURE TCollection.InsNullsAt(i, howMany: LONGINT);
(* BEGIN CONCEPTUAL METHODS (parameter types differ in subclasses; sometimes extra parameters required)
{Enumerate members}
PROCEDURE TCollection.Each(PROCEDURE DoToMember(member: "TMember")); CONCEPTUAL;
FUNCTION TCollection.Pos(after: LONGINT; member: "TMember"): LONGINT; CONCEPTUAL;
FUNCTION TCollection.Scanner: TScanner; CONCEPTUAL;
{c.ScannerFrom(-MaxLInt, scanForward)}
FUNCTION TCollection.ScannerFrom(firstToScan: LONGINT; scanDirection: TScanDirection)
: TScanner; CONCEPTUAL;
{Inspect members}
FUNCTION TCollection.At(i: LONGINT): "TMember"; CONCEPTUAL;
FUNCTION TCollection.First: "TMember"; CONCEPTUAL;
FUNCTION TCollection.Last: "TMember"; CONCEPTUAL;
FUNCTION TCollection.ManyAt(i, howMany: LONGINT): "TCollection"; CONCEPTUAL;
{Insert members}
PROCEDURE TCollection.InsAt(i: LONGINT; member: "TMember"); CONCEPTUAL;
PROCEDURE TCollection.InsFirst(member: "TMember"); CONCEPTUAL;
PROCEDURE TCollection.InsLast(member: "TMember"); CONCEPTUAL;
{Delete members}
PROCEDURE TCollection.DelAll; CONCEPTUAL;
PROCEDURE TCollection.DelAt(i: LONGINT); CONCEPTUAL;
PROCEDURE TCollection.DelFirst; CONCEPTUAL;
PROCEDURE TCollection.DelLast; CONCEPTUAL;
PROCEDURE TCollection.DelManyAt(i, howMany: LONGINT); CONCEPTUAL;
{Change member}
PROCEDURE TCollection.PutAt(i: LONGINT; member: "TMember"); CONCEPTUAL;
END CONCEPTUAL METHODS *)
{Private methods -- to be called by subclasses only!!!}
{$IFC fRngObject}
PROCEDURE TCollection.CheckIndex(index: LONGINT);
{$ENDC}
FUNCTION TCollection.AddrMember(i: LONGINT): LONGINT;
{The address is only valid momentarily}
PROCEDURE TCollection.CopyMembers(dstAddr, startIndex, howMany: LONGINT);
PROCEDURE TCollection.EditAt(atIndex: LONGINT; deltaMembers: INTEGER);
{Transfers no data}
PROCEDURE TCollection.ResizeColl(membersPlusHole: INTEGER);
{Resizes at end, no fields changed}
PROCEDURE TCollection.ShiftColl(afterSrcIndex, afterDstIndex, howMany: INTEGER); {No fields changed}
END;
TList = SUBCLASS OF TCollection
{Variables}
{Creation and Destruction}
FUNCTION TList.CREATE(object: TObject; heap: THeap; initialSlack: INTEGER): TList;
FUNCTION TList.Clone(heap: THeap): TObject; OVERRIDE;
PROCEDURE TList.Free; OVERRIDE;
{Debugging}
{$IFC fDebugMethods}
PROCEDURE TList.Debug(numLevels: INTEGER; memberTypeStr: S255); OVERRIDE;
{ numLevels=0
print just class of list;
1
also print size of list;
2
also print compacted list of member classes
>=3
print class, size, and call Debug(numLevels-1) on members
}
PROCEDURE TList.DebugMembers;
{$ENDC}
{Attributes}
FUNCTION TList.MemberBytes: INTEGER; OVERRIDE;
{Enumerate members}
PROCEDURE TList.Each(PROCEDURE DoToObject(object: TObject)); DEFAULT;
FUNCTION TList.Pos(after: LONGINT; object: TObject): LONGINT;
FUNCTION TList.Scanner: TListScanner;
FUNCTION TList.ScannerFrom(firstToScan: LONGINT; scanDirection: TScanDirection)
: TListScanner; DEFAULT;
{Inspect members}
FUNCTION
FUNCTION
FUNCTION
FUNCTION
{Insert members}
PROCEDURE TList.InsAt(i: LONGINT; object: TObject); DEFAULT;
PROCEDURE TList.InsFirst(object: TObject);
PROCEDURE TList.InsLast(object: TObject);
{Delete members}
PROCEDURE TList.DelAll(freeOld: BOOLEAN); DEFAULT;
PROCEDURE TList.DelAt(i: LONGINT; freeOld: BOOLEAN); DEFAULT;
PROCEDURE TList.DelFirst(freeOld: BOOLEAN);
PROCEDURE TList.DelLast(freeOld: BOOLEAN);
PROCEDURE TList.DelManyAt(i, howMany: LONGINT; freeOld: BOOLEAN); DEFAULT;
PROCEDURE TList.DelObject(object: TObject; freeOld: BOOLEAN);
FUNCTION TList.PopLast: TObject;
{Change member}
PROCEDURE TList.PutAt(i: LONGINT; object: TObject; freeOld: BOOLEAN); DEFAULT;
END;
TArray = SUBCLASS OF TCollection
{*** WARNING: The Ptrs below become invalid if the heap compacts!!!}
{Variables}
recordBytes: INTEGER;
{Creation and Destruction}
FUNCTION TArray.CREATE(object: TObject; heap: THeap; initialSlack, bytesPerRecord: INTEGER): TArray;
{Attributes}
FUNCTION TArray.MemberBytes: INTEGER; OVERRIDE;
{Enumerate members}
PROCEDURE TArray.Each(PROCEDURE DoToRecord(pRecord: Ptr)); DEFAULT;
FUNCTION TArray.Pos(after: LONGINT; pRecord: Ptr): LONGINT;
FUNCTION TArray.Scanner: TArrayScanner;
FUNCTION TArray.ScannerFrom(firstToScan: LONGINT; scanDirection: TScanDirection)
: TArrayScanner; DEFAULT;
{Inspect members}
FUNCTION TArray.At(i: LONGINT): Ptr; DEFAULT;
FUNCTION TArray.First: Ptr;
PROCEDURE TArray.GetAt(i: LONGINT; pRecord: Ptr); DEFAULT; {Sort of: pRecord^ := SELF.At(i)^}
FUNCTION TArray.Last: Ptr;
FUNCTION TArray.ManyAt(i, howMany: LONGINT): TArray; DEFAULT;
{Insert members}
PROCEDURE TArray.InsAt(i: LONGINT; pRecord: Ptr); DEFAULT;
PROCEDURE TArray.InsFirst(pRecord: Ptr);
PROCEDURE TArray.InsLast(pRecord: Ptr);
{Delete members}
PROCEDURE TArray.DelAll; DEFAULT;
PROCEDURE TArray.DelAt(i: LONGINT); DEFAULT;
PROCEDURE TArray.DelFirst;
PROCEDURE TArray.DelLast;
PROCEDURE TArray.DelManyAt(i, howMany: LONGINT); DEFAULT;
{Change member}
PROCEDURE TArray.PutAt(i: LONGINT; pRecord: Ptr); DEFAULT;
END;
TString = SUBCLASS OF TCollection
{Variables}
{Creation and Destruction}
FUNCTION TString.CREATE(object: TObject; heap: THeap; initialSlack: INTEGER): TString;
{Attributes}
FUNCTION TString.MemberBytes: INTEGER; OVERRIDE;
{Enumerate members}
PROCEDURE TString.Each(PROCEDURE DoToCharacter(character: CHAR));
FUNCTION TString.Pos(after: LONGINT; character: CHAR): LONGINT;
FUNCTION TString.Scanner: TStringScanner;
FUNCTION TString.ScannerFrom(firstToScan: LONGINT; scanDirection: TScanDirection): TStringScanner;
{Inspect members}
FUNCTION TString.At(i: LONGINT): CHAR;
FUNCTION TString.First: CHAR;
FUNCTION TString.Last: CHAR;
FUNCTION TString.ManyAt(i, howMany: LONGINT): TString;
PROCEDURE TString.ToPStr(pStr: TPString);
PROCEDURE TString.ToPStrAt(i, howMany: LONGINT; pStr: TPString);
{Insert members}
PROCEDURE TString.InsAt(i: LONGINT; character: CHAR);
PROCEDURE TString.InsFirst(character: CHAR);
PROCEDURE TString.InsLast(character: CHAR);
PROCEDURE TString.InsPStrAt(i: LONGINT; pStr: TPString);
{Delete members}
PROCEDURE TString.DelAll;
PROCEDURE TString.DelAt(i: LONGINT);
PROCEDURE TString.DelFirst;
PROCEDURE TString.DelLast;
PROCEDURE TString.DelManyAt(i, howMany: LONGINT);
{Change member}
PROCEDURE TString.PutAt(i: LONGINT; character: CHAR);
{QuickDraw}
PROCEDURE TString.Draw(i: LONGINT; howMany: INTEGER);
FUNCTION TString.Width(i: LONGINT; howMany: INTEGER): INTEGER;
END;
TFile = SUBCLASS OF TCollection
{Variables}
path:
password:
scanners:
TFilePath;
TPassword;
{The current password protecting this file, and used for all
accesses to it; client is responsible for setting this
field after the TFile is created; ignored if
LibraryVersion <= 20}
{Attributes}
FUNCTION TFile.MemberBytes: INTEGER; OVERRIDE;
{Enumerate members}
FUNCTION TFile.Scanner: TFileScanner;
{f.ScannerFrom(0, [fRead, fWrite])}
FUNCTION TFile.ScannerFrom(firstToScan: LONGINT; manip: TAccesses): TFileScanner;
{Catalog}
PROCEDURE TFile.ChangePassword(VAR error: INTEGER; newPassword: TPassword);
{also changes the password field, if successful}
PROCEDURE TFile.Delete(VAR error: INTEGER);
FUNCTION TFile.Exists(VAR error: INTEGER): BOOLEAN;
FUNCTION TFile.WhenModified(VAR error: INTEGER): LONGINT;
PROCEDURE TFile.Rename(VAR error: INTEGER; newFileName: TFilePath);
FUNCTION
END;
TScanner = SUBCLASS OF TObject
{Variables}
collection:
position:
increment:
scanDone:
atEnd:
FUNCTION
{Slack Control}
PROCEDURE TScanner.Allocate(slack: LONGINT); DEFAULT;
PROCEDURE TScanner.Compact; DEFAULT;
{Like collection.StartEdit(slack)}
{Like collection.StopEdit}
{Positioning}
FUNCTION TScanner.Advance(PROCEDURE DoToCurrent(anotherMember: BOOLEAN)): BOOLEAN;
PROCEDURE TScanner.Done; DEFAULT;
{Set scanDone so that Scan will return FALSE}
PROCEDURE TScanner.Reverse; DEFAULT;
{Reverse the scan direction}
PROCEDURE TScanner.Seek(newPosition: LONGINT); DEFAULT; {Forces to legal places}
PROCEDURE TScanner.Skip(deltaPos: LONGINT); DEFAULT;
{Forces to legal places}
(* BEGIN CONCEPTUAL METHODS (parameter types differ in subclasses; sometimes extra parameters required)
{Data Transfer}
FUNCTION TScanner.Obtain: "TMember"; CONCEPTUAL; {Return previous member (redundant right after
Scan)}
FUNCTION TScanner.Scan(VAR member: "TMember"): BOOLEAN; CONCEPTUAL; {Return next & advance past it}
{Editing}
PROCEDURE TScanner.Append(member: "TMember"); CONCEPTUAL;
PROCEDURE TScanner.Delete; CONCEPTUAL;
PROCEDURE TScanner.DeleteRest; CONCEPTUAL;
PROCEDURE TScanner.Replace(member: "TMember"); CONCEPTUAL;
position}
END CONCEPTUAL METHODS *)
END;
TListScanner = SUBCLASS OF TScanner
{Variables}
{Creation and Destruction}
FUNCTION TListScanner.CREATE(object: TObject; itsList: TList; itsInitialPosition: LONGINT;
itsScanDirection: TScanDirection): TListScanner;
PROCEDURE TListScanner.Free; OVERRIDE;
{Traversal}
FUNCTION TListScanner.Obtain: TObject; DEFAULT; {Return previous member (redundant right after Scan)}
FUNCTION TListScanner.Scan(VAR nextObject: TObject): BOOLEAN; DEFAULT;{Return next, advance past it}
{Editing}
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
END;
TArrayScanner = SUBCLASS OF TScanner
{Variables}
{Creation and Destruction}
FUNCTION TArrayScanner.CREATE(object: TObject; itsArray: TArray; itsInitialPosition: LONGINT;
itsScanDirection: TScanDirection): TArrayScanner;
PROCEDURE TArrayScanner.Free; OVERRIDE;
{Traversal}
FUNCTION TArrayScanner.Obtain: Ptr; DEFAULT; {Return previous member (redundant right after Scan)}
FUNCTION TArrayScanner.Scan(VAR pNextRecord: Ptr): BOOLEAN; DEFAULT; {Return next & advance past it}
{Editing}
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
TArrayScanner.Append(pRecord: Ptr); DEFAULT; {Add a new record after position, scan past it}
TArrayScanner.Delete; DEFAULT;
{Delete previous record and adjust position}
TArrayScanner.DeleteRest; DEFAULT;
{Delete all records after position}
TArrayScanner.Replace(pRecord: Ptr); DEFAULT;{Replace previous record and maintain position}
END;
TStringScanner.Append(character: CHAR); DEFAULT; {Add char after position, scan past it}
TStringScanner.Delete; DEFAULT;
{Delete previous char, adjust position}
TStringScanner.DeleteRest; DEFAULT;
{Delete all chars after position}
TStringScanner.Replace(character: CHAR); DEFAULT;{Replace previous char, maintain position}
{Typed Sequential Data Transfer: characters are read/written from left to right regardless of increment}
FUNCTION TStringScanner.ReadArray(heap: THeap; bytesPerRecord: INTEGER): TArray; {reads size first}
FUNCTION TStringScanner.ReadNumber(numBytes: SizeOfNumber): LONGINT; {iff numBytes is even
then signed}
FUNCTION TStringScanner.ReadObject(heap: THeap): TObject;
{tells object to Read(SELF)}
PROCEDURE TStringScanner.WriteArray(a: TArray); {inverse of ReadArray: writes size but not
recordBytes}
PROCEDURE TStringScanner.WriteNumber(value: LONGINT; numBytes: SizeOfNumber);{does not write size}
PROCEDURE TStringScanner.WriteObject(object: TObject); {tells object to Write(SELF)}
PROCEDURE TStringScanner.XferContiguous(whichWay: xReadWrite; collection: TCollection);
{xfers the size and members, non-recursively; xRead appends what it reads}
PROCEDURE TStringScanner.XferFields(whichWay: xReadWrite; object: TObject); {xfers all but the class}
PROCEDURE TStringScanner.XferPString(whichWay: xReadWrite; pStr: TPString); {it better be long enough}
{Untyped Data Transfer: characters are read/written from left to right regardless of increment}
PROCEDURE TStringScanner.XferSequential(whichWay: xReadWrite; pFirst: Ptr; numBytes:
LONGINT); DEFAULT;
PROCEDURE TStringScanner.XferRandom(whichWay: xReadWrite; pFirst: Ptr; numBytes: LONGINT;
mode: TIOMode; offset: LONGINT); DEFAULT;
END;
TFileScanner = SUBCLASS OF TStringScanner
{Variables}
accesses:
refnum:
error:
TAccesses;
INTEGER;
INTEGER;
{Untyped Data Transfer: characters are read/written from left to right regardless of increment}
PROCEDURE TFileScanner.XferSequential(whichWay: xReadWrite; pFirst: Ptr; numBytes: LONGINT); OVERRIDE;
PROCEDURE TFileScanner.XferRandom(whichWay: xReadWrite; pFirst: Ptr; numBytes: LONGINT;
mode: TIOMode; offset: LONGINT); OVERRIDE;
END;
{$IFC compatibleLists}
{Backward compatibility classes}
TDynamicArray = SUBCLASS OF TArray
ch: {UNPACKED} ARRAY [0..16370] OF CHAR;
FUNCTION TDynamicArray.CREATE(object: TObject; heap: THeap; bytesPerRecord: INTEGER;
initialSize: INTEGER): TDynamicArray;
FUNCTION TDynamicArray.NumRecords: INTEGER;
PROCEDURE TDynamicArray.BeSize(newSize: INTEGER);
END;
INTEGER;
THeap;
INTEGER;
BOOLEAN;
onDesktop:
wmIsInitialized:
isInitialized:
amDying:
BOOLEAN;
BOOLEAN;
BOOLEAN;
BOOLEAN;
myWorld:
TClassWorld;
FUNCTION
FUNCTION
PROCEDURE
FUNCTION
PROCEDURE
PROCEDURE
{$IFC compatibleLists}
{Backward compatibility procedures}
FUNCTION
PROCEDURE
PROCEDURE
PROCEDURE
FUNCTION
{$ENDC}
FUNCTION
FUNCTION
{optional}
{$IFC fDbgObject}
PROCEDURE EntDebugger(inputStr, enterReason: S255);
PROCEDURE DumpVar(pVariable: Ptr; nameAndType: S255); {used mainly by TProcess.DumpGlobals}
PROCEDURE WrStr(str: S255);
{ write a string with wrap-around }
PROCEDURE WrLn;
{ goto next line, and output indent }
{$IFC fDebugMethods}
PROCEDURE WrObj(object: TObject; numLevels: INTEGER; memberTypeStr: S255);
{$ENDC}
{$ENDC}
{$IFC fDbgObject OR fDebugMethods}
====================
This function must be defined in every class until the compiler generates this info automatically!
PROCEDURE TWhatever.Fields{(PROCEDURE Field(nameAndType: S255))};
BEGIN {THE FIELDS MUST BE LISTED IN DECLARED ORDER, NONE OMITTED AND NONE ADDED}
{Tell the superclass first (unnecessary if it is TObject)}
SUPERSELF.Fields(Field);
{The following type names are recognized by the parser}
Field('flag: BOOLEAN');
Field('coCode: Byte');
Field('inputChar: CHAR');
Field('version: INTEGER');
Field('width: LONGINT');
Field('viewLPt: LPoint');
Field('boundLRect: LRect');
Field('size: Point');
Field('ptr: Ptr');
Field('boundRect: Rect');
Field('someName: STRING[100]');
{If the last field is a Byte or a BOOLEAN, force padding to a word boundary by...
Field('');
{Every Registered Class name is recognized}
*)
Field('miscObj: TObject');
Field('myPanel: TPanel');
Field('mySel: TMySelection');
Field('appSpecific: TAppSpecific');
{You may report more than one field in a single call to reduce code space}
Field('boundLRect: LRect; size: Point; ptr: Ptr; mySel: TMySelection');
{Unpacked invariant RECORDs are recognized}
Field('info: RECORD version: INTEGER; size: Point END');
{If the record has variants, select among them before calling Field()}
CASE SELF.variant OF
flavor1: Field('RECORD version: INTEGER; size: Point END');
flavor2: Field('RECORD viewLPt: LPoint END');
END;
{Unpacked ARRAYs with literal bounds are recognized}
Field('desc: ARRAY [1..99] OF RECORD version: INTEGER; id: ARRAY [1..2] OF CHAR END');
{Other constructs and type names are NOT recognized; substitute one of the above forms}
{As a last resort, use ARRAY [1..SIZEOF(SELF.fieldName)] OF Byte}
END;
IMPLEMENTATION
{$I LIBTK/UOBJECT2.text}
{$I LIBTK/UOBJECT3.text}
{$I LIBTK/UOBJECT4.text}
(**********
{$I UOBJECT2.text}
{$I UOBJECT3.text}
{$I UOBJECT4.text}
**********)
END.
TRecycleChain = RECORD
classPtr:
TClass;
chainLink: TObject;
END;
TPRecycleChain = ^TRecycleChain;
THRecycleChain = ^TPRecycleChain;
UnsignedByte = 0..255;
TTypeCode = (yBoolean, yHexByte, yByte, yChar, yHexInteger, yInteger, yLongInt, yLongReal,
yLPoint, yLRect, yObject, yPoint, yPtr, yReal, yRect, yString, yArray);
{We can't USE Unit UDRAW because it USES us; these are needed in EXTERNAL decls below for KitBug}
FakePoint = RECORD v, h: INTEGER END;
FakeRect = RECORD top, left, bottom, right: INTEGER END;
FakeLPoint = RECORD v, h: LONGINT END;
FakeLRect = RECORD top, left, bottom, right: LONGINT END;
{$IFC LibraryVersion < 20}
{ The following definitions come from PasLibCall and PPasLibC; if those files change, these
will have to be changed too !!!! }
dsProcCode = (dsResProg, dsSoftPwbtn, dsPrintDev, dsSetGPrefix, dsEnbDisk);
dsProcParam = record
case ProcCode : dsProcCode of
dsResProg : (RProcessId : longint);
dsSoftPwbtn : (SPButton : boolean);
dsPrintDev
: (PrDevice : e_name);
dsSetGPrefix : (errnum : INTEGER;
prefix : pathname);
dsEnbDisk
: (DiskEvent : boolean);
end;
{$ENDC}
{Tallying}
TTally = RECORD
count:
microseconds:
epPC:
END;
INTEGER;
LONGINT;
LONGINT;
END;
TPDTallyArray = ^TDTallyArray;
THTallies = ^TPDTallyArray;
TDSTables = RECORD
header:
TArrayHeader;
records:
TSTableArray;
END;
TPDSTables = ^TDSTables;
THSTables = ^TPDSTables;
TDAuthorArray = RECORD
header:
TArrayHeader;
records:
TAuthorArray;
END;
TPDAuthorArray = ^TDAuthorArray;
THAuthors = ^TPDAuthorArray;
{An alias for a TArray of TA32 (company and author)}
TDAliasArray = RECORD
header:
TArrayHeader;
records:
TAliasArray;
END;
TPDAliasArray = ^TDAliasArray;
THAliases = ^TPDAliasArray;
{An alias for a TArray of TA8 (class alias)}
TIdxArray = ARRAY [1..16000] OF INTEGER;
TDIdxArray = RECORD
header:
TArrayHeader;
records:
TIdxArray;
END;
TPDIdxArray = ^TDIdxArray;
THIdxArray = ^TPDIdxArray;
TWorld = RECORD
hExClasses:
hExSTables:
hExAuthors:
hExAliases:
{hExClasses^^
{hExSTables^^
{hExAuthors^^
{hExAliases^^
THClasses;
THSTables;
THAuthors;
THAliases;
.records[i]
.records[i]
.records[i]
.records[i]
is
is
is
is
the
the
the
the
END;
VAR
hMyClasses:
hMySTables:
hMyAuthors:
hMyAliases:
hMyHashName:
THClasses;
THSTables;
THAuthors;
THAliases;
THIdxArray;
cObject:
TClass;
tallyOverhead:
debugTime:
startTime:
stopTime:
segNames:
LONGINT;
{usual time spent calling and returning from BP, EP, or Tally} *)
LONGINT;
{cumulative time spend in BP and EP since tallying started} *)
LONGINT;
{when tallying started}
LONGINT;
{when tallying last paused}
TArray{[1..127] OF S8};
{We can't USE Unit QuickDraw because we can't use Storage; nor WM without using QuickDraw; nor UDraw, so...}
PROCEDURE InitQDWM; EXTERNAL; {in UDraw}
PROCEDURE DrawText(textBuf: TpINTEGER; firstByte, byteCount: INTEGER); EXTERNAL;
FUNCTION TextWidth(textBuf: TpINTEGER; firstByte, byteCount: INTEGER): INTEGER; EXTERNAL;
PROCEDURE DrawLText(textBuf: TpINTEGER; firstByte, byteCount: INTEGER); EXTERNAL;
{The rest are assembler routines in XFER and ARE declared in the INTERFACE of this unit}
FUNCTION LIntAndLInt(i, j: LONGINT): LONGINT; EXTERNAL;
FUNCTION LIntOrLInt(i, j: LONGINT): LONGINT; EXTERNAL;
FUNCTION LIntXorLInt(i, j: LONGINT): LONGINT; EXTERNAL;
PROCEDURE XferLeft(source, dest: Ptr; nBytes: INTEGER); EXTERNAL;
PROCEDURE XferRight(source, dest: Ptr; nBytes: INTEGER); EXTERNAL;
FUNCTION EqualBytes(source, dest: Ptr; nBytes: INTEGER): BOOLEAN; EXTERNAL;
{The rest are assembler routines in CLASLIB and are NOT declared in the INTERFACE of this unit}
FUNCTION %_GetA5: LONGINT; EXTERNAL;
PROCEDURE %_GoLisabug; EXTERNAL;
{Forward}
{$IFC fDebugMethods}
PROCEDURE WriteDRecord(numLevels: INTEGER; hDRecord: Handle; posInDRecord: INTEGER;
PROCEDURE SupplyFields(PROCEDURE Field(nameAndType: S255))); FORWARD;
{$ENDC}
{ ====================================== COLD UTILITIES ====================================== }
{$S SgCLAcld}
FUNCTION MakeIdxArray(numElements: INTEGER; sparse: BOOLEAN): THIdxArray;
VAR anArray:
TArray;
i:
INTEGER;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
IF sparse THEN
numElements := (((numElements + 6) * 4) DIV 3);
anArray := TArray.CREATE(NIL, mainHeap, numElements, SIZEOF(INTEGER));
anArray.InsNullsAt(1, numElements);
MakeIdxArray := THIdxArray(anArray);
(*****
hArray := THIdxArray(TDynamicArray.CREATE(NIL, mainHeap, SIZEOF(INTEGER), numElements));
FOR i := 1 TO numElements DO
hArray^^.records[i] := 0;
MakeIdxArray := hArray;
*****)
END;
{$S SgCLAcld}
PROCEDURE EachObject(heap: THeap; PROCEDURE DoToObject(object: TObject));
VAR hz:
THz;
{ The heap as a UnitHz type }
mpFirst:
LONGINT;
{ The address of the first master pointer }
mpLast:
LONGINT;
{ The address of the last master pointer }
mpIndex:
LONGINT;
{ An index variable used for stepping through the master pointers }
mp:
LONGINT;
{ the value of the master pointer at mpIndex }
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
hz := THz(heap);
mpFirst := ORD(@hz^.argpPool);
mpLast := mpFirst + 4 * ((hz^.ipPoolMac) - 1);
{Step through each master pointer in heap}
mpIndex := mpFirst;
WHILE mpIndex <= mpLast DO
BEGIN
mp := ORD(Handle(mpIndex)^);
IF NOT (((mp >= mpFirst) AND (mp <= mpLast)) OR (mp = 1)) THEN {not on the free list}
DoToObject(POINTER(ORD(mpIndex))); { Pass it to DoToObject as a TObject, but don't coerce
directly to a TObject because of run-time checking. }
mpIndex := mpIndex + 4;
{ advance to the next master pointer }
END;
END;
{ ====================================== HOT UTILITIES ====================================== }
{$S sHotUtil}
FUNCTION Min(i, j: LONGINT): LONGINT;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
IF i < j THEN
Min := i
ELSE
Min := j;
{$IFC fMaxTrace}EP;{$ENDC}
END;
{$S sHotUtil}
This PROCEDURE accepts a binary LONGINT, decNumber, and returns the equivalent hexadecimal *)
number by means of the output parameter hexNumber. Note that if the equivalent hexadecimal number is *)
of a sufficiently small magnitude that it does not require all of the digits in the hex field to be *)
expressed (e.g. if 8 digits are allocated in the hex field and the hex number if 58A7, which is only *)
4 digits), then the hexadecimal number will be right-justified with leading zeros to pad the field. So, *)
(* for example, 58A7 will be returned as 000058A7 if 8 digits are allocated for hexadecimal numbers via the *)
(* constant hexFieldSize.
To change the number of digits in the hex field, change the constant *)
(* hexFieldSize. *)
{NOTE: many users of LIntToHex pass in a pointer to a variable declared as S8; therefore, it is important
that LIntToHex not return more than 8 digits }
CONST
hexFieldSize = 8;
(* the number of digits which are to appear in a hexadecimal field; leading zeros
*)
(* may be used to pad small hexadecimal numbers (e.g. if hexFieldSize is 8, then the
(* hex number FA9 would appear as 00000FA9) *)
This PROCEDURE accepts a STRING of hexadecimal digits, hexString, and returns a long-INTEGER decimal
equivalent by means of the variable parameter decNumber. Information concerning the acceptability of
the hexadecimal STRING is returned via the variable parameter result.
Note that this PROCEDURE ignores any leading or trailing blanks which may be present in the given
hexString, and the presence of lower-case hexadecimal digits in the hex STRING does not adversely
affect conversion. Also, if the first non-blank character of the STRING is a dollar sign, then that
dollar sign is ignored and not considered during conversion (it is, effectively, deleted from the
STRING).
VAR numDigits:
digit:
i:
digitValue:
hexDigits:
0..255;
CHAR;
INTEGER;
INTEGER;
S16;
*)
*)
*)
*)
*)
*)
*)
*)
BEGIN
(* HexStrToLInt *)
{$IFC fMaxTrace}BP(1);{$ENDC}
(* Delete any trailing blanks *)
TrimBlanks(POINTER(ORD(hexstring)));
{ Remove any leading zeros, except keep at least 1 digit; also, remove any leading $ }
IF Length(hexString^) > 0 THEN
WHILE ((Length(hexString^) > 1) AND (hexString^[1] = '0')) OR (hexString^[1] = '$') DO
Delete(hexString^, 1, 1);
numDigits := Length(hexString^);
decNumber := 0;
IF numDigits = 0 THEN
(* if the given hex STRING is empty... *)
result := cvNoNumber
ELSE
IF Length (hexString^) > 8 THEN (* if can't fit in LONGINT *)
result := cvOverflow
ELSE
result := cvValid;
(* innocent until proven guilty *)
FOR i := 1 TO numDigits DO
BEGIN
digit := hexString^[i];
IF digit IN ['0'..'9'] THEN
digitValue := ORD(digit) - ORD('0')
ELSE
IF digit IN ['A'..'F'] THEN
digitValue := ORD(digit) - ORD('A') + 10
ELSE
IF digit IN ['a'..'f'] THEN
digitValue := ORD(digit) - ORD('a') + 10
ELSE
BEGIN
digitValue := 0;
result := cvBadNumber;
END;
decNumber := decNumber * 16 + digitValue;
END;
{$IFC fMaxTrace}EP;{$ENDC}
END;
(* HexStrToLInt *)
{$S sUtil}
PROCEDURE StrToLInt(str: TPString; VAR decNumber: LONGINT; VAR result: TConvResult);
LABEL
1;
VAR s:
S255;
pos:
INTEGER;
neg:
BOOLEAN;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
result := cvValid;
XferLeft(Ptr(str), Ptr(@s), Length(str^) + 1);
TrimBlanks(@s);
decNumber := 0;
neg := FALSE;
IF s='' THEN
result := cvNoNumber
ELSE IF (s[1]='-') OR (s[1]='+') THEN
BEGIN
neg := s[1] = '-';
Delete(s, 1, 1);
IF s='' THEN
result := cvBadNumber;
END;
pos := 1;
WHILE pos <= Length(s) DO
BEGIN
IF ('0' > s[pos]) OR (s[pos] > '9') THEN {invalid numeric character}
BEGIN
result := cvBadNumber;
GOTO 1;
END;
{check for overflow}
IF pos > 10 THEN {more than 10 digits guarantees an overflow}
BEGIN
result := cvOverflow;
GOTO 1;
END;
IF pos = 10 THEN
IF ORD(s[pos]) > ORD('7') THEN
IF decNumber > 214748363 THEN
BEGIN
result := cvOverflow;
GOTO 1;
END
ELSE
{ okay }
ELSE { 10th digit is 7 or less }
1:
IF neg THEN
decNumber := -decNumber;
{$IFC fMaxTrace}EP;{$ENDC}
END;
{$S sUtil}
PROCEDURE StrToInt(str: TPString; VAR decNumber: INTEGER; VAR result: TConvResult);
VAR l: LONGINT;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fDbgObject}
{$0V+} {make sure we don't screw up}
{$ENDC}
StrToLint(str, l, result);
IF result = cvValid THEN
IF (l < -MAXINT-1) OR (l > MAXINT) THEN
result := cvOverflow
ELSE
decNumber := INTEGER(l);
{$IFC fMaxTrace}EP;{$ENDC}
END;
{$S sUtil}
PROCEDURE TrimBlanks(str: TPString);
LABEL
1, 10;
CONST
tabCh = CHR(9);
VAR i:
INTEGER;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
i := 1;
10:
{$IFC fMaxTrace}EP;{$ENDC}
END;
{$S sUtil}
FUNCTION CharUpperCased(ch: CHAR): CHAR;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
CharUpperCased := ch;
IF 'a' <= ch THEN
IF ch <= 'z' THEN
CharUpperCased := CHR(ORD(ch) - 32);
{$IFC fMaxTrace}EP;{$ENDC}
END;
{$S sUtil}
PROCEDURE StrUpperCase(str: TPString);
VAR i: INTEGER;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
i := Length(str^);
WHILE i > 0 DO
BEGIN
str^[i] := CharUpperCased(str^[i]);
i := i - 1;
END;
{$IFC fMaxTrace}EP;{$ENDC}
END;
{$S sUtil}
PROCEDURE SplitFilePath(VAR fullPath, itsCatalog, itsFilePart: TFilePath);
LABEL
1;
VAR i: INTEGER;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
itsCatalog := '';
itsFilePart := fullPath;
1:
{$IFC fMaxTrace}EP;{$ENDC}
END;
{$S sStartup}
PROCEDURE SetCp(object: TObject; itsClass: TClass);
VAR index: INTEGER;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
Handle(object)^^ := ORD(itsClass);
{Install slice table
index := CiOfCp(TPSliceTable(itsClass));
{Determine its class
IF index < 256 THEN
{If it will fit in a
{$R-}
TPByte(Handle(object)^)^ := index;
{...to speed version
{$IFC fRngObject}{$R+}{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
END;
pointer}
index}
byte, store it...}
conversion (cf ConvertHeap: FindClasses)}
{$S sStartup}
FUNCTION NewDynObject(heap: THeap; itsClass: TClass; dynBytes: INTEGER): TObject;
VAR nBytes: INTEGER;
object: TObject;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
nBytes := SizeOfCp(TPSliceTable(itsClass)) + dynBytes;
object := POINTER(ORD(HAllocate(THz(heap), nBytes)));
{TObject() won't work until after SetCp}
IF ORD(object) = ORD(hNIL) THEN
BEGIN
{$IFC fDbgObject}
WriteLn(CbOfHz(THz(heap)):1, ' bytes in the heap');
{$ENDC}
ABCBreak('NewObject: Heap full, can''t make an object of size', nBytes);
END;
SetCp(object, itsClass);
NewDynObject := object;
{$IFC fMaxTrace}EP;{$ENDC}
END;
{$S sStartup}
FUNCTION NewObject(heap: THeap; itsClass: TClass): TObject;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
NewObject := NewDynObject(heap, itsClass, 0);
{$IFC fMaxTrace}EP;{$ENDC}
END;
{$S sStartup}
PROCEDURE ResizeDynObject(object: TObject; newTotalBytes: INTEGER);
VAR i: INTEGER;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
IF (newTotalBytes < 0) OR (newTotalBytes > (MAXINT-20)) THEN
ABCBreak('New size must lie between 0 and 32K-20, not', newTotalBytes);
ChangeSizeH(THz(object.Heap), TH(object), newTotalBytes);
IF CbDataOfH(THz(object.Heap), TH(object)) < newTotalBytes THEN
ABCBreak('ResizeDynObject: Heap full, size can''t change to', newTotalBytes);
{$IFC fMaxTrace}EP;{$ENDC}
END;
{$IFC compatibileLists}
FUNCTION SubObject(super: TObject; itsClass: TClass): TObject;
BEGIN
ResizeDynObject(super, SizeOfCp(TPSliceTable(itsClass)));
SetCP(super, itsClass);
SubObject := super;
END;
{$ENDC}
{$S sStartup}
FUNCTION NewOrRecycledObject(heap: THeap; itsClass: TClass; VAR chainHead: TObject): TObject;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
IF chainHead = NIL THEN
NewOrRecycledObject := NewObject(heap, itsClass)
ELSE
BEGIN
{$IFC fDbgObject}
IF (chainHead.Class <> itsClass) OR (chainHead.Heap <> heap) THEN
ABCBreak('NewOrRecycledObject: chainHead contains an alien object', ORD(chainHead));
{$ENDC}
NewOrRecycledObject := chainHead;
chainHead := THRecycleChain(chainHead)^^.chainLink;
END;
{$IFC fMaxTrace}EP;{$ENDC}
END;
{$S sStartup}
PROCEDURE RecycleObject(object: TObject; VAR chainHead: TObject);
{$IFC fDbgObject}
VAR chainMember: TObject;
{$ENDC}
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fDbgObject}
IF object.HeapBytes < 8 THEN
ABCBreak('RecycleObject: object is too small for a chainHead link', ORD(object));
chainMember := chainHead;
WHILE chainMember <> NIL DO
BEGIN
IF chainMember = object THEN
ABCBreak('RecycleObject: object freed twice', ORD(object));
chainMember := THRecycleChain(chainMember)^^.chainLink;
END;
{$ENDC}
THRecycleChain(object)^^.chainLink := chainHead;
chainHead := object;
{$IFC fMaxTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE Recreate(object: TObject; oldSize, newSize: INTEGER; newSTP: TPSliceTable);
VAR extraPtr:
TPByte;
hz:
THz;
cb:
INTEGER;
bk:
LONGINT;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
SetCP(object, TClass(newSTP));
{Install the new slice-table pointer}
IF newSize <> oldSize THEN
{Default extra fields to 0/NIL}
BEGIN
hz := HzFromH(TH(object));
cb := CbDataOfH(hz, TH(object));
bk := ORD(Handle(object)^);
IF (cb > oldSize) AND (newSize < oldSize) THEN
{There is a variable-length part & we're shrinking}
XferLeft(Ptr(bk + oldSize), Ptr(bk + newSize), cb - oldSize);
ChangeSizeH(hz, TH(object), cb + newSize - oldSize);
IF (cb > oldSize) AND (newSize > oldSize) THEN
{There is a variable-length part & we're expanding}
XferRight(Ptr(bk + oldSize), Ptr(bk + newSize), cb - oldSize);
IF newSize > oldSize THEN
{Default extra fields to 0/NIL}
BEGIN
extraPtr := TPByte(bk + oldSize + 1);
extraPtr^ := 0;
{Store one zero and let XferLeft copy it repeatedly}
XferLeft(Ptr(extraPtr), Ptr(ORD(extraPtr) + 1), newSize - oldSize - 1);
END;
END;
{$IFC fMaxTrace}EP;{$ENDC}
END;
{$S sRes}
FUNCTION Superclass(class: TClass): TClass;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$R-} Superclass := TClass(TPSliceTable(class)^[-1]); {$IFC fRngObject}{$R+}{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
END;
{$S sRes}
FUNCTION ClassDescendsFrom(descendant, ancestor: TClass): BOOLEAN;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
WHILE (descendant <> ancestor) AND (descendant <> NIL) DO
{$R-} descendant := TClass(TPSliceTable(descendant)^[-1]); {$IFC fRngObject}{$R+}{$ENDC}
ClassDescendsFrom := descendant <> NIL;
{$IFC fMaxTrace}EP;{$ENDC}
END;
{$S sRes}
PROCEDURE NameOfClass(class: TClass; VAR className: TClassName);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
CpToCn(TPSliceTable(class), TS8(className));
{$IFC fMaxTrace}EP;{$ENDC}
END;
{$S sRes}
FUNCTION SizeOfClass(class: TClass): INTEGER;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
SizeOfClass := SizeOfCp(TPSliceTable(class));
{$IFC fMaxTrace}EP;{$ENDC}
END;
{$S SgCLAres}
{toInsert, return: -1 if class already there or if table full, index if a hole found}
{not toInsert, return: index (> 0) if class found, -1 if not there}
FUNCTION LookupName(classAlpha: TA8; toInsert: BOOLEAN): INTEGER;
FUNCTION CompareName(hashIndex: INTEGER): THashCompare;
VAR myIndex:
INTEGER;
trialName: TS8;
BEGIN
myIndex := hMyHashName^^.records[hashIndex];
IF myIndex = 0 THEN
CompareName := cHole
ELSE
IF classAlpha = hMyClasses^^.records[myIndex].classAlpha THEN
CompareName := cMatch
ELSE
CompareName := cMismatch;
END;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
LookupName := LookupInHashArray(hMyHashName^^.header.size,
ORD(classAlpha[2])*ORD(classAlpha[4])+ORD(classAlpha[6]),
toInsert, CompareName);
END;
{$S SgCLAres}
FUNCTION ValidDataAddress(addr: LONGINT): BOOLEAN;
{Returns TRUE iff: addr is in a data segment (stack seg doesn't qualify)
AND is it an even address
AND is it within the bounds of the data segment}
CONST
dsMaxSize
= $00020000; {128K}
DsProcParam;
T_Ex_Name;
INTEGER;
prcsInfo:
heapBase:
progVolume:
ProcInfoRec;
LONGINT;
PathName;
BEGIN
{Until we call InitQDWM, NOTHING CAN FAIL!!!!}
isInitialized := FALSE;
amDying := FALSE;
wmIsInitialized := FALSE;
{$IFC fTrace}
fTraceEnabled := FALSE;
fDebugRecursion := FALSE;
tabLevel := -1;
curTraceLevel := 1;
traceCount := 0;
defTraceCount := 0;
breakMCount := 0;
kpcntr := 0;
keyPresLimit := stdKeyPresLimit;
returnToMain := TRUE;
showPrompt := TRUE;
outputIndent := 0;
currXPos := 0;
tallyingCalls := FALSE;
tallies := NIL;
segNames := NIL;
{$ENDC}
{Determine environment and program volume name}
Info_Process(error, My_id, prcsInfo);
{get my volume name as '-volname-'; assumes that the OS gives us back a program name of the form:
'-volname-progname'}
Delete(prcsInfo.progPathName, 1, 1); {the first '-'}
progVolume := Concat('-', Copy(prcsInfo.progPathName, 1, Pos('-', prcsInfo.progPathName)));
{$IFC LibraryVersion <= 20}
{Yu Ying has a better way to know if we are on the desktop or in the workshop, but meanwhile...}
IF prcsInfo.father_Id > 1 THEN
BEGIN
Info_Process(error, prcsInfo.father_Id, prcsInfo);
{this assumes that the OS returns a program name of the form '-volname-progname'}
Delete(prcsInfo.progPathName, 1, 1); {the first '-'}
Delete(prcsInfo.progPathName, 1, Pos('-', prcsInfo.progPathName)); {the 'volname-'}
StrUpperCased(@prcsInfo.progPathName);
{must be the first thing before any operations that could fail;
when running on the Workshop, it also sets up the FontMgr & writeln to alternate screen.}
{$IFC fDbgObject}
Write('Running on the ');
IF onDesktop THEN
WriteLn('desktop')
ELSE
WriteLn('workshop');
{$ENDC}
{Declare an OS Exception Handler}
excepName := 'SYS_TERMINATE';
Declare_Excep_Hdl(error, excepName, @TrmntExceptionHandler);
CheckInitError(error);
{$IFC fDbgObject}
GoToXY(0,31);
{$ENDC}
{Create data segment and heap}
mainLdsn := prcsLdsn;
heapBase := MakeDataSegment(error, mainDsRefnum, '', progVolume, mainLdsn, prcsDsBytes, prcsDsBytes);
CheckInitError(error);
mainHeap := NewHeap(error, heapBase, prcsDsBytes, prcsDsBytes DIV 20);
CheckInitError(error);
SetHeap(mainHeap);
END;
{$S sInit1}
PROCEDURE UnitAuthor(companyAndAuthor: TAuthorName);
VAR a32:
TA32;
BEGIN
StrUpperCased(@companyAndAuthor);
FillChar(a32, 32, ' ');
XferLeft(Ptr(ORD(@companyAndAuthor)+1), @a32, LENGTH(companyAndAuthor));
QUnitAuthor(a32);
END;
{$S sInit1}
PROCEDURE ClassAuthor(companyAndAuthor: TAuthorName; classAlias: TClassName);
VAR a32:
TA32;
a8:
TA8;
BEGIN
IF LENGTH(companyAndAuthor) > 0 THEN
BEGIN
StrUpperCased(@companyAndAuthor);
FillChar(a32, 32, ' ');
XferLeft(Ptr(ORD(@companyAndAuthor)+1), @a32, LENGTH(companyAndAuthor));
QClassAuthor(a32);
END;
{optional}
{$IFC fMaxTrace}BP(1);{$ENDC}
Recreate(object, exWorld.hExClasses^^.records[exIndex].objectSize, (*^*)
hMyClasses^^.records[myIndex].objectSize, hMySTables^^.records[myIndex]); (*^*)
{$IFC fMaxTrace}EP;{$ENDC}
END;
{$S SgCLAcld}
FUNCTION IndexOfExClass(exWorld: TWorld; exIndex: INTEGER): INTEGER;
LABEL 1,2;
VAR exAuthor:
TA32;
exAlias:
TA8;
exAlpha:
TA8;
coCode:
INTEGER;
alCode:
INTEGER;
index:
INTEGER;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
IndexOfExClass := 0;
WITH exWorld, hExClasses^^.records[exIndex] DO (*^*)(* WHOLE BLOCK CHANGED *)
BEGIN
exAlpha := classAlpha;
IF classAlias = 0 THEN
exAlias := classAlpha
ELSE
exAlias := hExAliases^^.records[classAlias];
1:
{If that class name is one of mine, too, do it the easy way}
index := CiOfAlpha(exAlpha);
IF index <> 0 THEN (*^*)
IF hMyClasses^^.records[index].companyAndAuthor = coCode THEN
BEGIN (*^*)
IndexOfExClass := index;
EXIT(IndexOfExClass); (*^*)
END; (*^*)
{Different company name or never heard of that class name at all, return 0}
EXIT(IndexOfExClass); (*^*)
2:
{The hard way: exhaustive search, because we may be using different names for the same class}
WITH hMyClasses^^ DO
FOR index := 1 TO numClasses DO
WITH records[index] DO
IF coCode = companyAndAuthor THEN
IF alCode = classAlias THEN
BEGIN
IndexOfExClass := index;
EXIT(IndexOfExClass);
END;
END;
{$S SgCLAcld}
FUNCTION NeedConversion(exClassWorld: TClassWorld; VAR olderVersion, newerVersion: BOOLEAN): BOOLEAN;
VAR someDifference:
BOOLEAN;
exWorld:
TWorld;
numExClasses:
INTEGER;
exIndex:
INTEGER;
exInfo:
TClassInfo;
exSize:
INTEGER;
exSTP:
TPSliceTable;
myIndex:
INTEGER;
myInfo:
TClassInfo;
mySize:
INTEGER;
mySTP:
TPSliceTable;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
someDifference := FALSE;
olderVersion := FALSE;
newerVersion := FALSE;
exWorld := TWorld(exClassWorld);
WITH exWorld DO
BEGIN
numExClasses := hExClasses^^.header.size;
IF numClasses <> numExClasses THEN
someDifference := TRUE;
FOR exIndex := 1 TO numExClasses DO
BEGIN
myIndex := IndexOfExClass(exWorld, exIndex);
IF myIndex = 0 THEN
newerVersion := TRUE
ELSE
BEGIN
exInfo := hExClasses^^.records[exIndex];
exSize := exInfo.objectSize;
exSTP := hExSTables^^.records[exIndex];
myInfo := hMyClasses^^.records[myIndex];
mySize := myInfo.objectSize;
mySTP := hMySTables^^.records[myIndex];
IF (myInfo.version < exInfo.version) OR (mySize < exSize) THEN
newerVersion := TRUE;
IF (myInfo.version > exInfo.version) OR (mySize > exSize) THEN
olderVersion := TRUE;
IF (mySTP <> exSTP) OR (myInfo.oldestReadableVersion <> exInfo.oldestReadableVersion) THEN
someDifference := TRUE;
IF exInfo.superIndex = 0 THEN
BEGIN
IF myInfo.superIndex <> 0 THEN
newerVersion := TRUE;
END
ELSE
IF myInfo.superIndex <> IndexOfExClass(exWorld, exInfo.superIndex) THEN
newerVersion := TRUE;
END;
END;
END;
NeedConversion := someDifference OR olderVersion OR newerVersion;
END;
{$S SgCLAcld}
PROCEDURE ConvertHeap(heap: THeap; exClassWorld: TClassWorld);
TWorld;
BOOLEAN;
INTEGER;
THIdxArray;
THIdxArray;
INTEGER;
{toInsert, return: -1 if sliceTable already there or if table full, index if a hole found}
{not toInsert, return: index (> 0) if sliceTable found, -1 if not there}
FUNCTION LookupSTP(stp: TPSliceTable; toInsert: BOOLEAN): INTEGER;
FUNCTION CompareSTP(hashIndex: INTEGER): THashCompare;
VAR myIndex:
INTEGER;
BEGIN
myIndex := hExHashSTP^^.records[hashIndex];
IF myIndex = 0 THEN
CompareSTP := cHole
ELSE
IF exWorld.hExSTables^^.records[myIndex] = stp THEN
CompareSTP := cMatch
ELSE
CompareSTP := cMismatch;
END;
BEGIN
LookupSTP := LookupInHashArray(hExHashSTP^^.header.size, ORD(stp), toInsert, CompareSTP);
END;
FUNCTION EquivIndex(exIndex: INTEGER): INTEGER;
VAR tblIndex:
INTEGER;
myIndex:
INTEGER;
BEGIN
tblIndex := exIndex;
WITH exWorld DO
WHILE tblIndex <> 0 DO
WITH hExClasses^^.records[tblIndex] DO
BEGIN
myIndex := IndexOfExClass(exWorld, tblIndex);
****)
END;
{Pass 2: Default extra fields; a separate pass so the application can follow pointers if need be}
VAR exIndex:
INTEGER;
myIndex:
INTEGER;
moreConverson: BOOLEAN;
BEGIN
{Determine both the original and my class}
IF FindClasses(object, exIndex, myIndex, moreConversion) THEN
IF moreConversion THEN
{Let the app supply extra fields etc.}
object.Convert(exWorld.hExClasses^^.records[exIndex].version);
END;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
exWorld := TWorld(exClassWorld);
WITH exWorld DO
BEGIN
numExClasses := hExClasses^^.header.size;
{Make temporary arrays that will speed up reconciliation of the two worlds}
hExEquivalent := MakeIdxArray(numExClasses, FALSE);
FOR exIndex := 1 TO numExClasses DO
hExEquivalent^^.records[exIndex] := EquivIndex(exIndex);
IF numExClasses > 255 THEN
BEGIN
hExHashSTP := MakeIdxArray(numExClasses - 255, TRUE);
FOR exIndex := 256 TO numExClasses DO
hExHashSTP^^.records[LookupSTP(hExSTables^^.records[exIndex], TRUE)] := exIndex;
END;
END;
needPassTwo := FALSE;
{Pass One -- convert method table pointers (STPs)}
EachObject(heap, ConvertClass);
{Pass Two -- let application default extra fields}
IF needPassTwo THEN
EachObject(heap, ConvertFields);
{Free the temporary arrays}
FreeH(THz(mainHeap), TH(hExEquivalent));
IF numExClasses > 255 THEN (*^*)
FreeH(THz(mainHeap), TH(hExHashSTP));
END;
{$S sError}
PROCEDURE ClascalReason(error: INTEGER; VAR s: S255);
BEGIN
CASE error OF
OTHERWISE s := 'Some kind of problem';
END;
END;
{$S sInit1}
PROCEDURE ClascalError(error: INTEGER); {called with error = 0 after successful Clascal initialization}
VAR s: S255;
i: INTEGER;
BEGIN
IF error > 0 THEN
BEGIN
{$IFC fDbgObject}
ClascalReason(error, s);
{$ENDC}
IF isInitialized THEN
BEGIN
{$IFC fDbgObject}
ABCBreak(s, error);
{$ENDC}
TrmntExceptionHandler;
END
ELSE
BEGIN
{$IFC fDbgObject}
WriteLn('Clascal error: ', s);
{$ENDC}
IF wmIsInitialized THEN
InitErrorAbort(error)
ELSE
{$IFC fDbgObject}
%_GoLisaBug;
{ELSEC}
HALT;
{$ENDC}
END;
END
ELSE
IF NOT classesInitialized THEN
BEGIN
{*** STILL TO DO: The first time the program runs, write to the tool resource file ***}
{Save conversion information not obtainable from UClascal in permanent arrays}
(*****
*****)
END;
METHODS OF TObject;
{$S sStartup}
PROCEDURE TObject.Become(object: TObject);
LABEL
1;
VAR hSelf: TH;
hObj:
TH;
bkSelf: TBk;
bkObj: TBk;
p:
TP;
{$IFC LibraryVersion <= 20}
oh:
TC;
{$ELSEC}
tempBP: TBp;
{$ENDC}
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
IF SELF.Heap <> object.Heap THEN
BEGIN
{$IFC fDbgObject}
WriteLn(ORD(SELF));
ABCBreak('Attempt to Become an object on another heap', ORD(object));
{$ENDC}
GOTO 1;
END;
hSelf := TH(SELF);
hObj := TH(object);
bkSelf := TBk(ORD(hSelf^) - 4);
bkObj := TBk(ORD(hObj^) - 4);
p := hSelf^;
hSelf^ := hObj^;
hObj^ := p;
{$IFC LibraryVersion <= 20}
oh := bkSelf^.oh;
bkSelf^.oh := bkObj^.oh;
bkObj^.oh := oh;
{$ELSEC}
tempBP := bkSelf^.bp;
bkSelf^.bp := bkObj^.bp;
bkObj^.bp := tempBP;
{$ENDC}
object.Free;
1:
{$IFC fTrace}EP;{$ENDC}
END;
{$S sStartup}
FUNCTION
BEGIN
{$IFC
Class
{$IFC
END;
{$S sRes}
FUNCTION
BEGIN
{$IFC
Clone
{$IFC
END;
TObject.Class: TClass;
fMaxTrace}BP(1);{$ENDC}
:= ClassPtr(Handle(SELF));
fMaxTrace}EP;{$ENDC}
{$S sRes}
FUNCTION TObject.CloneObject(heap: THeap): TObject;
VAR hz:
THz;
size:
INTEGER;
source: TH;
dest:
TH;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
hz := THz(heap);
source := TH(SELF);
size := cbDataOfH(hz, source);
dest := HAllocate(hz, size);
XferLeft(@source^^, @dest^^, size);
CloneObject := TObject(dest);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sStartup}
PROCEDURE TObject.Free;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
SELF.FreeObject;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sStartup}
PROCEDURE TObject.FreeObject;
VAR heap:
THeap;
numObjects: INTEGER;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
heap := SELF.Heap;
FreeH(THz(heap), TH(SELF));
{$IFC fTrace}EP;{$ENDC}
END;
{$S sStartup}
FUNCTION TObject.Heap: THeap;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
Heap := THeap(HzFromH(TH(SELF)));
END;
{$S sRes}
FUNCTION TObject.HeapBytes: INTEGER;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
HeapBytes := CbDataOfH(HzFromH(TH(SELF)), TH(SELF));
{$IFC fTrace}EP;{$ENDC}
END;
{$S sLOX}
PROCEDURE TObject.Read(s: TStringScanner);
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
s.XferFields(xRead, SELF);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sLOX}
PROCEDURE TObject.Write(s: TStringScanner);
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
s.XferFields(xWrite, SELF);
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S SgCLAdbg}
PROCEDURE TObject.Debug(numLevels: INTEGER; memberTypeStr: S255);
VAR class:
TClass;
name:
TClassName;
str:
S255;
{$IFC fTrace}
oldFlag:
BOOLEAN;
{$ENDC}
PROCEDURE SupplyObjFields(PROCEDURE Field(nameAndType: S255));
BEGIN
SELF.Fields(Field);
END;
BEGIN
{$IFC fTrace}
oldFlag := fDebugRecursion;
fDebugRecursion := TRUE;
{$ENDC}
class := SELF.Class;
CpToCn(TPSliceTable(class), TS8(name));
TrimBlanks(@name);
WrStr(Concat(name, ' '));
{$IFC fDebugMethods}
IF numLevels > 0 THEN
WriteDRecord(numLevels, Handle(SELF), 4, SupplyObjFields);
{$ELSEC}
LIntToHex(ORD(SELF), @str);
str := Concat('-- $', str);
IF NOT ValidObject(Handle(SELF)) THEN
str := Concat('Invalid Object', str);
WrStr(str);
{$ENDC}
{$IFC fTrace}
fDebugRecursion := oldFlag;
{$ENDC}
END;
{$S SgCLAres}
{$ENDC}
{$IFC fDebugMethods}
{$S SgCLAdbg}
PROCEDURE TObject.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
END;
{$S SgCLAres}
{$ENDC}
{$S SgCLAcld}
PROCEDURE TObject.Convert(fromVersion: Byte);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
END;
{$S SgCLAres}
{$S SgCLAcld}
FUNCTION TObject.JoinClass(newClass: TClass): TObject;
VAR oldClass:
TClass;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
oldClass := SELF.Class;
IF NOT ClassDescendsFrom(oldClass, newClass) THEN
IF ClassDescendsFrom(newClass, oldClass) THEN
Recreate(SELF, SizeOfCp(TPSliceTable(oldClass)),
SizeOfCP(TPSliceTable(newClass)), TPSliceTable(newClass)) (*^*)
ELSE
{$IFC fDbgObject}
ABCBreak('An Object cannot move to an unrelated class', ORD(newClass))
{$ENDC};
JoinClass := SELF;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgCLAres}
{$S sInit1}
BEGIN {Class Initialization}
InitClascal(ClascalError);
InitObject;
UnitAuthor('Apple');
cObject := THISCLASS;
END;
[c.holeStart+1..c.holeStart+c.holeSize]
METHODS OF TCollection;
{$S sResDat}
FUNCTION TCollection.CREATE(object: TObject; heap: THeap; initialSlack: INTEGER): TCollection;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
IF object = NIL THEN
ABCBreak('TCollection.CREATE must be passed an already-allocated object by a subclass CREATE', 0);
SELF := TCollection(object);
WITH SELF DO
BEGIN
size := 0;
{$H-} dynStart := SizeOfClass(SELF.Class); {$H+}
holeStart := 0;
holeSize := initialSlack;
holeStd := 0;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
FUNCTION TCollection.Clone(heap: THeap): TObject;
VAR numMembers: INTEGER;
collection: TCollection;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
numMembers := SELF.size;
collection := TCollection(NewDynObject(heap, SELF.Class, numMembers * SELF.MemberBytes));
XferLeft(Ptr(Handle(SELF)^), Ptr(Handle(collection)^), SELF.dynStart);
collection := TCollection.CREATE(collection, heap, numMembers);
collection.InsManyAt(1, SELF, 1, numMembers);
Clone := collection;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S SgCLAdbg}
PROCEDURE TCollection.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('size: LONGINT');
Field('dynStart: INTEGER');
Field('holeStart: INTEGER');
Field('holeSize: INTEGER');
Field('holeStd: INTEGER');
END;
{$S SgCLAres}
{$ENDC}
{$IFC fCheckIndices}
{$S SgCLAdbg}
PROCEDURE TCollection.CheckIndex(index: LONGINT);
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
IF (index < 1) OR (index > SELF.size) THEN
ABCBreak('CheckIndex', index);
END;
{$S SgCLAres}
{$ENDC}
{$S sResDat}
FUNCTION TCollection.AddrMember(i: LONGINT): LONGINT;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
{$IFC fDbgObject}
IF SELF.dynStart = MAXINT THEN
ABCBreak('No dynamic part', i);
{$ENDC}
{$IFC fCheckIndices}
IF fCheckIndices THEN
IF (i < 1) OR (i > SELF.size+1) THEN
ABCBreak('CheckIndex', i);
{$ENDC}
IF i > SELF.holeStart THEN
i := i + SELF.holeSize;
{i is now a physical index}
AddrMember := TpLONGINT(SELF)^ + SELF.dynStart + (SELF.MemberBytes * (i - 1));
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
PROCEDURE TCollection.CopyMembers(dstAddr, startIndex, howMany: LONGINT);
VAR memberBytes:
INTEGER;
beforeHole:
INTEGER;
srcAddr:
j:
offset:
numBytes:
LONGINT;
INTEGER;
INTEGER;
INTEGER;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
IF startIndex < 1 THEN
startIndex := 1;
howMany := Min(howMany, SELF.size + 1 - startIndex);
IF (howMany > 0) AND (startIndex <= SELF.size) THEN
BEGIN
memberBytes := SELF.MemberBytes;
beforeHole := Min(howMany, SELF.holeStart + 1 - startIndex);
srcAddr := SELF.AddrMember(startIndex);
IF beforeHole > 0 THEN
BEGIN
numBytes := beforeHole * memberBytes;
XferLeft(Ptr(srcAddr), Ptr(dstAddr), numBytes);
dstAddr := dstAddr + numBytes;
END
ELSE
beforeHole := 0;
IF beforeHole < howMany THEN
BEGIN
srcAddr := SELF.AddrMember(startIndex + beforeHole);
XferLeft(Ptr(srcAddr), Ptr(dstAddr), (howMany - beforeHole) * memberBytes);
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
{AFTER EXECUTING THIS METHOD:
IF deltaMembers >= 0,
physical positions [atIndex..atIndex+deltaMembers-1] are available for adding new members.
IF deltaMembers < 0,
actual members [atIndex..atIndex-deltaMembers+1] have been removed.
NOTE: This routine does not preserve the TCollection invariant.
}
PROCEDURE TCollection.EditAt(atIndex: LONGINT; deltaMembers: INTEGER);
VAR oldHoSize:
INTEGER;
newHoSize:
INTEGER;
oldHoStart:
INTEGER;
newHoStart:
INTEGER;
maxHoStart:
INTEGER;
minHoStart:
INTEGER;
size:
INTEGER;
b:
0..1;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
{$IFC fDbgObject}
IF SELF.dynStart = MAXINT THEN
ABCBreak('No dynamic part', atIndex);
{$ENDC}
{increase the space allocated to the collection, and shift the collection so that the
the last real element is at the end of the space allocated to the collection;
but only move REAL elements that will end up after the hole}
size := SELF.size;
newHoSize := Max(newHoSize, SELF.holeStd);
SELF.ResizeColl(size + newHoSize);
SELF.ShiftColl(maxHoStart + oldHoSize, maxHoStart + newHoSize, size - maxHoStart);
{Explanation of the above line:
maxHoStart = max # real elements before the hole (in initial and final collections)
size = # real elements in the initial collection
therefore, size - maxHoStart is min # real elements after the hole, which
is the right number of elements to move
the allocated size of the collection is size + newHoSize (from SELF.ResizeColl)
to get the last real element we are moving to be at the end of the allocated space,
we need to move the first element to
allocated size of collection - # elements moving
=
size + newHoSize - (size - maxHoStart)
=
maxHoStart + newHoSize
we increased the size of the collection by newHoSize - oldHoSize
therefore the first source element must be
first destination element - (newHoSize - oldHoSize)
=
maxHoStart + newHoSize - (newHoSize - oldHoSize)
=
maxHoStart + oldHoSize
}
END;
SELF.holeStart := newHoStart;
SELF.holeSize := newHoSize;
END;
END;
WITH SELF DO
BEGIN
size := size + deltaMembers;
holeSize := holeSize - deltaMembers;
{$S sResDat}
{NOTE: This routine does not preserve the TCollection invariant.}
PROCEDURE TCollection.ResizeColl(membersPlusHole: INTEGER);
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
{$IFC fDbgObject}
IF SELF.dynStart = MAXINT THEN
ABCBreak('No dynamic part', membersPlusHole);
{$ENDC}
IF membersPlusHole <> (SELF.size + SELF.holeSize) THEN
ResizeDynObject(SELF, SELF.dynStart + (membersPlusHole * SELF.MemberBytes));
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
{NOTE: This routine does not preserve the TCollection invariant.}
PROCEDURE TCollection.ShiftColl(afterSrcIndex, afterDstIndex, howMany: INTEGER);
VAR memberBytes:
INTEGER;
numBytes:
INTEGER;
startAddr:
LONGINT;
srcAddr:
LONGINT;
dstAddr:
LONGINT;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
{$IFC fDbgObject}
IF SELF.dynStart = MAXINT THEN
ABCBreak('No dynamic part', howMany);
{$ENDC}
IF (howMany > 0) AND (afterSrcIndex <> afterDstIndex) THEN
BEGIN
memberBytes := SELF.MemberBytes;
numBytes := howMany * memberBytes;
startAddr := TpLONGINT(SELF)^ + SELF.dynStart;
srcAddr := startAddr + afterSrcIndex * memberBytes;
dstAddr := startAddr + afterDstIndex * memberBytes;
IF afterSrcIndex < afterDstIndex THEN
XferRight(Ptr(srcAddr), Ptr(dstAddr), numBytes)
ELSE
XferLeft(Ptr(srcAddr), Ptr(dstAddr), numBytes);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TCollection.StartEdit(withSlack: INTEGER);
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
{$IFC fDbgObject}
IF SELF.dynStart = MAXINT THEN
ABCBreak('No dynamic part', withSlack);
{$ENDC}
SELF.holeStd := withSlack;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
PROCEDURE TCollection.StopEdit;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
{$IFC fDbgObject}
IF SELF.dynStart = MAXINT THEN
ABCBreak('No dynamic part', 0);
{$ENDC}
IF SELF.holeStart < SELF.size THEN
SELF.EditAt(SELF.size + 1, 0);
SELF.ResizeColl(SELF.size);
SELF.holeStd := 0;
SELF.holeSize := 0;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sInit1}
BEGIN
{$IFC fCheckIndices}
fCheckIndices := FALSE;
{$ENDC}
END;
{$S SgCLAres}
METHODS OF TList;
{$S sResDat}
FUNCTION TList.CREATE(object: TObject; heap: THeap; initialSlack: INTEGER): TList;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
IF object = NIL THEN
object := NewDynObject(heap, THISCLASS, initialSlack * SIZEOF(Handle));
SELF := TList(TCollection.CREATE(object, heap, initialSlack));
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
PROCEDURE TList.Free;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
SELF.Each(Free);
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
FUNCTION TList.Clone(heap: THeap): TObject;
VAR l: TList;
j: INTEGER;
x: TObject;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
l := TList(SUPERSELF.Clone(heap));
FOR j := 1 TO l.size DO
BEGIN
x := SELF.At(j);
IF x <> NIL THEN
l.PutAt(j, x.Clone(heap), FALSE);
END;
Clone := l;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S SgCLAdbg}
PROCEDURE TList.Debug(numLevels: INTEGER; memberTypeStr: S255);
VAR s:
TListScanner;
obj:
TObject;
str:
S8;
first:
BOOLEAN;
{$IFC fTrace}
oldFlag:
BOOLEAN;
{$ENDC}
BEGIN
{$IFC fTrace}
oldFlag := fDebugRecursion;
fDebugRecursion := TRUE;
{$ENDC}
SUPERSELF.Debug(numLevels, '');
{ this prints other fields of the list }
IF numLevels > 0 THEN
BEGIN
WrStr('(');
IF numLevels = 1 THEN
{ compressed list of classes }
SELF.DebugMembers
ELSE
{ list of classes and their handles }
BEGIN
s := SELF.Scanner;
IF s.position = SELF.holeStart THEN
Write('<=HOLE=>');
first := TRUE;
WHILE s.Scan(obj) DO
BEGIN
IF NOT first THEN
WrStr(', ');
first := FALSE;
IF obj = NIL THEN
WrStr('NIL')
ELSE IF ValidObject(Handle(obj)) THEN
obj.Debug(numLevels-2, '')
ELSE
WrStr('<Invalid Object>');
IF numLevels = 2 THEN
BEGIN
LIntToHex(ORD4(obj), @str);
WrStr(CONCAT(': $', str));
END;
IF s.position = SELF.holeStart THEN
Write('<=HOLE=>');
END;
END;
WrStr(')');
END;
{$IFC fTrace}
fDebugRecursion := oldFlag;
{$ENDC}
END;
{$S SgCLAres}
{$S SgCLAdbg}
PROCEDURE TList.DebugMembers;
VAR y:
TObject;
s:
TListScanner;
str:
S8;
initial:
BOOLEAN;
class:
TClass;
thisClass:
TClassName;
prevClass:
TClassName;
sameClass:
INTEGER;
charCount:
INTEGER;
PROCEDURE WriteMembers;
VAR charsNeeded:
INTEGER;
BEGIN
IF sameClass = 0 THEN EXIT(WriteMembers);
IF sameClass = 1 THEN
charsNeeded := 10
ELSE
charsNeeded := 13;
IF initial THEN
initial := FALSE
ELSE IF (charCount + charsNeeded) > 70 THEN
BEGIN
WrStr(',');
WrLn;
WrStr('
');
charCount := 10;
END
ELSE
WrStr(', ');
str := prevClass;
WrStr(str);
IF sameClass > 1 THEN
BEGIN
IntToStr(sameClass, @str);
WrStr(CONCAT('*', str));
END;
charCount := charCount + charsNeeded;
END;
BEGIN
IF SELF.size > 0 THEN {prevent initialization anomaly in BP(i)/EP}
BEGIN
charCount := cMin(indentTrace, 20) + 30;
initial := TRUE;
sameClass := 0;
prevClass := '';
s := SELF.Scanner;
WHILE s.Scan(y) DO
BEGIN
IF y = NIL THEN
thisClass := 'NIL'
ELSE IF ValidObject(Handle(y)) THEN
BEGIN
class := y.Class;
CpToCn(TPSliceTable(class), TS8(thisClass));
END
ELSE
thisClass := '????????';
IF thisClass <> prevClass THEN
BEGIN
WriteMembers;
sameClass := 1;
END
ELSE
sameClass := sameClass + 1;
prevClass := thisClass;
END;
WriteMembers;
END;
END;
{$S SgCLAres}
{$ENDC}
{$S sResDat}
FUNCTION TList.At(i: LONGINT): TObject;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
{$IFC fCheckIndices}
IF fCheckIndices THEN
SELF.CheckIndex(i);
{$ENDC}
{At := TPObject(SELF.AddrMember(i))^;
SELF.DelAt(SELF.size, freeOld);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TList.DelManyAt(i, howMany: LONGINT; freeOld: BOOLEAN);
VAR j: INTEGER;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
IF howMany > 0 THEN
BEGIN
{$IFC fCheckIndices}
IF fCheckIndices THEN
BEGIN
SELF.CheckIndex(i);
SELF.CheckIndex(i+howMany-1);
END;
{$ENDC}
IF freeOld THEN
FOR j := 0 TO howMany - 1 DO
Free(SELF.At(i + j));
SELF.EditAt(i, -howMany);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TList.DelObject(object: TObject; freeOld: BOOLEAN);
VAR y: TObject;
s: TListScanner;
BEGIN
{If there is more than one occurrence, and editing is off, this calls StopEdit more than once}
{$IFC fTrace}BP(4);{$ENDC}
s := SELF.Scanner;
WHILE s.Scan(y) DO
IF y = object THEN
s.Delete(FALSE);
IF freeOld THEN
Free(object);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
PROCEDURE TList.Each(PROCEDURE DoToObject(object: TObject));
VAR holeStart: INTEGER;
offset:
INTEGER;
j:
pObject:
INTEGER;
TPObject;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
holeStart := SELF.holeStart;
offset := SELF.dynStart;
FOR j := 0 TO SELF.size - 1 DO
BEGIN
IF j = holeStart THEN
offset := offset + 4 * SELF.holeSize;
pObject := TPObject(TpLONGINT(SELF)^ + offset);
DoToObject(pObject^);
offset := offset + 4;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
FUNCTION
BEGIN
{$IFC
First
{$IFC
END;
TList.First: TObject;
fTrace}BP(3);{$ENDC}
:= SELF.At(1);
fTrace}EP;{$ENDC}
{$S sResDat}
PROCEDURE TList.InsAt(i: LONGINT; object: TObject);
VAR pObject:
TPObject;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
SELF.EditAt(i, 1);
pObject := TPObject(SELF.AddrMember(i));
pObject^ := object;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TList.InsFirst(object: TObject);
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
SELF.InsAt(1, object);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
PROCEDURE TList.InsLast(object: TObject);
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
SELF.InsAt(SELF.size + 1, object);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
FUNCTION TList.Last: TObject;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
Last := SELF.At(SELF.size);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
FUNCTION TList.ManyAt(i, howMany: LONGINT): TList;
VAR list: TList;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
list := TList.CREATE(NIL, SELF.Heap, howMany);
list.InsManyAt(1, SELF, i, howMany);
ManyAt := list;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
FUNCTION TList.MemberBytes: INTEGER;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
MemberBytes := 4;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
FUNCTION TList.PopLast: TObject;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
PopLast := SELF.Last;
SELF.DelLast(FALSE);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
FUNCTION TList.Pos(after: LONGINT; object: TObject): LONGINT;
VAR y: TObject;
s: TListScanner;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
Pos := after;
s := SELF.ScannerFrom(after, scanForward);
WHILE s.Scan(y) DO
IF object = y THEN
BEGIN
Pos := s.position;
s.Done;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TList.PutAt(i: LONGINT; object: TObject; freeOld: BOOLEAN);
VAR pObject:
TPObject;
oldObject: TObject;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
{$IFC fCheckIndices}
IF fCheckIndices THEN
SELF.CheckIndex(i);
{$ENDC}
{pObject := TPObject(SELF.AddrMember(i));
Field('recordBytes: INTEGER');
END;
{$S SgCLAres}
{$ENDC}
{$IFC fDebugMethods}
{$S SgCLAdbg}
PROCEDURE TArray.Debug(numLevels: INTEGER; memberTypeStr: S255);
VAR s:
TArrayScanner;
pRecord:
Ptr;
i:
INTEGER;
j:
INTEGER;
str:
S255;
hexOrd:
S8;
PROCEDURE SupplyMember(PROCEDURE Field(nameAndType: S255));
BEGIN
Field(Concat(str, ': ', memberTypeStr));
END;
BEGIN
SUPERSELF.Debug(numLevels, '');
{ this prints other fields of the array }
IF (numLevels > 1) OR ((numLevels = 1) AND (memberTypeStr <> '')) THEN
BEGIN
WrStr('{ ');
i := 0;
s := SELF.Scanner;
IF s.position = SELF.holeStart THEN
WrStr(' <=HOLE=> ');
WHILE s.Scan(pRecord) DO
BEGIN
IF i > 0 THEN
WrStr(', ');
i := i + 1;
IntToStr(i, @str);
IF memberTypeStr = '' THEN
BEGIN
str := CONCAT(str, ': ');
FOR j := 0 TO SELF.recordBytes-1 DO
BEGIN
LIntToHex(TPByte(ORD(pRecord)+j)^, @hexOrd);
str := CONCAT(str, Copy(hexOrd, 7, 2));
END;
WrStr(str);
END
ELSE
WriteDRecord(numLevels - 1, @pRecord, 0, SupplyMember);
END;
{$S SgCLAres}
{$ENDC}
{$S sResDat}
FUNCTION TArray.At(i: LONGINT): Ptr;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
{$IFC fCheckIndices}
IF fCheckIndices THEN
SELF.CheckIndex(i);
{$ENDC}
{ At := Ptr(SELF.AddrMember(i));
PROCEDURE TArray.DelFirst;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
SELF.DelAt(1);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TArray.DelLast;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
SELF.DelAt(SELF.size);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TArray.DelManyAt(i, howMany: LONGINT);
VAR j: INTEGER;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
IF howMany > 0 THEN
SELF.EditAt(i, -howMany);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TArray.Each(PROCEDURE DoToRecord(pRecord: Ptr));
VAR holeStart:
INTEGER;
offset:
INTEGER;
recordBytes:
INTEGER;
j:
INTEGER;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
holeStart := SELF.holeStart;
offset := SELF.dynStart;
recordBytes := SELF.recordBytes;
FOR j := 0 TO SELF.size - 1 DO
BEGIN
IF j = holeStart THEN
offset := offset + recordBytes * SELF.holeSize;
DoToRecord(Ptr(TpLONGINT(SELF)^ + offset));
offset := offset + recordBytes;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
FUNCTION
BEGIN
{$IFC
First
{$IFC
END;
TArray.First: Ptr;
fTrace}BP(3);{$ENDC}
:= SELF.At(1);
fTrace}EP;{$ENDC}
{$S sResDat}
PROCEDURE TArray.GetAt(i: LONGINT; pRecord: Ptr);
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
{$IFC fCheckIndices}
IF fCheckIndices THEN
SELF.CheckIndex(i);
{$ENDC}
XferLeft(Ptr(SELF.AddrMember(i)), pRecord, SELF.recordBytes);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
PROCEDURE TArray.InsAt(i: LONGINT; pRecord: Ptr);
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
SELF.EditAt(i, 1);
SELF.PutAt(i, pRecord);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
PROCEDURE TArray.InsFirst(pRecord: Ptr);
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
SELF.InsAt(1, pRecord);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
PROCEDURE TArray.InsLast(pRecord: Ptr);
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
SELF.InsAt(SELF.size + 1, pRecord);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
FUNCTION TArray.Last: Ptr;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
Last := SELF.At(SELF.size);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
FUNCTION TArray.ManyAt(i, howMany: LONGINT): TArray;
VAR arr: TArray;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
arr := TArray.CREATE(NIL, SELF.Heap, howMany, SELF.recordBytes);
arr.InsManyAt(1, SELF, i, howMany);
ManyAt := arr;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
FUNCTION TArray.MemberBytes: INTEGER;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
MemberBytes := SELF.recordBytes;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
FUNCTION TArray.Pos(after: LONGINT; pRecord: Ptr): LONGINT;
VAR y: Ptr;
s: TArrayScanner;
FUNCTION EqualRecords(p, q: Ptr; n: INTEGER): BOOLEAN; {n is even}
VAR i: INTEGER;
BEGIN
EqualRecords := FALSE;
i := 0;
WHILE i < n DO
BEGIN
IF TpINTEGER(ORD(p) + i)^ <> TpINTEGER(ORD(q) + i)^ THEN
EXIT(EqualRecords);
i := i + 2;
END;
EqualRecords := TRUE;
END;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
Pos := after;
s := SELF.ScannerFrom(after, scanForward);
WHILE s.Scan(y) DO
IF EqualRecords(pRecord, y, SELF.recordBytes) THEN
BEGIN
Pos := s.position;
s.Done;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
PROCEDURE TArray.PutAt(i: LONGINT; pRecord: Ptr);
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
{$IFC fCheckIndices}
IF fCheckIndices THEN
SELF.CheckIndex(i);
{$ENDC}
XferLeft(pRecord, Ptr(SELF.AddrMember(i)), SELF.recordBytes);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
FUNCTION TArray.Scanner: TArrayScanner;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
Scanner := TArrayScanner.CREATE(NIL, SELF, 0, scanForward);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
FUNCTION TArray.ScannerFrom(firstToScan: LONGINT; scanDirection: TScanDirection): TArrayScanner;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
ScannerFrom := TArrayScanner.CREATE(NIL, SELF, firstToScan, scanDirection);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sInit1}
{$IFC compatibleLists} {For TDynamicArray.Class}
BEGIN
cArray := THISCLASS;
{$ENDC}
END;
METHODS OF TString;
{$S sResDat}
FUNCTION TString.CREATE(object: TObject; heap: THeap; initialSlack: INTEGER): TString;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
IF ODD(initialSlack) THEN
initialSlack := initialSlack + 1;
IF object = NIL THEN
object := NewDynObject(heap, THISCLASS, initialSlack);
SELF := TString(TCollection.CREATE(object, heap, initialSlack));
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S SgCLAdbg}
PROCEDURE TString.Debug(numLevels: INTEGER; memberTypeStr: S255);
VAR s:
TStringScanner;
ch:
CHAR;
str:
S8;
BEGIN
SUPERSELF.Debug(numLevels, '');
{ this prints other fields of the list }
IF numLevels > 0 THEN
BEGIN
WrStr('''');
s := SELF.Scanner;
IF s.position = SELF.holeStart THEN
WrStr('<=HOLE=>');
str := 'x';
WHILE s.Scan(ch) DO
BEGIN
str[1] := ch;
WrStr(str);
IF s.position = SELF.holeStart THEN
WrStr('<=HOLE=>');
END;
WrStr('''');
END;
END;
{$S SgCLAres}
{$ENDC}
{$S SgCLAres}
FUNCTION TString.At(i: LONGINT): CHAR;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
{$IFC fCheckIndices}
IF fCheckIndices THEN
SELF.CheckIndex(i);
{$ENDC}
IF i > SELF.holeStart THEN
i := i + SELF.holeSize;
At := TpPAOC(TpLONGINT(SELF)^ + SELF.dynStart)^[i];
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgCLAres}
PROCEDURE TString.DelAll;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
SELF.EditAt(1, -SELF.size);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgCLAres}
PROCEDURE TString.DelAt(i: LONGINT);
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
SELF.EditAt(i, -1);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgCLAres}
PROCEDURE TString.DelFirst;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
SELF.DelAt(1);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgCLAres}
PROCEDURE TString.DelLast;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
SELF.DelAt(SELF.size);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgCLAres}
PROCEDURE TString.DelManyAt(i, howMany: LONGINT);
VAR j: INTEGER;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
IF howMany > 0 THEN
SELF.EditAt(i, -howMany);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgCLAres}
PROCEDURE TString.Draw(i: LONGINT; howMany: INTEGER);
VAR beforeHole: INTEGER;
pWord1:
TpINTEGER;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
beforeHole := Min(SELF.holeStart - (i - 1), howMany);
pWord1 := TpINTEGER(TpLONGINT(SELF)^ + SELF.dynStart);
IF beforeHole > 0 THEN
DrawLText(pWord1, i - 1, beforeHole);
IF beforeHole < howMany THEN
DrawLText(pWord1, SELF.holeStart + SELF.holeSize - Min(beforeHole, 0),
howMany - Max(beforeHole, 0));
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
FUNCTION TString.Width(i: LONGINT; howMany: INTEGER): INTEGER;
VAR beforeHole: INTEGER;
pWord1:
TpINTEGER;
totalWidth: INTEGER;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
TString.First: CHAR;
fTrace}BP(3);{$ENDC}
:= SELF.At(1);
fTrace}EP;{$ENDC}
{$S SgCLAres}
PROCEDURE TString.InsAt(i: LONGINT; character: CHAR);
VAR pPAOC:
TpPAOC;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
SELF.EditAt(i, 1);
pPAOC := TpPAOC(TpLONGINT(SELF)^ + SELF.dynStart);
pPAOC^[i] := character;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgCLAres}
PROCEDURE TString.InsFirst(character: CHAR);
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
SELF.InsAt(1, character);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgCLAres}
PROCEDURE TString.InsLast(character: CHAR);
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
SELF.InsAt(SELF.size + 1, character);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
PROCEDURE TString.InsPStrAt(i: LONGINT; pStr: TPString);
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
SELF.EditAt(i, Length(pStr^));
XferLeft(Ptr(ORD(pStr)+1), Ptr(SELF.AddrMember(i)), Length(pStr^));
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgCLAres}
FUNCTION TString.Last: CHAR;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
Last := SELF.At(SELF.size);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgCLAres}
FUNCTION TString.ManyAt(i, howMany: LONGINT): TString;
i := i + SELF.holeSize;
pPAOC := TpPAOC(TpLONGINT(SELF)^ + SELF.dynStart);
pPAOC^[i] := character;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgCLAres}
FUNCTION TString.Scanner: TStringScanner;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
Scanner := TStringScanner.CREATE(NIL, SELF, 0, scanForward);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgCLAres}
FUNCTION TString.ScannerFrom(firstToScan: LONGINT; scanDirection: TScanDirection): TStringScanner;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
ScannerFrom := TStringScanner.CREATE(NIL, SELF, firstToScan, scanDirection);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgCLAres}
PROCEDURE TString.ToPStr(pStr: TPString);
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
SELF.ToPStrAt(1, SELF.size, pStr);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgCLAres}
PROCEDURE TString.ToPStrAt(i, howMany: LONGINT; pStr: TPString);
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
{$IFC fCheckIndices}
IF howMany > 255 THEN
ABCBreak('ToPStrAt: Too many characters', howMany);
{$ENDC}
SELF.EditAt(i + howMany, 0);
XferLeft(Ptr(SELF.AddrMember(i)), Ptr(ORD(pStr)+1), howMany);
{$R-} pStr^[0] := CHAR(howMany); {$IFC fRngObject}{$R+}{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S sInit1}
END;
{$S SgCLAres}
METHODS OF TFile;
{$S sResDat}
FUNCTION
{$S sResDat}
PROCEDURE TFile.Free;
BEGIN
{$IFC fTrace}BP(5);{$ENDC}
SELF.scanners.Free;
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgCLAres}
{$IFC fDbgObject}
{$S SgCLAdbg}
FUNCTION TFile.Clone(heap: THeap): TObject;
BEGIN
ABCBreak('A TFile cannot Clone', 0);
END;
{$S SgCLAres}
{$ENDC}
{$IFC fDebugMethods}
{$S SgCLAdbg}
PROCEDURE TFile.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('path: STRING[255]');
Field('password: STRING[32]');
Field('scanners: TList');
END;
{$S SgCLAres}
{$ENDC}
{$S SgCLAcld}
PROCEDURE TFile.ChangePassword(VAR error: INTEGER; newPassword: TPassword);
VAR pPath:
TPPathname;
pPass:
TPEName;
pNPass:
TPEName;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
{$IFC LibraryVersion <= 20}
error := -1293; {warning: file is not password protected}
{$ELSEC}
pPath := @SELF.path;
pPass := @SELF.password;
pNPass := @newPassword;
Change_Password(error, pPath^, pPass^, pNPass^);
{$ENDC}
IF error <= 0 THEN
SELF.password := newPassword;
END;
{$S SgCLAres}
{$S SgCLAcld}
PROCEDURE TFile.Delete(VAR error: INTEGER);
VAR pPath:
TPPathname;
{$IFC LibraryVersion > 20}
pPass:
TPEName;
{$ENDC}
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
pPath := @SELF.path;
{$IFC LibraryVersion <= 20}
Kill_Object(error, pPath^);
{$ELSEC}
pPass := @SELF.password;
Kill_Secure(error, pPath^, pPass^);
{$ENDC}
END;
{$S SgCLAres}
{$S sResDat}
FUNCTION TFile.Exists(VAR error: INTEGER): BOOLEAN;
{$IFC LibraryVersion <= 20}
VAR refInfo:
FS_Info;
{$ELSEC}
VAR refInfo:
Q_Info;
{$ENDC}
pPath:
TPPathname;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
pPath := @SELF.path;
{$IFC LibraryVersion <= 20}
Lookup(error, pPath^, refInfo);
{$ELSEC}
Quick_Lookup(error, pPath^, refInfo);
{$ENDC}
Exists := error <= 0;
END;
{$S SgCLAres}
{$S SgABCdat}
FUNCTION TFile.MemberBytes: INTEGER;
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
MemberBytes := 1;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgCLAcld}
PROCEDURE TFile.Rename(VAR error: INTEGER; newFileName: TFilePath);
{the volume of newFileName is ignored}
VAR pPath:
TPPathname;
vol:
TFilePath;
name:
TFilePath;
pEName:
TPEname;
{$IFC LibraryVersion > 20}
pPass:
TPEName;
{$ENDC}
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
pPath := @SELF.path;
SplitFilePath(newFileName, vol, name);
pEName := @name;
{$IFC LibraryVersion <= 20}
Rename_Entry(error, pPath^, pEName^);
{$ELSEC}
pPass := @SELF.password;
Rename_Secure(error, pPath^, pEName^, pPass^);
{$ENDC}
END;
{$S SgCLAres}
{$S SgCLAcld}
FUNCTION TFile.Scanner: TFileScanner;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
Scanner := SELF.ScannerFrom(0, [fRead, fWrite]);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgCLAres}
{$S sResDat}
FUNCTION TFile.ScannerFrom(firstToScan: LONGINT; manip: TAccesses): TFileScanner;
VAR s: TFileScanner;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
s := TFileScanner.CREATE(NIL, SELF, manip);
s.Seek(firstToScan);
ScannerFrom := s;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgCLAres}
{$S SgCLAcld}
FUNCTION TFile.VerifyPassword(VAR error: INTEGER; password: TPassword): BOOLEAN;
VAR pPath: TPPathname;
pPass: TPEName;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
{$IFC LibraryVersion <= 20}
error := -1293; {warning file is not password protected}
VerifyPassword := TRUE;
{$ELSEC}
pPath := @SELF.path;
pPass := @password;
Verify_Password(error, pPath^, pPass^);
VerifyPassword := error <= 0;
{$ENDC}
END;
{$S SgCLAres}
{$S SgCLAcld}
FUNCTION TFile.WhenModified(VAR error: INTEGER): LONGINT;
{$IFC LibraryVersion <= 20}
VAR refInfo:
FS_Info;
{$ELSEC}
VAR refInfo:
Q_Info;
{$ENDC}
pPath:
TPPathname;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
pPath := @SELF.path;
{$IFC LibraryVersion <= 20}
Lookup(error, pPath^, refInfo);
{$ELSEC}
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
IF object = NIL THEN
ABCBreak('TScanner.CREATE must be passed an already-allocated object by a subclass CREATE', 0);
SELF := TScanner(object);
WITH SELF DO
BEGIN
collection := itsCollection;
{$H-} position := Max(0, Min(collection.size+1, itsInitialPosition)); {$H+}
scanDone := FALSE;
IF scanDirection = scanForward THEN
BEGIN
increment := 1;
atEnd := position >= collection.size;
END
ELSE
BEGIN
increment := -1;
atEnd := position <= 1;
END;
END;
SELF.Seek(itsInitialPosition);
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S SgCLAdbg}
PROCEDURE TScanner.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('collection: TCollection');
Field('position: LONGINT');
Field('increment: INTEGER');
Field('scanDone: BOOLEAN');
Field('atEnd: BOOLEAN');
END;
{$S SgCLAres}
{$ENDC}
{$S SgABCdat}
FUNCTION TScanner.Advance(PROCEDURE DoToCurrent(anotherMember: BOOLEAN)): BOOLEAN;
VAR moreToScan: BOOLEAN;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
WITH SELF DO
IF scanDone THEN
moreToScan := FALSE
{don't reassign nextObject}
ELSE
BEGIN
IF atEnd THEN
moreToScan := FALSE
ELSE
BEGIN
moreToScan := TRUE;
position := position + increment;
IF increment > 0 THEN
atEnd := position >= collection.size
ELSE
atEnd := position <= 1;
END;
{$H-} DoToCurrent(moreToScan); {$H+}
END;
IF NOT moreToScan THEN
SELF.Free;
Advance := moreToScan;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TScanner.Allocate(slack: LONGINT);
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
SELF.collection.StartEdit(slack);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TScanner.Close;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TScanner.Compact;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
SELF.collection.StopEdit;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
PROCEDURE TScanner.Done;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
SELF.scanDone := TRUE;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TScanner.Open;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TScanner.Reverse;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
SELF.increment := - SELF.increment;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
PROCEDURE TScanner.Seek(newPosition: LONGINT);
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
WITH SELF DO
BEGIN
{$H-} position := Max(0, Min(collection.size+1, newPosition)); {$H+}
atEnd := ((position >= collection.size) AND (increment > 0)) OR
((position <= 1) AND (increment < 0));
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TScanner.Skip(deltaPos: LONGINT);
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
SELF.Seek(SELF.position + deltaPos);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sInit1}
END;
{$S SgCLAres}
METHODS OF TListScanner;
{$S sResDat}
FUNCTION
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
IF object = NIL THEN
object := NewOrRecycledObject(mainHeap, THISCLASS, availListScanner);
SELF := TListScanner(TScanner.CREATE(object, itsList, itsInitialPosition, itsScanDirection));
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
PROCEDURE TListScanner.Free;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
RecycleObject(SELF, availListScanner);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TListScanner.Append(object: TObject);
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
TList(SELF.collection).InsAt(SELF.position + 1, object);
SELF.position := SELF.position + 1;
(***** removed the following line: .InsAt should have set the collection size
{$H-} SELF.collection.size := Max(SELF.collection.size, SELF.position); {$H+}
*****)
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TListScanner.Delete(freeOld: BOOLEAN);
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
TList(SELF.collection).DelAt(SELF.position, freeOld);
WITH SELF DO
IF increment > 0 THEN
position := position - 1;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TListScanner.DeleteRest(freeOld: BOOLEAN);
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
WITH SELF DO
IF increment > 0 THEN
{$H-}
TList(collection).DelManyAt(position + 1, collection.size - position, freeOld)
ELSE
TList(collection).DelManyAt(1, position - 1, freeOld); {$H+}
WITH SELF DO
BEGIN
collection.size := position;
atEnd := TRUE;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
FUNCTION TListScanner.Obtain: TObject;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
Obtain := TList(SELF.collection).At(SELF.position);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TListScanner.Replace(object: TObject; freeOld: BOOLEAN);
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
TList(SELF.collection).PutAt(SELF.position, object, freeOld);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
FUNCTION TListScanner.Scan(VAR nextObject: TObject): BOOLEAN;
VAR actIndex:
LONGINT;
{an actual index into the list, INCLUDING the hole as part of the list}
(*
PROCEDURE AssignListScanVariable(anotherObject: BOOLEAN);
BEGIN
IF anotherObject THEN
nextObject := TList(SELF.collection).At(SELF.position)
ELSE
nextObject := NIL;
END;
*)
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
Scan := SELF.Advance(AssignListScanVariable);
{$IFC fTrace}EP;{$ENDC}
END;
VAR moreToScan: BOOLEAN;
BEGIN {speedier version}
{$IFC fTrace}BP(1);{$ENDC}
WITH SELF DO
IF scanDone THEN
moreToScan := FALSE
ELSE
BEGIN
IF atEnd THEN
moreToScan := FALSE
ELSE
BEGIN
moreToScan := TRUE;
position := position + increment;
IF increment > 0 THEN
atEnd := position >= collection.size
ELSE
atEnd := position <= 1;
END;
IF moreToScan THEN
BEGIN
IF position > collection.holeStart THEN
actIndex := position + collection.holeSize
ELSE
actIndex := position;
nextObject := TPObject(TpLONGINT(collection)^ + collection.dynStart
+ (4 * (actIndex - 1)))^;
END
ELSE
nextObject := NIL;
END;
IF NOT moreToScan THEN
SELF.Free;
Scan := moreToScan;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sInit1}
BEGIN
availListScanner := NIL;
END;
{$S SgCLAres}
METHODS OF TArrayScanner;
{$S SgABCdat}
FUNCTION TArrayScanner.CREATE(object: TObject; itsArray: TArray;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
IF object = NIL THEN
object := NewOrRecycledObject(mainHeap, THISCLASS, availArrayScanner);
SELF := TArrayScanner(TScanner.CREATE(object, itsArray, itsInitialPosition, itsScanDirection));
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TArrayScanner.Free;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
RecycleObject(SELF, availArrayScanner);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TArrayScanner.Append(pRecord: Ptr);
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
TArray(SELF.collection).InsAt(SELF.position + 1, pRecord);
SELF.position := SELF.position + 1;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TArrayScanner.Delete;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
TArray(SELF.collection).DelAt(SELF.position);
WITH SELF DO
IF increment > 0 THEN
position := position - 1;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TArrayScanner.DeleteRest;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
WITH SELF DO
IF increment > 0 THEN
{$H-}
TArray(collection).DelManyAt(position + 1, collection.size - position)
ELSE
TArray(collection).DelManyAt(1, position - 1); {$H+}
WITH SELF DO
BEGIN
collection.size := position;
atEnd := TRUE;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
FUNCTION TArrayScanner.Obtain: Ptr;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
Obtain := TArray(SELF.collection).At(SELF.position);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TArrayScanner.Replace(pRecord: Ptr);
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
TArray(SELF.collection).PutAt(SELF.position, pRecord);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
FUNCTION TArrayScanner.Scan(VAR pNextRecord: Ptr): BOOLEAN;
PROCEDURE AssignArrayScanVariable(anotherRecord: BOOLEAN);
BEGIN
IF anotherRecord THEN
pNextRecord := TArray(SELF.collection).At(SELF.position)
ELSE
pNextRecord := NIL;
END;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
Scan := SELF.Advance(AssignArrayScanVariable);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sInit1}
BEGIN
availArrayScanner := NIL;
END;
{$S SgCLAres}
METHODS OF TStringScanner;
{$S SgABCdat}
FUNCTION TStringScanner.CREATE(object: TObject; itsString: TString;
itsInitialPosition: LONGINT; itsScanDirection: TScanDirection)
: TStringScanner;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
IF object = NIL THEN
object := NewOrRecycledObject(mainHeap, THISCLASS, availStringScanner);
SELF := TStringScanner(TScanner.CREATE(object, itsString, itsInitialPosition, itsScanDirection));
SELF.actual := 0;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TStringScanner.Free;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
RecycleObject(SELF, availStringScanner);
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$S SgCLAdbg}
PROCEDURE TStringScanner.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('actual: LONGINT');
END;
{$S SgCLAres}
{$ENDC}
{$S SgABCdat}
{$S SgABCdat}
PROCEDURE TStringScanner.Replace(character: CHAR);
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
TString(SELF.collection).PutAt(SELF.position, character);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
FUNCTION TStringScanner.Scan(VAR nextChar: CHAR): BOOLEAN;
PROCEDURE AssignStringScanVariable(anotherChar: BOOLEAN);
BEGIN
IF anotherChar THEN
nextChar := TString(SELF.collection).At(SELF.position)
ELSE
nextChar := CHAR(0);
END;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
Scan := SELF.Advance(AssignStringScanVariable);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
FUNCTION TStringScanner.ReadArray(heap: THeap; bytesPerRecord: INTEGER): TArray;
VAR a: TArray;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
a := TArray.CREATE(NIL, heap, 0, bytesPerRecord);
XferContiguous(xRead, a, 2, SELF);
ReadArray := a;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
FUNCTION TStringScanner.ReadNumber(numBytes: SizeOfNumber): LONGINT;
VAR v:
RECORD
CASE INTEGER OF
1: (signExtension, short: INTEGER);
2: (long: LONGINT);
END;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
v.long := 0;
SELF.XferSequential(xRead, Ptr(ORD(@v)+4-numBytes), numBytes);
IF numBytes=2 THEN
IF v.short < 0 THEN
v.signExtension := -1;
ReadNumber := v.long;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
FUNCTION TStringScanner.ReadObject(heap: THeap): TObject;
VAR class: TClass;
object: TObject;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
class := TClass(SELF.ReadNumber(4));
object := NewObject(heap, class);
object.Read(SELF);
ReadObject := object;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TStringScanner.WriteArray(a: TArray);
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
XferContiguous(xWrite, a, 2, SELF);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TStringScanner.WriteNumber(value: LONGINT; numBytes: SizeOfNumber);
BEGIN
{$IFC fTrace}BP(3);{$ENDC}
SELF.XferSequential(xWrite, Ptr(ORD(@value)+4-numBytes), numBytes);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TStringScanner.WriteObject(object: TObject);
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
SELF.WriteNumber(ORD(object.Class), 4);
object.Write(SELF);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TStringScanner.XferContiguous(whichWay: xReadWrite; collection: TCollection);
VAR numToXfer: INTEGER;
BEGIN
{Transfer the size (as an INTEGER), class-specific fields, and members.
Do not recur on the members.
Do not transfer the class, the dynStart (=SizeOfClass), or the hole info (=zero).
When reading, append the elements that are read.
This only works for contiguous objects up to 32K members in size.}
{$IFC fTrace}BP(3);{$ENDC}
XferContiguous(whichWay, collection, 0, SELF);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TStringScanner.XferFields(whichWay: xReadWrite; object: TObject);
BEGIN
{Transfers the bits of a TObject, excluding the class pointer and any dynamic part}
{$IFC fTrace}BP(3);{$ENDC}
SELF.XferSequential(whichWay,
Ptr(ORD(TH(object)^) + SIZEOF(TObject)),
SizeOfClass(object.Class) - SIZEOF(TObject));
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TStringScanner.XferPString(whichWay: xReadWrite; pStr: TPString);
VAR size: Byte;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
IF whichWay = xWrite THEN
size := Length(pStr^);
SELF.XferSequential(whichWay, @size, 1);
SELF.XferSequential(whichWay, Ptr(ORD(pStr)+1), size);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TStringScanner.XferRandom(whichWay: xReadWrite; pFirst: Ptr; numBytes: LONGINT;
mode: TIOMode; offset: LONGINT);
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
CASE mode OF
fAbsolute: SELF.Seek(offset);
fRelative: SELF.Skip(offset);
END;
SELF.XferSequential(whichWay, pFirst, numBytes);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TStringScanner.XferSequential(whichWay: xReadWrite; pFirst: Ptr; numBytes: LONGINT);
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
WITH SELF, collection DO
BEGIN
{$H-} actual := Min(size - position, numBytes); {$H+}
{$H-} collection.EditAt(size + 1, 0); {$H+} {Maybe we should xfer in two steps instead}
END;
WITH SELF DO
BEGIN
{$H-} XferLeft(pFirst, Ptr(collection.AddrMember(position + 1)), actual); {$H+}
position := position + actual;
atEnd := position = collection.size;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sInit1}
BEGIN
availStringScanner := NIL;
END;
{$S SgCLAres}
METHODS OF TFileScanner;
{$S sResDat}
FUNCTION TFileScanner.CREATE(object: TObject; itsFile: TFile; manip: TAccesses): TFileScanner;
BEGIN
{$IFC fTrace}BP(5);{$ENDC}
IF object = NIL THEN
object := NewObject(itsFile.Heap, THISCLASS);
SELF := TFileScanner(TScanner.CREATE(object, itsFile, 0, scanForward));
SELF.actual := 0;
SELF.accesses := manip;
SELF.Open;
TFile(SELF.collection).scanners.InsLast(SELF);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgCLAres}
{$IFC fDebugMethods}
{$S SgCLAdbg}
PROCEDURE TFileScanner.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('accesses: Byte');
Field('refnum: INTEGER');
Field('error: INTEGER');
END;
{$S SgCLAres}
{$ENDC}
{$S SgABCdat}
PROCEDURE TFileScanner.FreeObject; {use FreeObject, rather than Free, so that we close the
file if the user says fs.FreeObject (as in
TDocManager.OpenSaved), as well as fs.Free}
BEGIN
{$IFC fTrace}BP(5);{$ENDC}
SELF.Close;
TFile(SELF.collection).scanners.DelObject(SELF, FALSE);
SUPERSELF.FreeObject;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TFileScanner.Free;
{Free frees the TFile as well, if no other scanners still exist}
VAR itsFile: TFile;
BEGIN
{$IFC fTrace}BP(5);{$ENDC}
itsFile := TFile(SELF.collection);
SELF.FreeObject;
IF itsFile.scanners.size = 0 THEN
itsFile.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TFileScanner.Allocate(slack: LONGINT);
VAR fsInfo:
FS_Info;
pages:
LONGINT;
actual:
LONGINT;
newErr:
INTEGER;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
Info(newErr, SELF.refnum, fsInfo);
WITH fsInfo DO
pages := ((size + slack + lpSize - 1) DIV lpSize) - ((pSize + lpSize - 1) DIV lpSize);
IF pages > 0 THEN
Allocate(newErr, SELF.refnum, TRUE, pages, actual);
IF (newErr <= 0) AND (actual < pages) THEN
Allocate(newErr, SELF.refnum, FALSE, pages - actual, actual);
{$H-} LatestError(newErr, SELF.error); {$H+}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TFileScanner.Close;
VAR newErr: INTEGER;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
Close_Object(newErr, SELF.refnum);
{$H-} LatestError(newErr, SELF.error); {$H+}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TFileScanner.Compact;
VAR newErr:
INTEGER;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
Compact(newErr, SELF.refnum);
{$H-} LatestError(newErr, SELF.error); {$H+}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TFileScanner.Delete;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
SELF.Skip(-1);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TFileScanner.DeleteRest;
VAR newErr:
INTEGER;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
Truncate(newErr, SELF.refnum);
{$H-} LatestError(newErr, SELF.error); {$H+}
WITH SELF DO
BEGIN
collection.size := position;
atEnd := TRUE;
END;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TFileScanner.Append(character: CHAR);
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
SELF.XferSequential(xWrite, Ptr(ORD(@character)+1), 1);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
FUNCTION TFileScanner.Obtain: CHAR;
VAR character: CHAR;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
SELF.XferRandom(xRead, Ptr(ORD(@character) + 1), 1, fRelative, -1);
Obtain := character;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
{$IFC LibraryVersion <= 20}
PROCEDURE TFileScanner.Open;
VAR pPath:
TPPathName;
itsFile:
TFile;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
itsFile := TFile(SELF.collection);
pPath := @itsFile.path;
{$H-} Open(SELF.error, pPath^, SELF.refnum, MSet(SELF.accesses)); {$H+}
ELSE
nextChar := CHAR(0);
END;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
Scan := SELF.Advance(AssignFileScanVariable);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
PROCEDURE TFileScanner.Seek(newPosition: LONGINT);
VAR dummy: INTEGER;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
SELF.XferRandom(xRead, @dummy, 0, fAbsolute, newPosition);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgABCdat}
PROCEDURE TFileScanner.Skip(deltaPos: LONGINT);
VAR dummy: INTEGER;
BEGIN
{$IFC fTrace}BP(2);{$ENDC}
SELF.XferRandom(xRead, @dummy, 0, fRelative, deltaPos);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
PROCEDURE TFileScanner.XferRandom(whichWay: xReadWrite; pFirst: Ptr; numBytes: LONGINT;
mode: TIOMode; offset: LONGINT);
VAR newErr:
INTEGER;
osMode:
IOMode;
fsInfo:
FS_Info;
sched_err: INTEGER;
BEGIN
{$IFC fTrace}BP(4);{$ENDC}
osMode := IOMode(mode);
WITH SELF DO {$H-}
IF error <= 0 THEN
BEGIN
CASE whichWay OF
xRead: BEGIN
Sched_Class(sched_err, FALSE);
Read_Data(newErr, refnum, ord(pFirst), numBytes, actual, osMode, offset);
Sched_Class(sched_err, TRUE);
END;
xWrite: BEGIN
Sched_Class(sched_err, FALSE);
Write_Data(newErr, refnum, ord(pFirst), numBytes, actual, osMode, offset);
Sched_Class(sched_err, TRUE);
collection.size := Max(position + actual, collection.size);
END;
END;
IF (newErr = 956) OR (newErr = 963) OR (newErr = 883) OR (newErr = 882) OR
(newErr = 848) THEN {EOF}
newErr := 0;
IF mode = fSequential THEN {do it fast}
position := position + actual
ELSE
{play it safe}
BEGIN
Info(newErr, refnum, fsInfo);
position := fsInfo.fMark;
collection.size := fsInfo.size;
END;
atEnd := position = collection.size;
LatestError(newErr, error); {$H+}
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sResDat}
PROCEDURE TFileScanner.XferSequential(whichWay: xReadWrite; pFirst: Ptr; numBytes: LONGINT);
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
SELF.XferRandom(whichWay, pFirst, numBytes, fSequential, 0);
{$IFC fTrace}EP;{$ENDC}
END;
{$S sInit1}
END;
{$S SgCLAres}
{$IFC compatibleLists} {Backward Compatibility}
METHODS OF TDynamicArray;
FUNCTION
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
IF ODD(bytesPerRecord) THEN
bytesPerRecord := bytesPerRecord + 1;
SELF := POINTER(ORD(TArray.CREATE(object, heap, initialSize, bytesPerRecord))); {NB reversed args}
Handle(SELF)^^ := ORD(THISCLASS);
SELF.EditAt(1, initialSize);
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TDynamicArray.BeSize(newSize: INTEGER);
BEGIN
SELF.EditAt(SELF.size + 1, newSize - SELF.size);
END;
FUNCTION TDynamicArray.Class: TClass; {So New- & Resize- DynObject will use correct object size}
BEGIN
Class := cArray;
END;
FUNCTION TDynamicArray.numRecords: INTEGER;
BEGIN
numRecords := SELF.size;
END;
{$S sInit1}
END;
{$S SgCLAres}
METHODS OF TIndexList;
FUNCTION TIndexList.CREATE(object: TObject; heap: THeap; initialSize: INTEGER): TIndexList;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
SELF := POINTER(ORD(TList.CREATE(object, heap, initialSize)));
Handle(SELF)^^ := ORD(THISCLASS);
SELF.EditAt(1, initialSize);
{$IFC fTrace}EP;{$ENDC}
END;
FUNCTION TIndexList.Class: TClass; {So New- & Resize- DynObject will use correct object size}
BEGIN
Class := cList;
END;
FUNCTION TIndexList.numElements: INTEGER;
BEGIN
numElements := SELF.size;
END;
{$S sInit1}
END;
{$S SgCLAres}
METHODS OF TLinkList;
FUNCTION TLinkList.CREATE(object: TObject; heap: THeap): TLinkList;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
SELF := POINTER(ORD(TList.CREATE(object, heap, 0)));
Handle(SELF)^^ := ORD(THISCLASS);
{$IFC fTrace}EP;{$ENDC}
END;
FUNCTION TLinkList.numElements: INTEGER;
BEGIN
numElements := SELF.size;
END;
{$S sInit1}
END;
{$S SgCLAres}
METHODS OF TBlockList;
FUNCTION TBlockList.CREATE(object: TObject; heap: THeap; itsMinBlockSize: INTEGER): TBlockList;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
SELF := POINTER(ORD(TList.CREATE(object, heap, 0)));
Handle(SELF)^^ := ORD(THISCLASS);
{$IFC fTrace}EP;{$ENDC}
END;
FUNCTION TBlockList.numElements: INTEGER;
BEGIN
numElements := SELF.size;
END;
{$S sInit1}
END;
{$S SgCLAres}
METHODS OF TFileStream;
FUNCTION TFileStream.CREATE(object: TObject; heap: THeap; path: S255; manip: TAccesses): TFileStream;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TFileStream(TFileScanner.CREATE(object, TFile.CREATE(NIL, heap, path, ''), manip));
{$IFC fTrace}EP;{$ENDC}
END;
FUNCTION TFileStream.Size: LONGINT;
BEGIN
{$IFC fTrace}BP(1);{$ENDC}
Size := SELF.collection.size;
{$IFC fTrace}EP;{$ENDC}
END;
{$S sInit1}
END;
{$S SgCLAres}
{$S SgCLAcld}
PROCEDURE FileDelete(path: S255);
VAR osPath:
Pathname;
error:
INTEGER;
BEGIN
osPath := path;
{ THIS IS THE SECOND TIME WE COPY THE STRING !!!! }
Kill_Object(error, osPath);
END;
{$S SgCLAres}
{$S SgCLAcld}
PROCEDURE FileLookup(VAR error: INTEGER; path: S255);
VAR refInfo:
FS_Info;
osPath:
Pathname;
BEGIN
osPath := path;
{ THIS IS THE SECOND TIME WE COPY THE STRING !!!! }
Lookup(error, osPath, refInfo);
END;
{$S SgCLAres}
{$S SgCLAcld}
PROCEDURE FileRename(oldPath, newPath: S255);
VAR osPath:
Pathname;
osEname:
E_Name;
error:
INTEGER;
centerHyphen:
INTEGER;
BEGIN
osPath := oldPath;
centerHyphen := pos('-{', newPath);
osEname := copy(newPath, centerHyphen+1, length(newPath)-centerHyphen);
Rename_Entry(error, osPath, osEname);
END;
{$S SgCLAres}
{$S SgCLAcld}
FUNCTION FileModified(path: S255): LONGINT;
VAR refInfo:
FS_Info;
osPath:
Pathname;
error:
INTEGER;
BEGIN
osPath := path;
{ THIS IS THE SECOND TIME WE COPY THE STRING !!!! }
Lookup(error, osPath, refInfo);
IF error <= 0 THEN
FileModified := refInfo.DTM
ELSE
FileModified := -1;
END;
{$S SgCLAres}
{$ENDC} {Backward Compatibility}
Although MarkHeap operates depth-first, it is NOT recursive. Thus, it can mark long chains of objects }
without causing stack expansion. If w.e => x, x.f => y and y.g => z, then while y is being scanned, }
x.f => w.e. Thus, when y returns to x for further marking starting after f, x can know where it will }
have to return to when its scan is complete. The comments below assume that the scan has reached y.g }
TYPE TOffsets = RECORD
objectOffset:
fieldOffset:
END;
INTEGER;
INTEGER;
firstFieldAddress: LONGINT; { @y^^, the address of y's first data field (usually a method-table ptr)}
lastFieldAddress: LONGINT; { The upper limit of the fieldAddress loop--the last 4-byte field of y }
mpPtr: TpLONGINT;
mp: LONGINT;
fieldOffset: INTEGER;
fieldAddress: LONGINT;
{ @y.g - @y^^ }
{ The address of the field y.g, which may or may not be a handle.
It increases by twos because a handle can start on any even address}
{ Two offsets representing @x.f: x - mpFirst & @x.f - @x^^.
A pointer to x.f will be stashed there while z is scanned,
in the form of two offsets (see "previous") }
previous: TOffsets;
BEGIN
hndlAddress: LONGINT;
goodHandleFound: BOOLEAN;
{ MarkHeap }
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
hz := THz(heap);
{ A pointer to the heap }
mpFirst := ORD(@hz^.argpPool);
{ The address of the first master pointer }
mpLast := mpFirst + (4 * (hz^.ipPoolMac - 1));
{ The address of the last master pointer }
fieldOffset := 0;
goodHandleFound := TRUE;
previous.objectOffset := 1;
{ The handle of y }
{ Mark the master pointer which points to the present object }
REPEAT
firstFieldAddress := mpPtr^;
{ The
blockPtr := TBk(firstFieldAddress - 4);
{ The
sizeInWords := blockPtr^.hdr.cw;
{ The
lastFieldAddress := firstFieldAddress + sizeInWords +
{ Scan the fields of the present object in search of a handle to an unmarked object }
WHILE ((fieldAddress <= lastFieldAddress) AND (NOT goodHandleFound)) DO
BEGIN
hndlAddress := TpLONGINT(fieldAddress)^;
{ Get what may be the address of a master pointer }
IF (hndlAddress >= mpFirst) THEN
IF (hndlAddress <= mpLast) THEN
IF (LIntAndLInt(hndlAddress - mpFirst, 3) = 0) THEN
BEGIN
{ if the address of the alleged master pointer lies between the }
{ addresses of the first and last master pointers, inclusive, and if }
{ the address of the alleged master pointer lies a multiple of 4 bytes }
{ (the length of a master pointer) from the address of the first }
{ master pointer, then the given address is the address of a master }
{ pointer (i.e. it is a valid handle).}
mpPtr := TpLONGINT(hndlAddress); { Get a handle on the validated master pointer }
mp := ORD(mpPtr^);
IF (mp >= 0) THEN { unmarked }
IF NOT (((mp >= mpFirst) AND (mp <= mpLast)) OR (mp = 1)) THEN
BEGIN { not on the free list; it must be in the heap proper }
goodHandleFound := TRUE;
{ A handle to an unmarked object has been found }
TOffsets(TpLONGINT(fieldAddress)^) := previous; { Save offsets in the
field y.g }
previous.fieldOffset := fieldOffset;
END;
mpAddress := hndlAddress;
END;
{ The handle of z }
fieldAddress := fieldAddress + 2;
fieldOffset := fieldOffset + 2;
END;
IF goodHandleFound THEN
{ y.g contained the handle of z }
BEGIN
mpPtr^ := mpPtr^ + $80000000;
{ Mark the master pointer of z }
fieldOffset := 0;
{ Prepare to scan z }
END
ELSE
BEGIN
{ Finished examining the fields of y. Prepare to return to x.f
hndlAddress := mpAddress;
{ The handle y will be put back into x.f
fieldOffset := previous.fieldOffset;
{ Restore fieldOffset to
mpAddress := mpFirst + previous.objectOffset;
{ Restore mpAddress to x
mpPtr := TpLONGINT(mpAddress);
{ The handle of y }
END;
END;
UNTIL previous.objectOffset = 1;
{ MarkHeap }
}
where it belongs }
@x.f - @x^^ }
}
{ until all the fields of the original object have been examined }
This procedure accepts a handle, obj, to an object and frees or reports that object (depending on the }
value of SweepHeap's parameter, report) if its master pointer is not marked. If, the }
object's master pointer is marked, then this procedure unmarks the object's master pointer but }
otherwise leaves the object alone. }
VAR mpAddress:
clsName:
hexOrd:
BEGIN
LONGINT;
{ the address of the master pointer specified by the handle obj }
TClassName; { the name of that class }
S8;
{ the handle of the object, as a hex string }
{ CollectGarbage }
mpAddress := ORD(obj);
tempPtr := TpLONGINT(obj);
{ get a handle of the right type on the given object OBJ }
IF (tempPtr^ < 0) THEN
BEGIN
{ if the given object OBJ is marked }
tempPtr := TpLONGINT(mpAddress);
{ Unmark the master pointer that points to the present object }
tempPtr^ := tempPtr^ - $80000000; { Note: 2^31 = $80000000 }
END
ELSE IF report THEN
BEGIN
WriteLn;
IF ValidObject(Handle(obj)) THEN
CpToCn(TPSliceTable(ClassPtr(Handle(obj))), TS8(clsName))
ELSE
clsName := '????????';
LIntToHex(ORD(obj), @hexOrd);
Write (CHR(7), 'Found garbage object $', hexOrd, ' of class ', clsName);
END
ELSE
FreeH(THz(heap), TH(obj)); { It is unmarked, i.e., garbage. Free it. }
END;
{ CollectGarbage }
BEGIN
{ SweepHeap }
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
EachObject(heap, CollectGarbage);
END;
{ SweepHeap }
{ ====================================== ABCBREAK ====================================== }
{$IFC fDbgObject}
PROCEDURE TallyZero; FORWARD;
{$ENDC}
{$S sError}
PROCEDURE ABCBreak{(s: S255; errCode: LONGINT)};
VAR asHex: S8;
BEGIN
{$IFC fDbgObject}
WriteLn;
Write(CHR(7), s);
{Beep}
IF errCode <> 0 THEN
BEGIN
LIntToHex(errCode, @asHex);
Write(': ', errCode:1, ' = $', asHex);
END;
WriteLn;
{Turn off all tracing, tallying, etc.}
tallyingCalls := FALSE;
TallyZero;
fTraceEnabled := FALSE;
defTraceCount := 0;
traceCount := defTraceCount;
returnToMain := TRUE;
EntDebugger(' ', 'Error caused ABCBreak call');
{$ELSEC}
HALT;
{$ENDC}
END;
{$S SgCLAcld}
{ ====================================== $D DECODING ====================================== }
{$IFC fTrace OR fDebugMethods}
{$S SgCLAdbg}
FUNCTION GetDollarD(pFrame: TppINTEGER;
VAR nameOfClass: TClassName; VAR nameOfMethod: S8; VAR nextPC: LONGINT): BOOLEAN;
LABEL 1;
VAR pname:
pPC:
pc:
startOfSegment:
endOfSegment:
pcl:
fBothClassAndProc:
TPByte;
TppINTEGER;
TpINTEGER;
TpLONGINT;
TpINTEGER;
TpLONGINT;
BOOLEAN;
PROCEDURE AdvancePC;
BEGIN
IF ORD(pc) >= ORD(endOfSegment) THEN
GOTO 1;
pc := TpInteger(ORD(pc)+2);
END;
BEGIN
{$IFC fMaxTrace}BP(1);{$ENDC}
{$IFC fMaxTrace}EP;{$ENDC}
pPC := TppINTEGER(ORD(pFrame) + 4);
pc := pPC^;
nameOfClass := '';
nameOfMethod := '';
nextPC := 0;
GetDollarD := FALSE;
IF ORD(pc) <> 0 THEN
BEGIN
{$R-} SwapIn(TPS8(pc)^); {$IFC fRngObject} {$R+} {$ENDC} {Be sure the code is swapped in}
startOfSegment := TpLONGINT(LIntAndLint(LONGINT(PC), $FFFE0000));
endOfSegment := TpINTEGER(LONGINT(startOfSegment) + LIntAndLint(startOfSegment^, $00FFFFFF) {length} );
{We add the -1 to the following tests so that the things we are searching for don't
appear in the body of the procedure.}
WHILE (pc^-1) <> ($4E5E-1) DO
{search for UNLK A6}
IF ORD(pc) >= ORD(endOfSegment) THEN
GOTO 1
ELSE
pc := TpINTEGER(ORD(pc)+2);
WHILE ((pc^-1) <> ($4E75-1)) AND
((pc^-1) <> ($4ED0-1)) DO
{search for RTS or JMP (A0)}
IF ORD(pc) >= ORD(endOfSegment) THEN
GOTO 1
ELSE
pc := TpINTEGER(ORD(pc)+2);
nextPC := ORD(pc);
GetDollarD := TRUE;
pname := TPByte(ORD(pc)+3);
fBothClassAndProc := pname^ < 0;
pname := TPByte(ORD(pname)-1);
CopyName(nameOfMethod);
IF fBothClassAndProc THEN
1:
END;
{$ENDC}
CopyName(S8(nameOfClass))
ELSE
nameOfClass := '';
END;
*** NB ***
Is this Sg necessary?
PROCEDURE TallyStart;
VAR timeNow:
LONGINT;
i:
INTEGER;
arrSize:
INTEGER;
elapsed:
LONGINT; (*^*)
BEGIN
IF tallies = NIL THEN
BEGIN
{array size must be <= maxTallies; imposed by declaration of tallies global variable.}
arrSize := Min(numMethods, maxTallies);
tallies := THTallies(TArray.CREATE(NIL, mainHeap, arrSize, SIZEOF(TTally)));
TArray(tallies).InsNullsAt(1, arrSize);
elapsed := 0;(*^*)
END
ELSE {continuing}
elapsed := stopTime - startTime;(*^*)
timeNow := MicroTimer;
startTime := timeNow - elapsed; (*^*)
FOR i := 0 TO tabLevel DO
{BP's already passed}
traceTimes[i] := timeNow; (*^*)
stopTime := timeNow;
tallyingCalls := TRUE;
END;
PROCEDURE TallyZero;
BEGIN
IF tallies <> NIL THEN
END;
BEGIN
Free(TArray(tallies));
tallies := NIL;
END;
END;
ELSE
BEGIN
epPC := pc;
count:= 1;
microseconds := micSecs;
END;
END
ELSE
BEGIN
ABCBreak('Tally table full--more non-method procedures had EP''s than expected',
tallies^^.header.size);
tallyingCalls := FALSE;
END;
PROCEDURE TallyReport;
VAR totalCalls:
totalTime:
callees:
slot:
calls:
micSecs:
roundoff:
i:
j:
sortKeys:
segCount:
segTime:
pc:
sortBy:
swapem:
sloti:
slotj:
pctg:
elapsed:
segName:
segNum:
cState:
wantCalled:
clsName:
mthName:
nextPC:
inStr:
hexPC:
LONGINT;
LONGINT;
INTEGER;
INTEGER;
INTEGER;
LONGINT;
LONGINT;
INTEGER;
INTEGER;
THIdxArray;
ARRAY [0..127] OF LONGINT;
ARRAY [0..127] OF LONGINT;
LONGINT;
INTEGER;
BOOLEAN;
INTEGER;
INTEGER;
INTEGER;
LONGINT;
S8;
INTEGER;
TConvResult;
BOOLEAN;
TClassName;
S8;
LONGINT;
S255;
S8;
PROCEDURE ReadSegNames;
CONST
bSegTable = $9A;
bEOFMark = $00;
bModuleName = $80;
bCodeBlock = $85;
modNameSkip = 8; {# bytes to skip in module name block, to get segment name}
allBlanks = '
'; {8 blanks}
blankSeg = 'BLANKSEG';
TYPE
SegTblEntry = RECORD
SegName:
PACKED ARRAY[1..8] OF CHAR;
SegNumber:
INTEGER;
Version1:
LONGINT;
Version2:
LONGINT;
END;
VAR prcsInfo:
error:
aFile:
scanner:
blkType:
blkSize:
nSegments:
segblk:
addr:
i:
ProcInfoRec;
INTEGER;
TFile;
TFileScanner;
LONGINT;
LONGINT;
LONGINT;
SegTblEntry;
LONGINT;
INTEGER;
BEGIN
Info_Process(error, My_id, prcsInfo);
IF error <= 0 THEN
BEGIN
segName := allBlanks;
segNames := TArray.CREATE(NIL, mainHeap, 127, SIZEOF(S8));
segNames.InsNullsAt(1, 127);
aFile := TFile.CREATE(NIL, mainHeap, prcsInfo.progPathName, '');
scanner := TFileScanner.CREATE(NIL, aFile, [fRead]);
WriteLn('Reading segment numbers and names from ', prcsInfo.progPathName);
WriteLn;
REPEAT
blkType := scanner.ReadNumber(1);
blkSize := scanner.ReadNumber(3) - 4;
CASE blkType OF
bSegTable:
BEGIN
nSegments := scanner.ReadNumber(2);
blkSize := blkSize-2;
FOR i := 1 TO nSegments DO
BEGIN
scanner.XferSequential(xRead, @segblk, SIZEOF(SegTblEntry));
blkSize := blkSize - scanner.actual;
XferLeft(Ptr(@segblk.segName), Ptr(ORD(@segName)+1), 8);
segNames.PutAt(segblk.SegNumber, @segName);
END;
END;
bModuleName:
BEGIN
scanner.Skip(modNameSkip);
blkSize := blkSize-modNameSkip;
scanner.XferSequential(xRead, Ptr(ORD(@segName)+1), 8);
blkSize := blkSize - scanner.actual;
IF segName = allBlanks THEN
segName := blankSeg;
END;
bCodeBlock:
BEGIN
addr := scanner.ReadNumber(4);
blkSize := blkSize - 4;
segNames.PutAt(addr DIV $20000, @segName);
END;
END;
scanner.Skip(blkSize);
UNTIL scanner.atEnd OR (blkType = bEOFMark);
END;
scanner.Close;
END;
(**********
PROCEDURE ReadSegNames;
LABEL
1;
VAR prcsInfo:
error:
progVolume:
fileName:
progExt:
ProcInfoRec;
INTEGER;
TFilePath;
TFilePath;
TFilePath;
segNameFile:
i:
segName:
segNum:
1:
TEXT;
INTEGER;
S8;
INTEGER;
BEGIN
Info_Process(error, My_id, prcsInfo);
IF error <= 0 THEN
BEGIN
i := Length(prcsInfo.progPathName);
WHILE i > 0 DO
IF (prcsInfo.progPathName[i] = '}') OR (prcsInfo.progPathName[i] = '.') THEN
GOTO 1
ELSE
i := i - 1;
IF i > 0 THEN
filename := Concat(Copy(prcsInfo.progPathName, 1, i), 'SegNames.Text');
Reset(segNameFile, fileName);
i := IoResult;
IF i > 0 THEN
WriteLn('Unable to open ', fileName, ' because of error number ', i:1)
ELSE
BEGIN
WriteLn('Reading segment numbers and names from ', fileName);
WriteLn;
segNames := TArray.CREATE(NIL, mainHeap, 127, SIZEOF(S8));
segNames.InsNullsAt(1, 127);
WHILE (i = 0) AND NOT Eof(segNameFile) DO
BEGIN
segNum := 0;
ReadLn(segNameFile, segNum, inStr);
i := IoResult;
IF (i <= 0) AND (1 <= segNum) AND (segNum <= 127) THEN
BEGIN
TrimBlanks(@inStr);
segName := Copy(Concat(inStr, '
'), 1, 8);
segNames.PutAt(segNum, @segName);
END
ELSE
IF i > 0 THEN
WriteLn('*** IoError number ', i:1, ' reading ', fileName)
ELSE
IF NOT Eof(segNameFile) THEN
WriteLn('*** Bad segment number: ', segNum:1, ' in file ', fileName);
END;
segName := '????????';
END;
**********)
WriteLn;
WriteLn;
Close(segNameFile);
END;
PROCEDURE WriteName;
BEGIN
IF mthName = '' THEN
BEGIN
LIntToHex(pc, @hexPC);
Write('$', hexPC, '
');
END
ELSE
IF clsName = '' THEN
Write(mthName, '
')
ELSE
Write(clsName, '.', mthName);
END;
FUNCTION TallyRange(pc1, pc2: LONGINT): INTEGER;
VAR slot:
INTEGER;
BEGIN
{If this proves too slow, make the sortarray by PC and binary search it}
FOR slot := 1 TO tallies^^.header.size DO
WITH tallies^^.recs[slot] DO
IF count > 0 THEN
IF pc1 < epPC THEN
IF epPC <= pc2 THEN
BEGIN
TallyRange := slot;
EXIT(TallyRange);
END;
TallyRange := 0;
END;
PROCEDURE SwapIn(valueString: S8);
BEGIN
END;
BEGIN
FOR j := tabLevel - 1 DOWNTO 0 DO (*^*)
BEGIN
(*
SEGMENT USAGE');
WriteLn('No. of calls
WriteLn('-----------WriteLn;
% of time
---------
Segment
-------
SegSize
-------
Seg#');
----');
',
REPEAT
WriteLn;
WriteLn;
Write('Report procedure executions sorted by (C = # Calls; T = % of Time; S = Segment)? ');
ReadLn(inStr);
StrUpperCased(@inStr);
TrimBlanks(@inStr);
IF inStr = '' THEN
sortBy := -1
ELSE
IF inStr[1] = 'C' THEN
sortBy := 1
ELSE
IF inStr[1] = 'T' THEN
sortBy := 2
ELSE
IF inStr[1] = 'S' THEN
sortBy := 3
ELSE
sortBy := 0;
IF sortBy > 0 THEN
BEGIN {sortBy > 0}
sortKeys := MakeIdxArray(callees, FALSE);
{$R-}
WITH sortKeys^^, tallies^^ DO
BEGIN {with}
i := 0;
FOR slot := 1 TO header.size DO
IF recs[slot].count > 0 THEN
BEGIN
i := i + 1;
records[i] := slot;
END;
FOR i := 1 TO callees-1 DO
BEGIN
sloti := records[i];
FOR j := i+1 TO callees DO
BEGIN
slotj := records[j];
CASE sortBy OF
1: swapem := recs[sloti].count > recs[slotj].count;
2: swapem := recs[sloti].microseconds > recs[slotj].microseconds;
3: swapem := TpINTEGER(@recs[sloti].epPC)^ DIV 2 >
TpINTEGER(@recs[slotj].epPC)^ DIV 2;
END;
IF swapem THEN
BEGIN
records[i] := slotj;
records[j] := sloti;
sloti := records[i];
slotj := records[j];
END;
END;
END;
END; {with}
{$IFC fRngObject}{$R+}{$ENDC}
WriteLn('No. of calls
WriteLn('-----------WriteLn;
% of time
---------
Routine name
-----------------
PC
--------
Segment');
-------');
j := TpINTEGER(@pc)^ DIV 2;
IF sortBy = 3 THEN {if by segment}
IF i < callees THEN {if not first line printed}
IF j <> segNum THEN {if different from segment of previous line}
WriteLn; {then leave a blank line}
segNum := j;
Write(calls:8, ' ....... ');
pctg := (LONGINT(micSecs) * 100 + roundOff) DIV totalTime;
IF pctg = 0 THEN
Write('
')
ELSE
Write(pctg:3, '%');
Write(' ... ');
IF GetDollarD(TppINTEGER(ORD(@pc)-4), clsName, mthName, nextPC) THEN;
WriteName;
LIntToHex(pc, @hexPC);
Write('
', hexPC);
IF segNames = NIL THEN
Write(segNum:10)
ELSE
BEGIN
segName := TPString(segNames.At(segNum))^;
IF segName = '????????' THEN
Write(segNum:10)
ELSE
Write('
', segName);
END;
WriteLn;
IF CheckKeyPress('Tally and Time Listing') THEN
i := 1;
END; {for i}
TArray(sortKeys).Free;
END; {IF sortBy > 0}
UNTIL sortBy < 0;
IF segNames <> NIL THEN {segNames will be non-NIL except in case of an IO error}
REPEAT
Write('List procedures that were and weren''t called in segment [name or number]? ');
ReadLn(inStr);
TrimBlanks(@inStr);
StrUpperCased(@inStr);
IF inStr = '?' THEN
BEGIN
WriteLn('List of all segments used by application:');
i := 0; {# output so far}
FOR segnum := 1 TO 127 DO
BEGIN
segname := TPString(segNames.At(segnum))^;
IF segname <> '' THEN
BEGIN
Write(segnum:3, ':', segname, ' ');
i := i+1;
IF i MOD 5 = 0 THEN
WriteLn;
END;
END;
WriteLn;
END
ELSE
IF inStr <> '' THEN
BEGIN
StrToInt(@inStr, segNum, cState);
IF cState <> cvValid THEN
BEGIN
segNum := 0;
FOR i := 1 TO 127 DO
BEGIN
segName := TPString(segNames.At(i))^;
StrUpperCased(@segName);
IF segName = inStr THEN
segNum := i;
END; {For i}
END {invalid number}
ELSE IF (segNum>=1) AND (segNum<=127) THEN{make sure the segment number is OK}
BEGIN
segName := TPString(segNames.At(segNum))^;
IF segName = '' THEN
segNum := 0;
END
ELSE
segNum := 0;
IF segNum = 0 THEN
WriteLn('No such segment')
ELSE
FOR wantCalled := TRUE DOWNTO FALSE DO
BEGIN
WriteLn;
Write('PROCEDURES THAT WERE ');
IF wantCalled THEN
Write('CALLED')
ELSE
Write('NOT CALLED OR HAD NO BP/EP');
Write(' IN SEGMENT');
IF segNames <> NIL THEN
Write(': ', TPString(segNames.At(segNum))^);
WriteLn(' #', segNum:1, '--');
WriteLn;
pc := segNum * $20000;
j := 0;
WHILE GetDollarD(TppINTEGER(ORD(@pc)-4), clsName, mthName, nextPC) DO
BEGIN
IF (TallyRange(pc, nextPC) > 0) = wantCalled THEN
BEGIN
WriteName;
Write('
');
j := j + 1;
IF j = 4 THEN
BEGIN
j := 0;
WriteLn;
END;
END;
pc := nextPC;
IF CheckKeyPress('Segment Listing') THEN
pc := 0;
END;
WriteLn;
WriteLn;
END; {FOR wantCalled}
END; {inStr <> ''}
UNTIL inStr = '';
END; {totalCalls > 0}
WriteLn;
END;
{$ENDC}
{ ============================================================================================= }
END;
FUNCTION ParseNumber: LONGINT;
VAR k:
LONGINT;
cState: TConvResult;
BEGIN
StrToLint(@token, k, cState);
IF cState = cvValid THEN
ParseNumber := k
ELSE
FoundUnexpected(token, 'a number');
NextToken;
END;
PROCEDURE ParseField; FORWARD;
PROCEDURE ParseType(inhibit: BOOLEAN);
VAR typeName:
S8;
upName:
S8;
alphaName:
BOOLEAN;
word:
S8;
lowerBound:
INTEGER;
upperBound:
INTEGER;
pp:
INTEGER;
i:
INTEGER;
len:
INTEGER;
wasInhibited:
BOOLEAN;
BEGIN
wasInhibited := inhibited;
IF inhibit THEN
inhibited := TRUE;
typeName := token;
upName := token;
StrUpperCased(@upName);
alphaName := alpha;
NextToken;
IF NOT alphaName THEN
FoundUnexpected(typeName, 'typename')
ELSE
IF upName = 'RECORD' THEN
BEGIN
REPEAT
ParseField;
word := token;
StrUpperCased(@word);
UNTIL (word = 'END') OR (word = '');
Expect('END');
END
ELSE
IF upName = 'ARRAY' THEN
BEGIN
Expect('[');
lowerBound := ParseNumber;
Expect('.');
Expect('.');
upperBound := ParseNumber;
Expect(']');
pp := p;
Expect('OF');
ParseType(TRUE);
IF NOT inhibited THEN
FoundType('ARRAY', yArray, 0, lowerBound, upperBound, Copy(inStr, pp, start - pp));
END
ELSE
IF upName = 'STRING' THEN
BEGIN
Expect('[');
len := ParseNumber;
Expect(']');
IF NOT inhibited THEN
FoundType('STRING', yString, len + 1, 0, 0, '');
END
ELSE
IF upName = 'BOOLEAN' THEN
BEGIN
IF NOT inhibited THEN
FoundType(typeName, yBoolean, 1, 0, 0, '');
END
ELSE
IF upName = 'CHAR' THEN
BEGIN
IF NOT inhibited THEN
FoundType(typeName, yChar, 2, 0, 0, '')
END
ELSE
IF upName = 'BYTE' THEN
BEGIN
IF NOT inhibited THEN
FoundType(typeName, yByte, 1, 0, 0, '')
END
ELSE
IF upName = 'HEXBYTE' THEN
BEGIN
IF NOT inhibited THEN
FoundType(typeName, yHexByte, 1, 0, 0, '')
END
ELSE
IF upName = 'INTEGER' THEN
BEGIN
IF NOT inhibited THEN
FoundType(typeName,
END
ELSE
IF upName = 'HEXINTEG' THEN
BEGIN
IF NOT inhibited THEN
FoundType(typeName,
END
ELSE
IF upName = 'LONGINT' THEN
BEGIN
IF NOT inhibited THEN
FoundType(typeName,
END
ELSE
IF upName = 'REAL' THEN
BEGIN
IF NOT inhibited THEN
FoundType(typeName,
END
ELSE
IF upName = 'POINT' THEN
BEGIN
IF NOT inhibited THEN
FoundType(typeName,
END
ELSE
IF upName = 'PTR' THEN
BEGIN
IF NOT inhibited THEN
FoundType(typeName,
END
ELSE
IF upName = 'LONGREAL' THEN
BEGIN
IF NOT inhibited THEN
FoundType(typeName,
END
ELSE
IF upName = 'LPOINT' THEN
BEGIN
IF NOT inhibited THEN
FoundType(typeName,
END
yInteger, 2, 0, 0, '')
yHexInteger, 1, 0, 0, '')
yLongInt, 4, 0, 0, '')
yReal, 4, 0, 0, '')
yPoint, 4, 0, 0, '')
yPtr, 4, 0, 0, '')
yLongReal, 8, 0, 0, '')
yLPoint, 8, 0, 0, '')
ELSE
IF upName = 'RECT' THEN
BEGIN
IF NOT inhibited THEN
FoundType(typeName, yRect, 8, 0, 0, '')
END
ELSE
IF upName = 'LRECT' THEN
BEGIN
IF NOT inhibited THEN
FoundType(typeName, yLRect, 16, 0, 0, '')
END
ELSE
BEGIN
IF CiOfCn(upName) > 0 THEN
BEGIN
word := token;
StrUpperCased(@word);
IF word = 'OF' THEN
BEGIN
pp := p;
NextToken;
ParseType(TRUE);
IF NOT inhibited THEN
FoundType(typeName, yObject, SIZEOF(Handle), 0, 0, Copy(inStr, pp, start - pp));
END
ELSE
IF NOT inhibited THEN
FoundType(typeName, yObject, SIZEOF(Handle), 0, 0, '');
END
ELSE
FoundUnexpected(typeName, 'typename');
END;
inhibited := wasInhibited;
END;
PROCEDURE ParseField;
BEGIN
IF NOT alpha THEN
BEGIN
FoundUnexpected(token, 'var name');
NextToken;
END
ELSE
BEGIN
IF NOT inhibited THEN
FoundName(token);
NextToken;
END;
Expect(':');
ParseType(FALSE);
IF token = ';' THEN
NextToken
ELSE
IF (token <> '') AND (token <> 'END') THEN
FoundUnexpected(token, '; or END');
END;
BEGIN
inhibited := FALSE;
p := 1;
eoi := Length(inStr);
Insert(' ', inStr, Length(inStr) + 1); {So that inStr[eoi+1] won't blow up}
NextToken;
WHILE token <> '' DO
ParseField;
END;
PROCEDURE WriteDRecord{(numLevels: INTEGER; hDRecord: Handle; posInDRecord: INTEGER;
PROCEDURE SupplyFields(PROCEDURE Field(nameAndType: S255)))};
VAR fieldInDRecord: INTEGER;
PROCEDURE WrCkAbort;
BEGIN
IF KeyPress THEN
BEGIN
WrStr('...abort...');
EXIT(WriteDRecord);
END;
END;
PROCEDURE DeclName(token: S8);
BEGIN
WrCkAbort;
WrStr(Concat(token, ': '));
END;
PROCEDURE SkipName(token: S8);
BEGIN
WrCkAbort;
END;
PROCEDURE DeclBad(token, wanted: S8);
BEGIN
WrCkAbort;
WrLn;
WrStr('<<The Field proc expected:');
WrStr(Concat(' ''', wanted, ''' '));
WrStr('but encountered:');
WrStr(Concat(' ''', token, '''>>'));
END;
PROCEDURE DeclType(token: S8; typeCode: TTypeCode; numBytes: INTEGER;
lowerBound, upperBound: INTEGER; memberTypeStr: S255); FORWARD;
PROCEDURE DeclArray(token: S8; lowerBound, upperBound: INTEGER; memberTypeStr: S255);
VAR str1:
S8;
str2:
S8;
i:
INTEGER;
origPos:
INTEGER;
BEGIN
IF Odd(posInDRecord) THEN
posInDRecord := posInDRecord + 1;
IntToStr(lowerBound, @str1);
IntToStr(upperBound, @str2);
WrStr(Concat(token, ' [', str1, '..', str2, '] = {'));
FOR i := lowerBound TO upperBound DO
BEGIN
IF i > lowerBound THEN
WrStr(', ');
origPos := posInDRecord;
IntToStr(i, @str1);
ParseDecl(CONCAT(str1, ': ', memberTypeStr), DeclName, DeclType, DeclBad);
(*****
IF Odd(posInDRecord) THEN
posInDRecord := posInDRecord + 1;
*****)
END;
WrStr('}');
END;
PROCEDURE DeclType(token: S8; typeCode: TTypeCode; numBytes: INTEGER;
lowerBound, upperBound: INTEGER; memberTypeStr: S255);
TYPE
TAlias =
RECORD
CASE TTypeCode OF
yByte:
(asByte:
Byte);
yChar:
(asChar:
CHAR);
yInteger:
(asInteger: INTEGER);
yLongInt:
(asLongInt: LONGINT);
yLPoint:
(asLPoint: FakeLPoint);
yLRect:
(asLRect:
yObject:
(asObject:
yPoint:
(asPoint:
yReal:
(asReal:
yRect:
(asRect:
yString:
(asString:
END;
^TAlias;
{a bona
TObject;
S255;
INTEGER;
FakeLRect);
TObject);
FakePoint);
REAL);
FakeRect);
S255);
VAR alias:
fide use for aliasing instead of typecasting}
obj:
str:
i:
BEGIN
IF typeCode = yArray THEN
BEGIN
DeclArray(token, lowerBound, upperBound, memberTypeStr);
EXIT(DeclType);
END;
IF token <> '' THEN
WrStr(Concat(token, ' = '));
IF numBytes > 1 THEN
IF Odd(posInDRecord) THEN
posInDRecord := posInDRecord + 1;
alias := POINTER(ORD(hDRecord^) + posInDRecord); {Careful, this is a relocatable location!}
str := '';
CASE typeCode OF
yPtr:
BEGIN
LIntToHex(alias^.asLongInt, @str);
str := Concat('$', str);
END;
yBoolean:
IF alias^.asByte = ORD(FALSE) THEN
str := 'FALSE'
ELSE
str := 'TRUE';
yByte:
IntToStr(alias^.asByte, @str);
yHexByte:
BEGIN
LIntToHex(alias^.asByte, @str);
str := CONCAT('$', Copy(str, 7, 2));
END;
yChar:
BEGIN
str := 'A';
str[1] := alias^.asChar;
END;
yInteger:
IntToStr(alias^.asInteger, @str);
yHexInteger:BEGIN
LIntToHex(alias^.asInteger, @str);
yLongInt:
yLPoint:
yLRect:
yObject:
yPoint:
yRect:
yString:
yReal:
OTHERWISE
END;
WrCkAbort;
IF str <> '' THEN
WrStr(Concat(str, ' '));
posInDRecord := posInDRecord + numBytes;
END;
PROCEDURE DebugField(nameAndType: S255);
BEGIN
IF nameAndType <> '' THEN
BEGIN
fieldInDRecord := fieldInDRecord + 1;
total := Length(str);
start := 1;
WHILE start <= total DO
BEGIN
len := total - start + 1;
maxLen := outputRMargin - currXPos;
IF len > maxLen THEN
BEGIN
len := maxLen;
WHILE (len > 0) AND (str[len] <> ' ') DO
len := len - 1;
IF (len = 0) AND (currXPos = outputIndent) THEN
len := maxLen;
END;
IF len > 0 THEN
BEGIN
Write(Copy(str, start, len));
currXPos := currXPos + len;
start := start + len;
END;
IF (currXPos >= outputRMargin) OR (start <= total) THEN
WrLn;
END;
END;
PROCEDURE WrLn;
BEGIN
WriteLn;
IF outputIndent > 0 THEN
BEGIN
Write(' ':outputIndent);
currXPos := outputIndent;
END
ELSE
currXPos := 0;
END;
WriteLn;
END;
(* commented out and should be removed if paslib bug has been fixed
{ flush characters; because of PASLIB bug, also stop when user types a ~ }
ch := ' ';
WHILE KeyPress AND (ch<>'~') DO
IF EOLn THEN
ReadLn
ELSE
Read(ch);
*)
CheckKeyPress := TRUE;
END
ELSE
CheckKeyPress := FALSE;
END;
{$IFC fDebugMethods}
PROCEDURE WrObj(object: TObject; numLevels: INTEGER; memberTypeStr: S255);
BEGIN
WriteLn;
currXPos := 0;
outputIndent := 0;
IF ValidObject(Handle(object)) THEN
BEGIN
object.Debug(numLevels, memberTypeStr);
IF CheckKeyPress('Display of the object') THEN;
END
ELSE
Write('Not an object: ', ORD(object):1);
END;
{$ENDC}
{$S SgCLAini}
PROCEDURE DumpHeap(heap: THeap; wantedSTP: LONGINT; wantedReference: LONGINT; fPrintSelf: BOOLEAN);
VAR hz:
THz;
cb:
TC;
hndl:
Handle;
obj:
TObject;
heapSize:
LONGINT;
numObjects:
LONGINT;
{Clascal objects only}
objOvhdSize:
LONGINT;
{includes master, header, and class pointer}
objDataSize:
LONGINT;
numOther:
LONGINT;
{Non-Clascal objects}
otherSize:
LONGINT;
numFree:
LONGINT;
freeSize:
bigFreeSize:
bk:
dumpIt:
valid:
offset:
base:
hStr:
class:
className:
BEGIN
WriteLn;
LONGINT;
LONGINT;
TBk;
BOOLEAN;
BOOLEAN;
INTEGER;
LONGINT;
S8;
TClass;
TClassName;
cb := bk^.cwFree * 2;
IF cb <= 0 THEN
BEGIN
WriteLn('FREE BLOCK ', ORD(bk):1, ' HAS LENGTH', cb);
EXIT(DumpHeap);
END;
CASE bk^.hdr.tybk OF
tybkStd:
BEGIN
{$IFC LibraryVersion <= 20}
hndl := Handle(ORD(hz) + bk^.oh);
{$ELSEC}
hndl := Handle(ORD(@hz^.argpPool) + (LONGINT(bk^.bp.ip)*4));
{$ENDC}
valid := ValidObject(hndl);
IF wantedSTP > 0 THEN
IF valid THEN
{looks like a class pointer; pray that it is!}
dumpIt := %_InObCp(ORD(hndl), wantedSTP)
ELSE
dumpIt := FALSE
ELSE
IF wantedReference <> 0 THEN
BEGIN
offset := 0;
base := ORD(hndl^);
WHILE (offset < cb) AND (TpLONGINT(base + offset)^ <> wantedReference) DO
offset := offset + 2;
dumpIt := offset < cb;
END
ELSE
dumpIt := TRUE;
IF dumpIt THEN
BEGIN
LIntToHex(ORD(hndl), @hStr);
Write('$', hStr, cb:6, ': ');
IF bk <> TBk(ORD(hndl^) - 4) THEN
BEGIN
WriteLn('INCORRECT BACK POINTER FOR bk = ', ORD(bk):1);
EXIT(DumpHeap);
END;
IF valid THEN
BEGIN
obj := TObject(hndl);
currXPos := outputIndent;
{$IFC fDebugMethods}
IF fPrintSelf THEN
obj.Debug(1, '')
ELSE
obj.Debug(0, '');
{$ELSEC}
class := obj.Class;
CpToCn(TPSliceTable(class), TS8(className));
TrimBlanks(@className);
Write(className);
{$ENDC}
numObjects := numObjects + 1;
objOvhdSize := objOvhdSize + 12; {master=4, header=4, classPtr=4}
objDataSize := objDataSize + cb-4;
{classPtr=4}
END
ELSE
BEGIN
numOther := numOther + 1;
otherSize := otherSize + cb;
Write('???');
END;
WriteLn;
END;
bk := TBk(ORD(hndl^) - 4); {in case the heap compacted during obj.Debug}
END;
tybkFree:
BEGIN
numFree := numFree + 1;
freeSize := freeSize + cb;
IF cb > bigFreeSize THEN
bigFreeSize := cb;
END;
OTHERWISE
BEGIN
numOther := numOther + 1;
otherSize := otherSize + cb;
END;
END;
bk := TBk(ORD(bk) + cb);
IF CheckKeyPress('HeapDump') THEN
EXIT(DumpHeap);
END;
WriteLn;
IF numObjects > 0 THEN
BEGIN
WriteLn('Number of Clascal objects:
', numObjects:6);
IF wantedReference = 0 THEN
BEGIN
WriteLn('Bytes in their headers & masters: ', objOvhdSize:12);
WriteLn('Bytes in their records:
', objDataSize:12);
IF objDataSize+objOvhdSize > 0 THEN
WriteLn('Header and master overhead:
',
(100 * objOvhdSize) DIV (objDataSize+objOvhdSize):5, '%');
END;
WriteLn;
END;
IF (wantedSTP <= 0) AND (wantedReference = 0) THEN
BEGIN
WriteLn('Number of free blocks:
', numFree:6);
WriteLn('Largest free block:
', bigFreeSize:6);
WriteLn('Bytes in free blocks:
', freeSize:12);
WriteLn;
WriteLn('Number of other blocks:
', numOther:6);
WriteLn('Bytes in those blocks:
', otherSize:12);
WriteLn;
WriteLn('Other overhead:
', heapSize-objOvhdSize-objDataSize-freeSize-otherSize:12);
WriteLn('Total heap size in bytes:
', heapSize:12);
WriteLn;
END;
END;
{$S SgCLAini}
PROCEDURE GoKitBug; {intended to be called from LisaBug}
BEGIN
EntDebugger(' ', 'Called from GoKitBug');
END;
{$S SgCLAini}
PROCEDURE EntDebugger{(inputStr, enterReason: S255)};
LABEL 99;
CONST
null = CHR(0);
VAR token:
S255;
cState:
timeToGo:
brClass:
brMethod:
TConvResult;
BOOLEAN;
S8;
S8;
PROCEDURE GetToken;
VAR endOfToken: INTEGER;
BEGIN
token := '';
WHILE Pos(' ', inputStr) = 1 DO
Delete(inputStr,1,1);
endOfToken := Pos(' ', inputStr)-1;
IF endOfToken <= 0 THEN
endOfToken := Length(inputStr);
token := Copy(inputStr, 1, endOfToken);
Delete(inputStr, 1, endOfToken);
END;
PROCEDURE DebugStatus;
VAR i: INTEGER;
BEGIN
IntToStr(curTraceLevel, @token);
Write('Watch Level = ',token);
IntToStr(defTraceCount, @token);
WriteLn(', Watch Count = ',token);
FOR i := 1 TO breakMCount DO
WITH breakMethods[i] DO
IF (brClass <> '') OR (brMethod <> '') THEN
WriteLn(i:3, ': ', brClass:8,'.',brMethod:8)
END;
PROCEDURE ClearBreaks;
VAR brNumber:
INTEGER;
cState:
TConvResult;
BEGIN
GetToken;
IF token = '' THEN
BEGIN
Write('Clear which breakpoint [A for all breakpoints]? ');
ReadLn(token);
END;
TrimBlanks(@token);
StrUpperCased(@token);
IF token <> '' THEN
IF token[1] = 'A' THEN
breakMCount := 0
ELSE
BEGIN
StrToInt(@token, brNumber, cState);
IF cState = cvValid THEN
IF (brNumber >= 1) AND (brNumber <= breakMCount) THEN
WITH breakMethods[brNumber] DO
BEGIN
brClass := '';
brMethod := '';
END;
END;
'), 1, 8);
ELSE
defTraceCount := 0;
returnToMain := TRUE;
fTraceSelf := FALSE;
fTraceClass := FALSE;
WHILE token <> '' DO
BEGIN
StrUpperCased(@token);
IF token[1] = 'A' THEN {Stay on Alternate Screen During Trace}
returnToMain := FALSE
ELSE
IF token[1] = 'C' THEN {Print Class with Trace}
fTraceClass := TRUE
ELSE
IF token[1] = 'F' THEN {Print Fields with Trace}
fTraceSelf := TRUE;
GetToken;
END;
fTraceEnabled := TRUE;
traceCount := defTraceCount;
END;
PROCEDURE Level;
VAR i: INTEGER;
BEGIN
GetToken;
IF token = '' THEN
BEGIN
Write('Lowest BP level to watch (1..9999)? ');
ReadLn(token);
END;
StrToInt(@token, i, cState);
IF cState = cvValid THEN
IF (i >= 1) AND (i <= 32000) THEN
curTraceLevel := i;
END;
FUNCTION YesNo(prompt: S255): BOOLEAN;
BEGIN
REPEAT
GetOne(Concat(prompt, '? [Y/N]: '));
IF token = '' THEN
GOTO 99;
UNTIL token[1] IN ['Y', 'N'];
YesNo := token[1] = 'Y';
END;
PROCEDURE PromptOnOff;
BEGIN
showPrompt := YesNo('Show Debugger Prompt');
END;
{$IFC fDebugMethods}
PROCEDURE Inspect;
VAR lh: LONGINT;
d: INTEGER;
BEGIN
GetToken;
IF token = '' THEN
BEGIN
Write('Handle to inspect [depth] [member decl]? ');
Readln(inputStr);
GetToken;
END;
HexStrToLInt(@token, lh, cState);
IF cState <> cvValid THEN
BEGIN
WriteLn('Not a hex number');
Exit(Inspect);
END
ELSE
GetToken;
StrToInt(@token, d, cState);
IF cState <> cvValid THEN
d := 1;
IF ValidObject(Handle(lh)) THEN
BEGIN
WrObj(TObject(lh), d, inputStr);
Writeln;
END
ELSE
Writeln('Invalid Object');
Writeln;
END;
{$ENDC}
PROCEDURE TallyAndTime;
BEGIN
tallyingCalls := FALSE;
IF tallies <> NIL THEN
BEGIN
IF YesNo('Do you want to see performance measurements now') THEN
TallyReport;
IF YesNo('Do you want to zero the tallies and times') THEN
TallyZero;
END;
IF YesNo('Do you want to continue execution and measure its performance') THEN
TallyStart;
WriteLn;
END;
PROCEDURE RefsToObject;
VAR lh: LONGINT;
BEGIN
GetToken;
IF token = '' THEN
BEGIN
Write('Handle of the object whose every Reference from the same heap should be dumped? ');
Readln(inputStr);
GetToken;
END;
HexStrToLInt(@token, lh, cState);
IF cState <> cvValid THEN
BEGIN
WriteLn('Not a hex number');
Exit(RefsToObject);
END;
IF ValidObject(Handle(lh)) THEN
DumpHeap(TObject(lh).Heap, -1, lh, TRUE)
ELSE
Writeln('Invalid Object');
Writeln;
END;
FUNCTION StackFrame(whichFrame: INTEGER): LONGINT;
{ Returns address of stack frame 'whichFrame' (>=-1);
whichFrame < 0 returns -1.
whichFrame = 1 is the top frame not belonging to the debugger itself.
When called from ABCBREAK, the caller of ABCBREAK is frame 1;
When called from BEPSN, the caller of BP or EP is frame 1.
whichFrame = 2 is the caller of frame 1, and so on.
If whichFrame is greater than # frames, returns -1.
If neither ABCBREAK nor BEPSN is on the stack, returns -1.}
VAR dummy:
INTEGER;
{ must be first local and two bytes long }
RA6:
LONGINT;
RA5:
LONGINT;
i:
className:
procName:
startCount:
frameReference:
nextPC:
INTEGER;
TClassName;
S8;
BOOLEAN;
INTEGER;
LONGINT;
BEGIN
StackFrame := -1;
frameReference := 0;
startCount := FALSE;
{ default return }
RA5 := %_GetA5;
RA6 := ORD(@dummy)+2;
{ stack frame called by current one; start with my stack frame }
WHILE (whichFrame >= frameReference) AND (RA6 <> RA5) DO
BEGIN
IF NOT startCount THEN
BEGIN
IF GetDollarD(TppINTEGER(RA6), className, procName, nextPC) THEN { is this frame 0? }
IF (className = '') AND ((procName = 'BEPSN
') OR (procName = 'ABCBREAK'))THEN
BEGIN
startCount := TRUE; { yes }
IF procName = 'BEPSN
' THEN
frameReference := -1;
END;
END;
RA6 := TpLONGINT(RA6)^;
END;
IF startCount THEN
BEGIN
IF whichFrame = frameReference THEN
StackFrame := RA6;
whichFrame := whichFrame - 1;
END;
END;
Byte2Char := ''
ELSE
Byte2Char := CHR(n);
END;
{$R-}
PROCEDURE AddCh(s: TPString; ch: CHAR; maxStrLeng: INTEGER; VAR overflow: BOOLEAN);
BEGIN
overflow := TRUE;
IF Length(s^) < maxStrLeng THEN
BEGIN
overflow := FALSE;
s^[0] := CHR(ORD(s^[0]) + 1);
s^[ORD(s^[0])] := ch;
END;
END;
{$IFC fRngObject} {$R+} {$ENDC}
BEGIN
{ start at an even address and fullBytes a multiple of 16 >= numBytes }
addr := (start DIV 2) * 2;
IF checkAddresses THEN
IF NOT ValidDataAddress(addr) THEN
IF NOT ValidGlobalAddress(addr) THEN
BEGIN
WriteLn;
Write('*** That address is neither in a data segment nor in the stack/global segment. ');
WriteLn('***');
EXIT(WrMemory);
END;
fullBytes := ((numBytes + 15) DIV 16) * 16;
WHILE fullBytes > 0 DO
BEGIN
IF fullBytes MOD 16 = 0 THEN
BEGIN
LIntToHex(addr, @str);
Write(' ', str, '
');
asChars := '';
END;
IF checkAddresses THEN
IF NOT ValidDataAddress(addr) THEN
IF NOT ValidGlobalAddress(addr) THEN
WHILE numBytes > 0 DO
BEGIN
Write(' ');
AddCh(@asChars, '', 16, overflow);
AddCh(@asChars, '', 16, overflow);
numBytes := numBytes - 2;
fullBytes := fullBytes - 2;
END;
IF numBytes <= 0 THEN
WHILE fullBytes > 0 DO
BEGIN
Write('
');
AddCh(@asChars, ' ', 16, overflow);
AddCh(@asChars, ' ', 16, overflow);
fullBytes := fullBytes - 2;
END;
IF fullBytes > 0 THEN
BEGIN
extdWord := LIntAndLInt(TpINTEGER(addr)^, $0000FFFF);
LIntToHex(extdWord, @str);
Delete(str, 1, 4); {4 leading zeros}
Write(str, ' ');
AddCh(@asChars, Byte2Char(extdWord DIV 256), 16, overflow);
AddCh(@asChars, Byte2Char(extdWord MOD 256), 16, overflow);
addr := addr + 2;
fullBytes := fullBytes - 2;
numBytes := numBytes - 2;
END;
IF fullBytes MOD 16 = 0 THEN
WriteLn('
|', asChars, '|');
END;
WriteLn;
END;
FUNCTION WrFrame(whichFrame: INTEGER; full: BOOLEAN): BOOLEAN;
{ Write a frame given its number; return TRUE if that frame exists }
VAR RA5:
LONGINT;
calledA6:
LONGINT;
addr:
LONGINT;
laterA6:
LONGINT;
earlierA6:
LONGINT;
hexStr:
S8;
gotMainProg:
BOOLEAN;
className:
methName:
procName:
procStart:
frameSELF:
class:
nextPC:
localBytes:
paramBytes:
selfBytes:
TClassName;
S8;
S255;
LONGINT;
TObject;
TClass;
LONGINT;
INTEGER;
INTEGER;
INTEGER;
WHILE procStart = 0 DO
BEGIN
addr := addr - 2;
IF TpINTEGER(addr)^ = $4E56 { LINK A6,<n> } THEN
{ found LINK, so numLocal is now set correctly, and
start of PROCEDURE is 4 bytes back (auto stack expansion) }
procStart := addr - 4;
END;
IF gotMainProg THEN
procStart := procStart + 4;
addr := calledA6+4;
LintToHex(TpLONGINT(addr)^-4 - procStart, @hexStr);
Delete(hexStr, 1, Length(hexStr)-4);
{ only want the lower 4 digits of hex number }
Write('+ $', hexStr);
{ advance to next stack frame now, so we can get at its variables }
laterA6 := calledA6;
calledA6 := TpLONGINT(laterA6)^;
IF calledA6 = RA5 THEN
earlierA6 := RA5
ELSE
earlierA6 := TpLONGINT(calledA6)^;
frameSELF := NIL;
IF (className <> '') AND (procName <> 'CREATE ') THEN { regular method }
BEGIN
addr := calledA6+8;
IF ValidObject(Handle(TpLONGINT(addr)^)) THEN
frameSELF := TObject(TpLONGINT(addr)^);
END;
IF frameSELF <> NIL THEN
BEGIN
LIntToHex(ORD(frameSELF), @hexStr);
class := frameSELF.Class;
CpToCn(TPSliceTable(class), TS8(className));
Write(' (', className, ': $', hexStr, ')');
END;
IF full THEN
BEGIN
{$IFC fDebugMethods}
WriteLn;
IF frameSELF <> NIL THEN
BEGIN
Write('SELF = ');
currXPos := 7;
outputIndent := 7;
frameSELF.Debug(1, '');
WriteLn;
END;
{$ENDC}
localBytes := Max(0, Min(ORD(calledA6 - (laterA6 + 8)), $50));
paramBytes := Max(0, Min(ORD(earlierA6 - (calledA6 + 8)), $50));
selfBytes := 4 * ORD(frameSELF <> NIL);
WriteLn;
WriteLn('LOCALS (First declared local is listed last):');
WrMemory(calledA6 - localBytes, localBytes, FALSE);
WriteLn('PARAMETERS (Last declared parameter is listed first):');
WrMemory(calledA6 + 8 + selfBytes, paramBytes - selfBytes, FALSE);
END;
END;
WriteLn;
END;
PROCEDURE StackCrawl;
VAR frNum:
INTEGER;
BEGIN
frNum := 1;
WHILE WrFrame(frNum, FALSE) DO
frNum := frNum + 1;
WriteLn;
END;
PROCEDURE FrameDump;
VAR i:
INTEGER;
frame: LONGINT;
BEGIN
GetToken;
IF token = '' THEN
BEGIN
Write('Frame number to dump? ');
ReadLn(token);
END;
StrToInt(@token,i,cState);
IF cState = cvValid THEN
BEGIN
IF (i >= 1) THEN
IF NOT WrFrame(i, TRUE) THEN
WriteLn('Frame number was too large');
END;
WriteLn;
END;
PROCEDURE ToPrinter;
VAR errnum:
INTEGER;
outfname:
PathName;
{$IFC LibraryVersion <= 20}
{ Paslib initialization done in the WorkShop that is not done in the DeskTop manager }
PROCEDURE TellPaslibPrinterLocation;
CONST
AlreadyMounted = 1052;
VAR
errnum:
tp:
devname:
vname:
password:
tdt:
tdi:
dsp:
DevControl:
path:
INTEGER;
TPORTS;
E_Name;
E_Name;
E_Name;
TDeviceType;
TDeviceInfo;
DsProcParam;
DcType;
PathName;
{ error return }
BEGIN
FOR tp := uppertwig TO t_extra3 DO
BEGIN
Get_config_name(errnum,tp,devname);
IF errnum <= 0 THEN
BEGIN
PMReadConfig(tp,tdt,tdi);
IF tdt IN [DMPrinter,Typer] THEN
BEGIN
Mount(errnum, vname, password, devname);
IF (errnum <= 0) or (errnum = AlreadyMounted) THEN
BEGIN
dsp.proccode := dsPrintDev;
dsp.PrDevice := Concat('-', devname);
DSPaslibCall(dsp);
WITH DevControl DO
BEGIN
path := Concat('-',devname,'-x'); {OD}
dcversion := 2;
dccode := 17;
{auto LF disable}
dcdata[0] := 1;
Device_Control(errnum,path,DevControl);
CASE tp OF
seriala,serialb:
BEGIN
dccode := 5;
dcdata[0] := 9600;
Device_control(errnum,path,devcontrol);
dccode := 2;
Device_control(errnum,path,devcontrol);
dccode := 1;
dcdata[0] := 0;
Device_control(errnum,path,devcontrol);
dccode := 12;
dcdata[0] := 60;
Device_control(errnum,path,devcontrol);
dccode := 10;
dcdata[0] := 0;
dcdata[1] := -128;
Device_control(errnum,path,devcontrol);
END;
END {CASE}
END;
EXIT(TellPaslibPrinterLocation);
END
ELSE
WriteLn('Error number ',errnum,' mounting ',devname);
END;
{baud rate}
{DTR}
{8-bit no-parity}
{time out}
{disconnect detect}
END
END;
END { TellPaslibPrinterLocation };
{$ELSEC} {Spring Version}
{ Paslib initialization done in the WorkShop that is not done in the DeskTop manager }
PROCEDURE TellPaslibPrinterLocation;
CONST
AlreadyMounted = 1052;
cdSerialCable = 32;
TYPE
TExtWords = PACKED RECORD
isPrinter: BOOLEAN;
isDefault: BOOLEAN;
driverID:
-8192..8191;
END;
VAR
errnum:
nextEntry:
config:
pExtWords:
vname:
password:
devControl:
dsp:
path:
E_Name;
DcType;
DsProcParam;
Pathname;
BEGIN
nextEntry := 0;
REPEAT
PmReadConfig(errnum, nextEntry, config);
IF errnum <= 0 THEN
IF config.nExtWords >= 1 THEN
BEGIN
pExtWords := @config.extWords[1];
IF pExtWords^.isPrinter THEN
BEGIN
Mount(errnum, vname, password, config.devname);
IF (errnum <= 0) or (errnum = AlreadyMounted) THEN
BEGIN
dsp.proccode := dsPrintDev;
dsp.PrDevice := Concat('-', config.devname);
DSPaslibCall(dsp);
WITH devControl DO
BEGIN
path := Concat('-', config.devname, '-x'); {OD}
dcversion := 2;
dccode := 17;
{auto LF disable}
dcdata[0] := 1;
Device_Control(errnum, path, devControl);
IF config.driverID = cdSerialCable THEN
BEGIN
dccode := 5;
dcdata[0] := 9600;
Device_control(errnum,path,devcontrol); {baud rate}
dccode := 2;
Device_control(errnum,path,devcontrol); {DTR}
dccode := 1;
dcdata[0] := 0;
Device_control(errnum,path,devcontrol); {8-bit no-parity}
dccode := 12;
dcdata[0] := 60;
Device_control(errnum,path,devcontrol); {time out}
dccode := 10;
dcdata[0] := 0;
dcdata[1] := -128;
Device_control(errnum,path,devcontrol); {disconnect detect}
END; {IF config.driverID = cdSerialCable}
END; {WITH devControl DO}
END {IF (errnum <= 0) or (errnum = AlreadyMounted) THEN}
{$ENDC}
ELSE
WriteLn('Error number ', errnum, ' mounting ', config.devname);
END; {IF pExtWords^.isPrinter THEN}
END; {IF config.nExtWords >= 1 THEN}
UNTIL errnum > 0;
END { TellPaslibPrinterLocation };
BEGIN
GetToken;
outfname := token;
IF token = '' THEN
BEGIN
Write('Name of file to send output to? [-console] ');
ReadLn(outfname);
END;
IF outfname = '' THEN
OutputRedirect(errnum,outfname,TRUE)
ELSE
BEGIN
StrUpperCased(@outfname);
IF outfname = '-PRINTER' THEN
TellPaslibPrinterLocation;
OutputRedirect(errnum,outfname,FALSE);
END;
IF errnum > 0 THEN
BEGIN
IF outfname = '' THEN
outfname := '-CONSOLE';
WriteLn('Error number ',errnum,' redirecting output to ',outfname);
END;
END;
PROCEDURE MemoryDump;
VAR start:
LONGINT;
numBytes:
LONGINT;
BEGIN
GetToken;
IF token = '' THEN
BEGIN
Write('Starting address [# bytes]? ');
Readln(inputStr);
GetToken;
END;
HexStrToLInt(@token, start, cState);
IF cState <> cvValid THEN
Exit(MemoryDump)
ELSE
GetToken;
HexStrToLInt(@token, numBytes, cState);
IF cState <> cvValid THEN
numBytes := $10;
WrMemory(start, numBytes, TRUE);
END;
PROCEDURE HeapDump;
VAR allInfo:
wantedSTP:
allHeaps:
index:
heap:
dumpDocHeap:
BEGIN
allInfo := TRUE;
wantedSTP := -1;
allHeaps := TRUE;
BOOLEAN;
LONGINT; {-1 for all classes}
BOOLEAN;
INTEGER;
THeap;
BOOLEAN;
GetToken;
IF token <> '' THEN
BEGIN
allHeaps := FALSE;
TrimBlanks(@token);
StrUpperCased(@token);
index := CiOfCn(Copy(Concat(token, '
'), 1, 8));
IF index > 0 THEN
wantedSTP := ORD(hMySTables^^.records[index])
ELSE
BEGIN
WriteLn('No such class!');
EXIT(HeapDump);
END;
END;
IF allHeaps THEN
IF NOT YesNo('All classes') THEN
WHILE wantedSTP <= 0 DO
BEGIN
GetOne('Which class?');
IF token = '' THEN
GOTO 99
ELSE
BEGIN
index := CiOfCn(token);
END
ELSE
BEGIN
WriteLn('There is no document or clipboard heap because the process is not fully initialized');
WriteLn;
END;
END;
BEGIN {EntDebugger}
SetScreenKeybd(altscrn);
traceCount := defTraceCount;
timeToGo := FALSE;
WriteLn;
WriteLn('ToolKit Debugger - ',enterReason);
(*
*)
{ flush characters; because of PASLIB bug, also stop when user types a ~ }
commented out as a test case to see if still needed here
IF CheckKeyPress('') THEN;
IF tallyingCalls THEN
BEGIN
TallyAndTime;
returnToMain := tallyingCalls;
END;
IF NOT tallyingCalls THEN
BEGIN
REPEAT
IF NOT timeToGo THEN
BEGIN
IF showPrompt THEN
BEGIN
WriteLn('B)reakpoint, C)learBreakpoints [breakpoint #/ALL], D)ebugStatus, E)nterLisabug,');
{$IFC fDebugMethods}
WriteLn('
F)rameDump, G)o, H)eapDump [class], I)nspectObject, L)evelsToWatch,');
{$ELSEC}
WriteLn('
F)rameDump, G)o, H)eapDump [class], L)evelsToWatch,');
{$ENDC}
WriteLn('
M)emoryDump <location> [# bytes], O)utputTo, P)rompt [Y/N], R)efsToObject,');
WriteLn('
S)tackCrawl, T)ally & Time, W)atch [count] [A)ltScreen] [C)lass] [F)ields]');
END;
Write('-->');
ReadLn(inputStr);
END;
GetToken;
IF token <> '' THEN
CASE CharUpperCased(token[1]) OF
null:
GoKitBug;
{don't expect people to type this command, but this
will guarantee that the Linker does not flush
the GoKitBug procedure}
'B':
BrSetup('Break on');
'C':
ClearBreaks;
'D':
DebugStatus;
'E':
%_GoLisabug;
'F':
FrameDump;
'G':
BEGIN
fTraceEnabled := FALSE;
defTraceCount := 0;
traceCount := defTraceCount;
returnToMain := TRUE;
timeToGo := TRUE;
END;
'H':
HeapDump;
{$IFC fDebugMethods}
'I':
Inspect;
{$ENDC}
'L':
Level;
'M':
MemoryDump;
'O':
ToPrinter;
'P':
PromptOnOff;
'R':
RefsToObject;
'S':
StackCrawl;
'T':
BEGIN
TallyAndTime;
timeToGo := tallyingCalls;
END;
'W':
BEGIN
TraceOrNot;
timeToGo := TRUE;
END;
'X':
END;
timeToGo := TRUE;
99:
UNTIL timeToGo;
END;
IF tallyingCalls THEN
BEGIN
fTraceEnabled := FALSE;
defTraceCount := 0;
traceCount := defTraceCount;
returnToMain := TRUE;
END;
IF returnToMain THEN
SetScreenKeybd(priscrn);
END; {EntDebugger}
{$S SgCLAdbg}
FUNCTION AKeyPress: BOOLEAN;
VAR tb: BOOLEAN;
BEGIN
AKeyPress := FALSE;
IF kpcntr >= keyPresLimit THEN
BEGIN
tb := KeyPress;
{ force call to keyPress until press is dealt with }
IF NOT tb THEN
kpcntr := 0;
AKeyPress := tb;
END
ELSE
kpcntr := kpcntr + 1
END;
{ ====================================== BP -- EP ====================================== }
{$IFC fTrace}
PROCEDURE BEPSN(odummy:
VAR receiver:
caller:
i:
className:
procName:
toDebugger:
nextPC:
found := FALSE;
FOR i := 1 TO breakMCount DO
BEGIN
WITH breakMethods[i] DO
{ NOTE: if both brClass and brMethod are '', then the iTH breakpoint is unassigned }
IF brClass = '' THEN
found := (brMethod = procName) AND (brMethod <> '')
ELSE
IF brMethod = '' THEN
found := brClass = className
ELSE
found := (brClass = className) AND (brMethod = procName);
IF found THEN
BEGIN
displayIt := TRUE;
toDebugger := TRUE;
returnToMain := TRUE;
fTraceSelf := FALSE;
fTraceClass := TRUE;
lastBpPc := 0;
lastEpPc := 0;
EXIT(BreakHere)
END
END
END;
PROCEDURE WriteOutDebugInfo;
CONST maxIndent = 70;
VAR i:
INTEGER;
hexStr: S8;
BEGIN
WriteLn;
indentTrace := CMin(tabLevel, maxIndent + 5);
IF tabLevel <= trLevMemory THEN
Write(traceLevels[tablevel]:4, ' ')
ELSE
Write('
');
Write(' ': CMin(tabLevel, maxIndent));
IF tabLevel > maxIndent + 5 THEN
Write(tabLevel:4, ' ')
ELSE
IF indentTrace > maxIndent THEN
Write(' ': indentTrace - maxIndent);
IF fBegin THEN
Write('BEGIN ')
ELSE
Write('END
');
{$IFC fDebugMethods}
currXPos := indentTrace + 11 {5 for level #; 6 for BEGIN/END};
{$ENDC}
IF className<>'' THEN
BEGIN
Write(className, '.');
{$IFC fDebugMethods}
currXpos := currXPos + 9;
{$ENDC}
END;
Write(procName);
{$IFC fDebugMethods}
currXPos := currXPos + 8;
{$ENDC}
IF (fTraceSelf OR fTraceClass) AND (receiver <> NIL) THEN
IF (procName<>'DEBUGOBJ') AND (procName<>'DEBUG
') AND (procName<>'FIELDS
(fBegin OR ((procName<>'FREEOBJE') AND (procName<>'FREE
'))) THEN
BEGIN
{$IFC fDebugMethods}
Write('(');
currXPos := currXPos + 1;
') AND
END;
Write(')');
{$ENDC}
END;
PROCEDURE TraceStuff;
VAR nextPC: LONGINT;
BEGIN
IF traceCount = 1 THEN
callerPC:
departed:
LONGINT;
LONGINT;
BEGIN
IF tallyingCalls THEN
stopTime := MicroTimer(* - debugTime*);
tabLevel := tabLevel + 1; {Increment first because BEPSN can be reentrant}
callerPC := TpLONGINT(ORD(@dummy) + 8)^;
IF tabLevel <= trLevMemory THEN
BEGIN
traceLevels[tabLevel] := myTraceLevel;
bpFrame := TpLONGINT(ORD(@dummy) + 4);
traceFrames[tabLevel] := LIntAndLInt(bpFrame^, $00FFFFFF);
END;
IF fTraceEnabled AND (myTraceLevel >= curTraceLevel) THEN
BEPSN(ORD(@dummy), TRUE, TRUE)
ELSE
IF (breakMCount > 0) OR AKeyPress THEN
IF callerPC <> lastBpPc THEN
BEPSN(ORD(@dummy), TRUE, FALSE);
lastBpPc := callerPC;
IF tallyingCalls THEN
BEGIN
departed := MicroTimer;
(*
debugTime := debugTime + departed - stopTime + tallyOverhead; *)
IF tabLevel <= trLevMemory THEN
traceTimes[tabLevel] := departed (*- debugTime*);
END;
END;
PROCEDURE EP;
VAR dummy:
LONGINT;
{Must be first VAR and 4 bytes long}
epFrame:
LONGINT;
doTrace:
BOOLEAN;
i:
INTEGER;
callerPC:
LONGINT;
elapsed:
LONGINT;
BEGIN
callerPC := TpLONGINT(ORD(@dummy) + 8)^;
IF tallyingCalls THEN
BEGIN
stopTime := MicroTimer (*- debugTime*);
IF tabLevel <= trLevMemory THEN
BEGIN
elapsed := stopTime - traceTimes[tabLevel];
FOR i := tabLevel - 1 DOWNTO 1 DO
traceTimes[i] := traceTimes[i] + elapsed;
Tally(callerPC, elapsed);
END
ELSE
BEGIN
WriteLn('Stack bigger than performance measurement can handle! ', tablevel:1);
tallyingCalls := FALSE;
END;
END;
IF tabLevel < 0 THEN
BEGIN
tabLevel := 0;
Writeln('--------------------------');
BEPSN(ORD(@dummy), FALSE, TRUE);
ABCBreak('The above EP had no BP at all', 0);
doTrace := FALSE;
END
ELSE IF tabLevel <= trLevMemory THEN
BEGIN
epFrame := LIntAndLInt(TpLONGINT(ORD(@dummy) + 4)^, $00FFFFFF);
IF traceFrames[tabLevel] <> epFrame THEN
BEGIN
i := tabLevel - 1;
{Try to resynchronize}
WHILE (tabLevel <> i) AND (i >= 0) DO
IF traceFrames[i] = epFrame THEN
BEGIN
Writeln('--------------------------');
ABCBreak('There was a BP with no EP', 0);
tabLevel := i;
END
ELSE
i := i - 1;
IF tabLevel <> i THEN
BEGIN
Writeln('--------------------------');
BEPSN(ORD(@dummy), FALSE, TRUE);
ABCBreak('The above EP had no BP', 0);
END;
END;
doTrace := fTraceEnabled AND (traceLevels[tablevel] >= curTraceLevel);
END
ELSE
doTrace := FALSE;
IF doTrace THEN
BEPSN(ORD(@dummy), FALSE, TRUE)
ELSE
IF (breakMCount > 0) OR AKeyPress THEN
IF callerPC <> lastEpPc THEN
BEPSN(ORD(@dummy), FALSE, FALSE);
IF tabLevel >= 0 THEN
tabLevel := tabLevel - 1;
lastEpPc := callerPC;
(*
IF tallyingCalls THEN
debugTime := MicroTimer - stopTime + tallyOverhead;
*)
END;
{$ENDC}
{$ENDC}
{ ====================================== COUNTHEAP ====================================== }
{$IFC fCheckHeap}
FUNCTION CountHeap{(heap: THeap): INTEGER};
VAR hz:
THz;
numObjects: INTEGER;
BEGIN
hz := THz(heap);
IF FCheckHzOK(hz, numObjects) THEN ;
CountHeap := numObjects;
END;
{$ENDC}
{$S sInit1}
UNIT UText;
{$SETC IsIntrinsic := TRUE }
{$IFC IsIntrinsic}
INTRINSIC;
{$ENDC}
{Multiple Paragraph Building Block for the Tool Kit}
{changed
{changed
{changed
{changed
{changed
{changed
04/25/84
04/18/84
04/16/84
04/13/84
04/12/84
04/10/84
1437
1652
1135
0209
2344
1400
INTERFACE
{$DECL fUseUnivText}
{$SETC fUseUnivText := TRUE}
USES
{$U libtk/UObject}
UObject,
{$IFC LibraryVersion <= 20}
{$U UFont}
UFont,
{$ENDC}
{$U QuickDraw}
QuickDraw,
{$U libtk/UDraw}
UDraw,
{$IFC fUseUnivText}
{$U libtk/UUnivText}
UTKUniversalText,
{$ENDC}
{$U UABC}
UABC;
{$DECL
{$SETC
{$DECL
{$SETC
{$DECL
{$SETC
fTextTrace}
fTextTrace := fDbgOK}
fParaTrace}
fParaTrace := fDbgOK}
fRngText}
fRngText := fDbgOK}
CONST
cVertMargin = 4;
cHorizMargin = 6;
somethingKind = 1;
TYPE
TStyleChange = RECORD
lp:
INTEGER;
newStyle:
TTypeStyle;
END;
TTxtTabDescriptor = RECORD
xCoord:
INTEGER;
quad:
TAlignment;
{MORE LATER}
END;
TDrawAction = (actionDraw, actionInval, actionNone);
{ PARAGRAPH SUBCLASSES }
TParaFormat = SUBCLASS OF TObject
dfltTStyle:
TTypeStyle;
wordWrap:
BOOLEAN;
quad:
TAlignment;
firstIndent:
INTEGER;
leftIndent:
INTEGER;
rightIndent:
INTEGER;
spaceAbovePara:
INTEGER;
spaceBelowPara:
INTEGER;
lineSpacing:
INTEGER;
tabs:
TArray;
refCount:
permanent:
styleSheet:
INTEGER;
BOOLEAN;
TStyleSheet;
{Creation/Destruction}
FUNCTION TParagraph.CREATE(object: TObject; heap: THeap;
initialSize: INTEGER; initialTypeStyle: TTypeStyle): TParagraph;
PROCEDURE TParagraph.Free; OVERRIDE;
{Debugging}
{$IFC fParaTrace}
PROCEDURE TParagraph.Fields(PROCEDURE Field(nameAndType: S255)); OVERRIDE;
{$ENDC}
{Overridden TString methods}
PROCEDURE TParagraph.Draw(i: LONGINT; howMany: INTEGER); OVERRIDE;
FUNCTION TParagraph.Width(i: LONGINT; howMany: INTEGER): INTEGER; OVERRIDE;
{This method is used by TParagraph.Draw and TParagraph.Width to interpret the typeStyles array}
PROCEDURE TParagraph.DrawLine(startLP, endLP: INTEGER; fDraw: BOOLEAN; fWidth: BOOLEAN;
VAR width: INTEGER; VAR styleIndex: INTEGER);
{Type Style Maintainence}
PROCEDURE TParagraph.ChangeStyle(startLP, endLP: INTEGER; PROCEDURE Change(VAR typeStyle: TTypeStyle);
VAR styleOfStartLP: TTypeStyle);
{These four routines all call ChangeStyle}
PROCEDURE TParagraph.ChgFace(startLP, endLP: INTEGER;
newOnFaces: {$IFC LibraryVersion <= 20}TSeteface{$ELSEC}Style{$ENDC};
VAR styleOfStartLP: TTypeStyle);
PROCEDURE TParagraph.ChgFontSize(startLP, endLP: INTEGER; newFontSize: Byte;
VAR styleOfStartLP: TTypeStyle);
PROCEDURE TParagraph.ChgFontFamily(startLP, endLP: INTEGER; newFontFamily: Byte;
VAR styleOfStartLP: TTypeStyle);
PROCEDURE TParagraph.NewStyle(startLP, endLP: INTEGER; newTypeStyle: TTypeStyle);
PROCEDURE TParagraph.CleanRuns;
PROCEDURE TParagraph.UpdateRuns(atLP: INTEGER; replacedChars: INTEGER; insertedChars: INTEGER);
{Character Maintainence}
PROCEDURE TParagraph.ReplPara(fPos, numChars: INTEGER;
otherPara: TParagraph; otherFPos, otherNumChars: INTEGER);
PROCEDURE TParagraph.ReplTString(fPos, numChars: INTEGER;
otherString: TString; otherFPos, otherNumChars: INTEGER);
PROCEDURE TParagraph.ReplPString(fPos, numChars: INTEGER; pStr: TPString);
{Utilities}
{BuildExtentLRect takes an LPoint that indicates the baseline of the paragraph. It returns
in extentLRect the bounding rectangle whose height is based on the tallest font in the
paragraph and width is the width of the characters in the paragraph. Specifically:
top
:= baseLPt.v - tallestFontInfo.ascent;
bottom := baseLPt.v + tallestFontInfo.descent + tallestFontInfo.leading;
left
:= baseLPt.h;
right := baseLpt.h + paragraph.Width;}
PROCEDURE TParagraph.BuildExtentLRect(baseLPt: LPoint; VAR extentLRect: LRect);
FUNCTION TParagraph.FixLP(LP: INTEGER): INTEGER;
PROCEDURE TParagraph.SetTypeStyle(tStyle: TTypeStyle);
PROCEDURE TParagraph.StyleAt(lp: INTEGER; VAR typeStyle: TTypeStyle);
{Word Selection}
PROCEDURE TParagraph.FindWordBounds(orig: INTEGER; VAR first, last: INTEGER);
FUNCTION TParagraph.Qualifies(pos: INTEGER): BOOLEAN;
END;
{Editable Paragraph}
TEditPara = SUBCLASS OF TParagraph
{ character stuff }
bsCount:
INTEGER;
{ formatting stuff }
nestLevel:
INTEGER;
format:
TParaFormat;
{ paraImage stuff }
beingFiltered: BOOLEAN;
(*
maxImage:
numImages:
images:
*)
images:
INTEGER;
INTEGER;
ARRAY [1..1] OF TParaImage;
TList;
{Creation/Destruction}
FUNCTION TEditPara.CREATE(object: TObject; heap: THeap; initialSize: INTEGER;
itsFormat: TParaFormat): TEditPara;
PROCEDURE TEditPara.Free; OVERRIDE;
{Debugging}
{$IFC fParaTrace}
PROCEDURE TEditPara.Fields(PROCEDURE Field(nameAndType: S255)); OVERRIDE;
{$ENDC}
{Special Editing}
PROCEDURE TEditPara.BeginInsertion(atLP: INTEGER; size:INTEGER);
PROCEDURE TEditPara.EndInsertion;
FUNCTION TEditPara.GrowSize: INTEGER;
PROCEDURE TEditPara.InsertOneChar(ch: CHAR; atLP: INTEGER);
{Utility}
PROCEDURE TEditPara.SetTypeStyle(tStyle: TTypeStyle); OVERRIDE;
{ParaImage Maintenance}
PROCEDURE TEditPara.EachImage(PROCEDURE ImageProc(paraImage: TParaImage));
PROCEDURE TEditPara.DelImage(delImage: TParaImage; fFree: BOOLEAN);
PROCEDURE TEditPara.InsImage(paraImage: TParaImage);
PROCEDURE TEditPara.DelImgIF(FUNCTION ShouldDelete(paraImage: TParaImage): BOOLEAN);
END;
TLineInfo = SUBCLASS OF TObject
valid:
BOOLEAN;
startLP:
INTEGER;
lastDrawnLP:
INTEGER; {last character in line to draw: may omit trailing spaces}
endLP:
INTEGER; {last character in line: equals next lineInfo.startLP - 1}
lineLRect:
LRect;
lineAscent:
INTEGER;
FUNCTION TLineInfo.CREATE(object: TObject; heap: THeap): TLineInfo;
{$IFC fParaTrace}
PROCEDURE TLineInfo.Fields(PROCEDURE Field(nameAndType: S255)); OVERRIDE;
{$ENDC}
{Used by subclassers who don't like the way the hilite/update
rectangle is chosen so they can overrride it}
FUNCTION TLineInfo.LeftCoord(proposedLeftPixel: LONGINT): LONGINT;
FUNCTION TLineInfo.RightCoord(proposedRightPixel: LONGINT): LONGINT;
END;
TParaImage = SUBCLASS OF TImage
paragraph:
TEditPara;
height:
INTEGER;
{ pixel height of the paragraph}
lineList:
changed:
tickCount:
startLP:
endLP:
textImage:
wasOffset:
{Creation}
FUNCTION
TList;
BOOLEAN;
INTEGER;
INTEGER;
INTEGER;
{ of TLineInfo}
{ incremented (mod MAXINT) every time image is drawn }
{ MULTI-PARAGRAPH SUBCLASSES }
TStyleSheet = SUBCLASS OF TObject
formats:
TList; {of TParaFormat}
{Creation}
FUNCTION TStyleSheet.CREATE(object: TObject; heap: THeap): TStyleSheet;
PROCEDURE TStyleSheet.Free; OVERRIDE;
{Installs Default paraFormat into formats list}
PROCEDURE TStyleSheet.InitDefault;
{Debugging}
{$IFC fParaTrace}
PROCEDURE TStyleSheet.Fields(PROCEDURE Field(nameAndType: S255)); OVERRIDE;
{$ENDC}
END;
TTextRange = SUBCLASS OF TObject
firstPara: TEditPara;
firstIndex: LONGINT;
firstLP:
INTEGER;
lastPara:
TEditPara;
lastIndex: LONGINT;
lastLP:
INTEGER;
{Creation}
FUNCTION
{Debugging}
{$IFC fParaTrace}
PROCEDURE TTextRange.Fields(PROCEDURE Field(nameAndType: S255)); OVERRIDE;
{$ENDC}
{AdjustBy adjust the fields of TTextRange by the value of delta (where delta is in LPs)}
PROCEDURE TTextRange.AdjustBy(delta: INTEGER);
END;
TText = SUBCLASS OF TObject
paragraphs: TList; {of TEditPara }
styleSheet: TStyleSheet;
txtImgList: TList;
{Creation/Freeing}
FUNCTION TText.CREATE(object: TObject; heap: THeap; itsStyleSheet: TStyleSheet): TText;
{DfltTextImage can be called after CREATE to create and return a single textImage. It also
creates one empty paragraph using the first paraFormat in SELF.styleSheet. It installs the
textImage in txtImgList and the paragraph in paragraphs. This routine calls
textImage.RecomputeImages to set up the first paraImage.}
FUNCTION TText.DfltTextImage(view: TView; imageLRect: LRect; imgIsGrowable: BOOLEAN): TTextImage;
{TText.Free frees all paragraphs that belong to this text object and all textImages that
reference this text object}
PROCEDURE TText.Free; OVERRIDE;
PROCEDURE TText.FreeSelf(freeParas: BOOLEAN);
{Debugging}
{$IFC fParaTrace}
PROCEDURE TText.Fields(PROCEDURE Field(nameAndType: S255)); OVERRIDE;
{$ENDC}
{Calls to textImage procs get routed through these}
PROCEDURE TText.ChangeSelInOtherPanels(textSelection: TTextSelection);
PROCEDURE TText.DelPara(delPara: TEditPara; fFree: BOOLEAN);
PROCEDURE TText.Draw;
PROCEDURE TText.HiliteRange(highTransit: THighTransit; textRange: TTextRange; wholePara: BOOLEAN);
PROCEDURE TText.HiliteParagraphs(highTransit: THighTransit;
startIndex: LONGINT; startLP: INTEGER;
endIndex: LONGINT; endLP: INTEGER; wholePara: BOOLEAN);
PROCEDURE TText.InsParaAfter(existingPara: TEditPara; newPara: TEditPara);
PROCEDURE TText.Invalidate;
PROCEDURE TText.MarkChanged(textRange: TTextRange);
PROCEDURE TText.RecomputeImages;
FUNCTION TText.SelectAll(textImage: TTextImage): TTextSelection;
END;
INTEGER;
formerBottom:
LONGINT;
updateLRect:
LRect;
firstLinePixel:
useFirstPixel:
LONGINT;
BOOLEAN;
{ The following fields support multiple linked text images displaying a single text object,
where the text "flows" from one box to the next. APPLICATIONS ARE RESPONSIBLE FOR
MAINTAINING THESE FIELDS. This Building Block uses these fields for drawing, etc.
All text images in a chain should have growsDynamically set to FALSE (except possibly
for the last text image in a chain).
For applications that DO NOT use this feature, the fields will always be as follows:
startLP = 0;
endLP =
LP of last character in last paragraph; (if growsDynamically = TRUE)
LP of last character that fit in extentLRect; (if growsDynamically = FALSE)
prevTxtImg, nextTxtImg = NIL;
headTxtImg = SELF;
tailTxtImg = SELF;
}
firstIndex:
LONGINT;
{index of paragraph at SELF.imageList.First}
startLP:
INTEGER;
{startLP of paragraph at SELF.imageList.First}
endLP:
INTEGER;
{endLP of paragraph at SELF.imageList.Last}
prevTxtImg:
nextTxtImg:
headTxtImg:
tailTxtImg:
{Creation}
FUNCTION
TTextImage;
TTextImage;
TTextImage;
TTextImage;
{TTextImage.Free frees all text images and their paraImages in the text image chain.
It does NOT free any paragraphs, text objects, or paraFormats. Call this only once
for each text image chain (NOT for each text image in the chain). Note that TText.Free
frees its textImages so calling this routine is not necessary in most cases}
PROCEDURE TTextImage.Free; OVERRIDE;
{TTextImage.FreeOneTextImage frees just one text image from the chain. It pays no attention
to links or whether this is the head text image. Maintenance of these fields must be
handled by the caller before calling this routine. Those who do not use linked text images
should always call TTextImage.Free above, NOT this routine}
PROCEDURE TTextImage.FreeOneTextImage;
{Debugging}
{$IFC fParaTrace}
PROCEDURE TTextImage.Fields(PROCEDURE Field(nameAndType: S255)); OVERRIDE;
{$ENDC}
{Drawing}
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
TTextImage.Draw; OVERRIDE;
TTextImage.DrawImages(fDraw: BOOLEAN);
TTextImage.DrawOrInval(invalBits: BOOLEAN);
TTextImage.HiliteText(highTransit: THighTransit;
startIndex: LONGINT; startLP: INTEGER;
endIndex: LONGINT; endLP: INTEGER; wholePara: BOOLEAN);
{Locating}
PROCEDURE TTextImage.FindParaAndLp(LPt: LPoint; VAR paraImage: TParaImage;
{Creation}
FUNCTION
{Debugging}
{$IFC fParaTrace}
PROCEDURE TTextView.Fields(PROCEDURE Field(nameAndType: S255)); OVERRIDE;
{$ENDC}
{$IFC fUseUnivText}
PROCEDURE TTextView.CreateUniversalText; OVERRIDE;
{$ENDC}
PROCEDURE TTextView.Draw; OVERRIDE;
PROCEDURE TTextView.MousePress(mouseLPt: LPoint); OVERRIDE;
END;
{$IFC fUseUnivText}
TTextWriteUnivText = SUBCLASS OF TTKWriteUnivText
textSelection: TTextSelection;
currIndex:
LONGINT;
currPara:
TEditPara;
currLP:
INTEGER;
currStyleIndex: INTEGER;
currTStyles:
TArray;
{Creation}
FUNCTION TTextWriteUnivText.CREATE(object: TObject; heap: THeap;
itsString: TString; itsDataSize: INTEGER;
itsTextSel: TTextSelection): TTextWriteUnivText;
{Debugging}
{$IFC fParaTrace}
PROCEDURE TTextWriteUnivText.Fields(PROCEDURE Field(nameAndType: S255)); OVERRIDE;
{$ENDC}
PROCEDURE TTextWriteUnivText.FillParagraph; OVERRIDE;
END;
{$ENDC}
TTextSelection = SUBCLASS OF TSelection
textImage:
TTextImage;
textRange:
TTextRange;
isWordSelection:
BOOLEAN;
isParaSelection:
BOOLEAN;
viewTick:
INTEGER;
amTyping:
BOOLEAN;
currTypeStyle:
TTypeStyle;
FUNCTION
{Debugging}
{$IFC fParaTrace}
PROCEDURE TTextSelection.Fields(PROCEDURE Field(nameAndType: S255)); OVERRIDE;
{$ENDC}
{Commands}
PROCEDURE TTextSelection.KeyText;
FUNCTION TTextSelection.NewCommand(cmdNumber: TCmdNumber): TCommand; OVERRIDE;
FUNCTION TTextSelection.NewStyleCmd(heap: THeap; cmdNumber: TCmdNumber;
textImage: TTextImage): TCommand;
FUNCTION TTextSelection.NewCutCopyCmd(heap: THeap; cmdNumber: TCmdNumber;
textImage: TTextImage): TCommand; DEFAULT;
PROCEDURE TTextSelection.StyleFromContext; DEFAULT;
PROCEDURE TTextSelection.DoChangeStyle(cmdNumber: TCmdNumber; paragraph: TParagraph;
firstLP: INTEGER; lastLP: INTEGER; VAR newStyle: TTypeStyle);
PROCEDURE TTextSelection.ChangeStyle(cmdNumber: TCmdNumber); DEFAULT;
{Editing}
PROCEDURE TTextSelection.ChangeText(PROCEDURE TextEdit; PROCEDURE Adjust); DEFAULT;
FUNCTION TTextSelection.CopySelf(heap: THeap; view: TView): TMultiParaSelection; DEFAULT;
PROCEDURE TTextSelection.CutCopy(clipSelection: TSelection; deleteOriginal: BOOLEAN); DEFAULT;
PROCEDURE TTextSelection.DeleteAndFree; DEFAULT;
FUNCTION TTextSelection.DeleteButSave: TText; DEFAULT;
{Highlighting}
PROCEDURE TTextSelection.Highlight(highTransit: THighTransit); OVERRIDE;
{Selecting}
FUNCTION
PROCEDURE
PROCEDURE
FUNCTION
TTextSelection.BecomeInsertionPoint: TInsertionPoint;
TTextSelection.GetHysteresis(VAR hysterPt: Point); OVERRIDE;
TTextSelection.MousePress(mouseLPt: LPoint); OVERRIDE;
TTextSelection.SelSize: INTEGER; ABSTRACT;
{Invalidation}
PROCEDURE TTextSelection.Invalidate; DEFAULT;
{Generate Text Selection in another panel (ie. another Text Image)}
FUNCTION TTextSelection.ReplicateForOtherPanel(itsTextImage: TTextImage): TTextSelection;
END;
TInsertionPoint = SUBCLASS OF TTextSelection
typingCmd:
styleCmdNumber:
TTypingCmd;
INTEGER;
newestLP:
justReturned:
INTEGER;
BOOLEAN;
nextHighTransit:
nextTransitTime:
THighTransit;
LONGINT;
{Creation/Freeing}
FUNCTION TInsertionPoint.CREATE(object: TObject; heap: THeap; itsView: TView;
itsTextImage: TTextImage; itsAnchorLPt: LPoint; itsParagraph: TEditPara;
itsIndex: LONGINT; itsLP: INTEGER): TInsertionPoint;
{Debugging}
{$IFC fParaTrace}
PROCEDURE TInsertionPoint.Fields(PROCEDURE Field(nameAndType: S255)); OVERRIDE;
{$ENDC}
{Commands}
PROCEDURE
PROCEDURE
PROCEDURE
FUNCTION
{Editing}
PROCEDURE TInsertionPoint.CutCopy(clipSelection: TSelection; deleteOriginal: BOOLEAN); OVERRIDE;
PROCEDURE TInsertionPoint.FinishPaste(clipSelection: TSelection; pic: PicHandle);
PROCEDURE TInsertionPoint.InsertText(text: TText; isParaSelection: BOOLEAN; isWordSelection: BOOLEAN;
universalText: BOOLEAN);
PROCEDURE TInsertionPoint.KeyBack(fWord: BOOLEAN); OVERRIDE;
PROCEDURE TInsertionPoint.KeyChar(ch: CHAR); OVERRIDE;
PROCEDURE TInsertionPoint.KeyClear; OVERRIDE;
PROCEDURE TInsertionPoint.KeyForward(fWord: BOOLEAN); OVERRIDE;
{Selecting}
PROCEDURE TInsertionPoint.MouseMove(mouseLPt: LPoint); OVERRIDE;
PROCEDURE TInsertionPoint.MousePress(mouseLPt: LPoint); OVERRIDE;
PROCEDURE TInsertionPoint.MouseRelease; OVERRIDE;
END;
TOneParaSelection = SUBCLASS OF TTextSelection
anchorBegin:
INTEGER;
anchorEnd:
INTEGER;
{anchorBegin <> anchorEnd iff double or triple click}
{Creation/Freeing}
FUNCTION TOneParaSelection.CREATE(object: TObject; heap: THeap; itsView: TView;
itsTextImage: TTextImage; itsAnchorLPt: LPoint; itsParagraph: TEditPara;
itsIndex: LONGINT; oldLP: INTEGER; currLP: INTEGER): TOneParaSelection;
{Debugging}
{$IFC fParaTrace}
PROCEDURE TOneParaSelection.Fields(PROCEDURE Field(nameAndType: S255)); OVERRIDE;
{$ENDC}
{Commands}
PROCEDURE TOneParaSelection.StyleFromContext; OVERRIDE;
{Editing}
FUNCTION TOneParaSelection.CopySelf(heap: THeap; view: TView): TMultiParaSelection; OVERRIDE;
PROCEDURE TOneParaSelection.DeleteAndFree; OVERRIDE;
FUNCTION TOneParaSelection.DeleteButSave: TText; OVERRIDE;
{Selecting}
PROCEDURE TOneParaSelection.MouseMove(mouseLPt: LPoint); OVERRIDE;
PROCEDURE TOneParaSelection.MouseRelease; OVERRIDE;
END;
TMultiParaSelection
anchorPara:
anchorIndex:
anchorBegin:
anchorEnd:
= SUBCLASS OF TTextSelection
TEditPara;
LONGINT;
INTEGER;
INTEGER;
{anchorBegin <> anchorEnd iff double or triple click}
{Creation/Freeing}
FUNCTION TMultiParaSelection.CREATE(object: TObject; heap: THeap; itsView: TView;
itsTextImage: TTextImage; itsAnchorLPt: LPoint;
beginPara: TEditPara; beginIndex: LONGINT; beginLP: INTEGER;
endPara: TEditPara; endIndex: LONGINT; endLP: INTEGER;
beginIsAnchor: BOOLEAN): TMultiParaSelection;
{Debugging}
{$IFC fParaTrace}
PROCEDURE TMultiParaSelection.Fields(PROCEDURE Field(nameAndType: S255)); OVERRIDE;
{$ENDC}
{Commands}
PROCEDURE TMultiParaSelection.StyleFromContext; OVERRIDE;
{Editing}
FUNCTION
FUNCTION
PROCEDURE
FUNCTION
TMultiParaSelection.CopySelf(heap:
TMultiParaSelection.Delete(saveIt:
TMultiParaSelection.DeleteAndFree;
TMultiParaSelection.DeleteButSave:
{Selecting}
PROCEDURE TMultiParaSelection.MouseMove(mouseLPt: LPoint); OVERRIDE;
PROCEDURE TMultiParaSelection.MouseRelease; OVERRIDE;
END;
{-------------
COMMANDS
-----------------}
TText;
TText;
TText;
TTextSelection;
LONGINT;
LONGINT;
INTEGER;
INTEGER;
TEditPara;
{handle to most recently filtered paragraph}
TArray;
{changed type styles of most recently filtered paragraph}
TText;
TTextRange;
TText;
BOOLEAN;
BOOLEAN;
BOOLEAN;
TText;
TText;
INTEGER;
INTEGER;
TTextRange;
TList;
BOOLEAN;
BOOLEAN;
IMPLEMENTATION
(*
{$I UTEXT2.text}
{$I UTEXT3.text}
{$I UTEXT4.text}
*)
{Paragraph classes}
{TStyleSheet, TText, TTextImage, TTextView}
{Text Selections and Commands}
{$I LibTK/UTEXT2.text}
{Paragraph classes}
{$I LibTK/UTEXT3.text}
{$I LibTK/UTEXT4.text}
END.
{UText2}
{changed
{changed
{changed
{changed
{Paragraph Classes}
05/11/84
04/25/84
04/18/84
04/17/84
1135
1250
1652
1806
04/13/84
04/13/84
04/12/84
04/11/84
04/11/84
04/10/84
04/10/84
1739
1537
2344
1527
1454
1400
1158
Added TParagraph.Clone}
Changed FilterAndDo calls back to filtering TParaImage for Compugraphic}
Use TTextImage.firstLinePixel in DrawParaImage}
Put call to ReplTString outside of IF in ReplPara;
Put more parameter checks in ReplTString}
Added styleSheet field to TParaFormat; use it in ChangeRefCountBy}
Put PicTextBegin, End in TParagraph.DrawLine;
Put PicGrpBegin, End in TParaImage.RedrawLines;
Removed picture comments from TParaImage.DrawLine}
Set paraformat.refcount = 0 in TParaFormat.Clone}
Changed calls to FilterAndDo to pass TEditPara rather than TParaImage}
Modified UpdateRuns to use new parameter list}
Call UpdateRuns after deleting characters in TParagraph.ReplPString and ReplTString}
Debug statement in Qualifies to check bug involving special characters}
Changed TEditPara.images field back to a TList and adusted references to it}
Put calls to TParaFormat.ChangeRefCountBy in TEditPara.CREATE, Free}
{$IFC fRngABC}
{$R+}
{$ELSEC}
{$R-}
{$ENDC}
{$IFC fSymABC}
{$D+}
{$ELSEC}
{$D-}
{$ENDC}
TYPE
TScanState = (cBeforeRange, cInRange, cAfterRange);
TFakeTStyle = PACKED ARRAY[1..SIZEOF(TTypeStyle)] OF CHAR;
{$IFC LibraryVersion <= 20}
Style = TSeteface;
FontInfo = TFinfo;
{$ENDC}
{$S SgTxtHot}
VAR nextHighTransit:
THighTransit;
nextTransitTime:
uvFont:
LONGINT;
ARRAY [1..14] OF TFontRecord;
METHODS OF TParaFormat;
{$S SgTxtIni}
FUNCTION TParaFormat.CREATE(object: TObject; heap: THeap; itsStyleSheet: TStyleSheet): TParaFormat;
VAR tabArray:
TArray;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TParaFormat(object);
tabArray := TArray.CREATE(NIL, heap, 0, SIZEOF(TTxtTabDescriptor));
WITH SELF DO
BEGIN
{$H-}
MakeTypeStyle(famModern, size12Pitch, [], dfltTstyle);
{$H+}
wordWrap := TRUE;
quad := aLeft;
firstIndent := 0;
leftIndent := 0;
rightIndent := 0;
spaceAbovePara := 0;
spaceBelowPara := 0;
lineSpacing := 0;
tabs := tabArray;
permanent := FALSE;
refCount := 0;
styleSheet := itsStyleSheet;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TParaFormat.Free;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
Free(SELF.tabs);
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
FUNCTION TParaFormat.Clone(heap: THeap): TObject;
VAR tabs:
TArray;
paraFormat: TParaFormat;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
tabs := TArray(SELF.tabs.Clone(heap));
paraFormat := TParaFormat(SUPERSELF.Clone(heap));
paraFormat.tabs := tabs;
paraFormat.refCount := 0;
Clone := paraFormat;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
{$IFC fParaTrace}
PROCEDURE TParaFormat.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('dfltTstyle: RECORD onFaces: HexByte; filler: HexByte; fontFamily: Byte; fontSize: Byte END');
Field('wordWrap: BOOLEAN');
Field('quad: HexByte');
Field('firstIndent: INTEGER');
Field('leftIndent: INTEGER');
Field('rightIndent: INTEGER');
Field('spaceAbovePara: INTEGER');
Field('spaceBelowPara: INTEGER');
Field('lineSpacing: INTEGER');
Field('tabs: TArray');
Field('refCount: INTEGER');
Field('permanent: BOOLEAN');
Field('styleSheet: BOOLEAN');
Field('');
END;
{$ENDC}
{$S SgTxtCld}
PROCEDURE TParaFormat.ChangeRefCountBy(delta: INTEGER);
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.refCount := SELF.refCount + delta;
IF (SELF.refCount <= 0) AND NOT SELF.permanent THEN
BEGIN
IF SELF.styleSheet <> NIL THEN
SELF.styleSheet.formats.DelObject(SELF, TRUE)
ELSE
SELF.Free;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TParaFormat.SetTypeStyle(tStyle: TTypeStyle);
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SetQDTypeStyle(tStyle);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtIni}
BEGIN
UnitAuthor('Apple');
END;
METHODS OF TParagraph;
{$S SgTxtIni}
FUNCTION TParagraph.CREATE(object: TObject; heap: THeap;
initialSize: INTEGER; initialTypeStyle: TTypeStyle): TParagraph;
VAR ts:
TArray;
styleChange:
TStyleChange;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF object = NIL THEN
object := NewDynObject(heap, THISCLASS, initialSize);
SELF := TParagraph(TString.CREATE(object, heap, initialSize));
ts := TArray.CREATE(NIL, heap, 0, SIZEOF(TStyleChange));
styleChange.lp := MAXINT; { -sentinel- }
styleChange.newStyle := initialTypeStyle;
ts.InsAt(1, @styleChange);
styleChange.lp := -1;
ts.InsAt(1, @styleChange);
SELF.typeStyles := ts;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TParagraph.Free;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
Free(SELF.typeStyles);
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
FUNCTION TParagraph.Clone(heap: THeap): TObject;
VAR paragraph: TParagraph;
styles:
TArray;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
styles := TArray(SELF.typeStyles.Clone(heap));
paragraph := TParagraph(SUPERSELF.Clone(heap));
paragraph.typeStyles := styles;
Clone := paragraph;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
{$IFC fParaTrace}
PROCEDURE TParagraph.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field(CONCAT('typeStyles: TArray OF RECORD lp: INTEGER; onFaces: HexByte; ',
'filler: HexByte; fontFamily: Byte; fontSize: Byte END'));
Field('');
END;
{$ENDC}
{$S TK2Start}
{BuildExtentLRect takes an LPoint that indicates the baseline of the paragraph. It returns
in extentLRect the bounding rectangle whose height is based on the tallest font in the
paragraph and width is the width of the characters in the paragraph.}
PROCEDURE TParagraph.BuildExtentLRect(baseLPt: LPoint; VAR extentLRect: LRect);
VAR styleChange:
TStyleChange;
fInfo:
FontInfo;
i:
INTEGER;
tallestFont:
FontInfo;
width:
INTEGER;
oldTallest:
INTEGER;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
oldTallest := 0;
FOR i := 1 to SELF.typeStyles.size - 1 DO
BEGIN
SELF.typeStyles.GetAt(i, @styleChange);
SELF.SetTypeStyle(styleChange.newStyle);
GetFontInfo(fInfo);
WITH fInfo DO
IF oldTallest < ascent + descent + leading THEN
BEGIN
oldTallest := ascent + descent + leading;
tallestFont := fInfo;
END;
END;
width := SELF.Width(1, SELF.size);
WITH extentLRect, baseLPt, tallestFont DO
BEGIN
top := v - ascent;
bottom := v + descent + leading;
left := h;
right := h + width;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TParagraph.ChangeStyle(startLP, endLP: INTEGER; PROCEDURE Change(VAR typeStyle: TTypeStyle);
VAR styleOfStartLP: TTypeStyle);
VAR firstChange:
TStyleChange;
tempChange:
TStyleChange;
prevChange:
TStyleChange;
styles:
TArray;
styleIndex:
INTEGER;
newStyle:
TTypeStyle;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
{$IFC fParaTrace}
IF fParaTrace THEN
BEGIN
WriteLn('=== Entering TParagraph.ChangeStyle: startLP=', startLP:1, ' endLP=', endLP:1);
END;
{$ENDC}
styles := SELF.typeStyles;
styleIndex := 1;
REPEAT
styleIndex := styleIndex + 1;
styles.GetAt(styleIndex, @tempChange);
UNTIL tempChange.lp >= startLP;
{If the change is on a run boundary, just remember the changed style at the beginning so
BEGIN
IF newOnFaces = [] THEN
typeStyle.onFaces := []
ELSE
typeStyle.onFaces := typeStyle.onFaces + newOnFaces;
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.ChangeStyle(startLP, endLP, ChangeFace, styleOfStartLP);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TParagraph.ChgFontFamily(startLP, endLP: INTEGER; newFontFamily: Byte;
VAR styleOfStartLP: TTypeStyle);
PROCEDURE ChangeFamily(VAR typeStyle: TTypeStyle);
BEGIN
typeStyle.font.fontFamily := newFontFamily;
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.ChangeStyle(startLP, endLP, ChangeFamily, styleOfStartLP);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TParagraph.ChgFontSize(startLP, endLP: INTEGER; newFontSize: Byte;
VAR styleOfStartLP: TTypeStyle);
PROCEDURE ChangeSize(VAR typeStyle: TTypeStyle);
BEGIN
typeStyle.font.fontSize := newFontSize;
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.ChangeStyle(startLP, endLP, ChangeSize, styleOfStartLP);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
{Deletes redundant run information}
PROCEDURE TParagraph.CleanRuns;
VAR styleChange:
TStyleChange;
prevChange:
TStyleChange;
styles:
TArray;
styleIndex:
INTEGER;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
styles := SELF.typeStyles;
styles.GetAt(1, @prevChange);
styleIndex := 2;
{Iterate through the style changes and delete any that have either the same lp as the previous
change or the same font and faces info}
WHILE styleIndex < styles.Size DO
BEGIN
styles.GetAt(styleIndex, @styleChange);
IF (styleChange.lp = prevChange.lp) OR
((styleChange.newStyle.onFaces = prevChange.newStyle.onFaces) AND
(styleChange.newStyle.font.fontNum = prevChange.newStyle.font.fontNum)) THEN
styles.DelAt(styleIndex)
ELSE
styleIndex := styleIndex + 1;
prevChange := styleChange;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TParagraph.Draw(i: LONGINT; howMany: INTEGER);
VAR dumInt:
INTEGER;
dumIndex:
INTEGER;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
dumIndex := 1;
SELF.DrawLine(i-1, i + howMany - 2, TRUE, FALSE, dumInt, dumIndex);
{$IFC fTrace}EP;{$ENDC}
END;
{$S TK2Start}
PROCEDURE TParagraph.DrawLine(startLP, endLP: INTEGER; fDraw: BOOLEAN; fWidth: BOOLEAN;
VAR width: INTEGER; VAR styleIndex: INTEGER);
{If fDraw = TRUE, draws a line of characters from startLP to endLP; does not worry about word wrap.
If fWidth = TRUE, returns width of characters. Also accepts an initial styleIndex (index into
run array) to make typestyle scanning faster. Returns styleIndex of run of last character drawn.}
{IDEAS TO MAKE THIS FASTER:
special check to see if there are no typestyle changes in this para?
}
VAR startPP:
endPP:
INTEGER;
INTEGER;
styleChange:
TStyleChange;
prevChange:
TStyleChange;
tStyles:
TArray;
drawCount:
INTEGER;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
{$IFC fParaTrace}
IF fParaTrace THEN
BEGIN
writeln('>> DrawLine: startLP=', startLP:1, ' endLP=', endLP:1,
' styleIndex=', styleIndex:1);
WriteLn('>> DrawLine: fDraw=', fDraw, ' holeStart =', SELF.holeStart:1,
' holeSize =', SELF.holeSize:1);
END;
{$ENDC}
width := 0;
tStyles := SELF.typeStyles;
IF (styleIndex < 1) OR (styleIndex > tStyles.size) THEN
styleIndex := 1;
tStyles.GetAt(styleIndex, @styleChange);
prevChange := styleChange;
WHILE styleChange.lp < startLP DO
BEGIN
prevChange := styleChange;
styleIndex := styleIndex + 1;
tStyles.GetAt(styleIndex, @styleChange);
END;
PicTextBegin(aLeft);
SELF.SetTypeStyle(prevChange.newStyle);
{$IFC fParaTrace}
IF fParaTrace THEN
writeln('>> DrawLine: starting to Draw');
{$ENDC}
WHILE startLP <= endLP DO
BEGIN
drawCount := MIN(styleChange.lp, endLP+1) - startLP;
IF fWidth THEN
width := width + TString.Width(startLP+1, drawCount);
IF fDraw THEN
BEGIN
{$IFC fParaTrace}
IF fParaTrace THEN
writeln('>> DrawLine: About to call DrawText; startLP,drawCount=', startLP:1,
',', drawCount:1);
{$ENDC}
TString.Draw(startLP+1, drawCount);
END;
startLP := startLP + drawCount;
IF startLP = styleChange.lp THEN
BEGIN
{$IFC fParaTrace}
IF fParaTrace THEN
writeln('>> DrawLine: found a typestyle change at LP=', startLP:1);
{$ENDC}
SELF.SetTypeStyle(styleChange.newStyle);
styleIndex := styleIndex+1;
tStyles.GetAt(styleIndex, @styleChange)
END;
END;
PicTextEnd;
styleIndex := styleIndex-1; {return styleIndex of current typeStyle run}
{$IFC fParaTrace}
IF fParaTrace THEN
BEGIN
Writeln('>> DrawLine: Finished, width=', width:1);
WriteLn;
END;
{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtWrm}
PROCEDURE TParagraph.FindWordBounds(orig: INTEGER; VAR first, last: INTEGER);
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
first := orig;
last := orig;
IF SELF.Qualifies(orig) THEN
BEGIN
WHILE SELF.Qualifies(first - 1) DO first := first - 1;
WHILE SELF.Qualifies(last + 1) DO last := last + 1;
END;
IF last < SELF.size THEN
last := last+1; {always selects at least one character, except at end of para}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
FUNCTION TParagraph.FixLP(LP: INTEGER): INTEGER;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF LP < 0 THEN
FixLP := 0
ELSE IF LP >= SELF.size THEN
FixLP := SELF.size
ELSE
FixLP := LP;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TParagraph.NewStyle(startLP, endLP: INTEGER; newTypeStyle: TTypeStyle);
VAR styleOfStartLP: TTypeStyle;
PROCEDURE ChgStyle(VAR typeStyle: TTypeStyle);
BEGIN
typeStyle := newTypeStyle;
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.ChangeStyle(startLP, endLP, ChgStyle, styleOfStartLP);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtWrm}
FUNCTION TParagraph.Qualifies(pos: INTEGER): BOOLEAN;
VAR i,j:
INTEGER;
left, this, right: CHAR;
FUNCTION CharClass(ch: CHAR): CHAR;
VAR c: INTEGER;
BEGIN
c := ORD(ch);
IF c IN [65..90, 97..122, 128..159, 167, 174..175,
187..188, 190..191, 202] THEN ch := 'A'
ELSE IF (48 <= c) AND (c <= 57) THEN ch := '9'
ELSE IF (c = 162) OR (c = 163) OR (c = 180) THEN ch := '$';
CharClass := ch;
END;
FUNCTION CharAt(i: INTEGER): CHAR;
BEGIN
IF i < 0 THEN
CharAt := ' '
ELSE IF i >= SELF.size THEN
CharAt := ' '
ELSE
CharAt := SELF.At(i+1);
END;
BEGIN {Qualifies}
{$IFC fTrace}BP(9);{$ENDC}
left := CharClass(CharAt(pos-1));
this := CharClass(CharAt(pos));
right := CharClass(CharAt(pos+1));
{$IFC fParaTrace}
IF fParaTrace THEN
WriteLn('IN QUALIFIES: left, this, right = (', left:1, this:1, right:1, ')
ORD(left):1, ',', ORD(this):1, ',', ORD(right):1, ']');
{$ENDC}
=> [',
styleChange.lp := fPos+otherNumChars;
styles.InsAt(styleIndex, @styleChange);
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TParagraph.ReplPString(fPos, numChars: INTEGER; pStr: TPString);
VAR otherNumChars: INTEGER;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
{ make fPos lie within [0..# chars in paragraph] }
fPos := SELF.fixLP(fPos);
IF pStr = NIL THEN
otherNumChars := 0
ELSE
otherNumChars := Length(pStr^);
SELF.StartEdit(otherNumChars);
SELF.DelManyAt(fPos + 1, numChars);
(*
SELF.UpdateRuns(fPos,-numChars);
*)
IF pStr <> NIL THEN
SELF.InsPStrAt(fPos + 1, pStr);
SELF.StopEdit;
SELF.UpdateRuns(fPos, numChars, otherNumChars);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TParagraph.ReplTString(fPos, numChars: INTEGER;
otherString: TString; otherFPos, otherNumChars: INTEGER);
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
{ make fPos lie within [0..# chars in paragraph] }
fPos := SELF.fixLP(fPos);
SELF.StartEdit(otherNumChars);
IF numChars > 0 THEN
SELF.DelManyAt(fPos + 1, numChars);
IF (otherString <> NIL) AND (otherNumChars > 0) THEN
SELF.InsManyAt(fPos + 1, otherString, otherFPos + 1, otherNumChars);
SELF.StopEdit;
SELF.UpdateRuns(fPos, numChars, otherNumChars);
{$IFC fTrace}EP;{$ENDC}
END;
{$S TK2Start}
PROCEDURE TParagraph.SetTypeStyle(tStyle: TTypeStyle);
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SetQDTypeStyle(tStyle);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TParagraph.StyleAt(lp: INTEGER; VAR typeStyle: TTypeStyle);
VAR styleChange:
TStyleChange;
styles:
TArray;
styleIndex:
INTEGER;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
styles := SELF.typeStyles;
styleIndex := 1;
styles.GetAt(1, @styleChange);
WHILE styleChange.lp <= lp DO
BEGIN
typeStyle := styleChange.newStyle;
styleIndex := styleIndex+1;
styles.GetAt(styleIndex, @styleChange);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TParagraph.UpdateRuns(atLP: INTEGER; replacedChars: INTEGER; insertedChars: INTEGER);
VAR tStyles:
TArray;
i:
INTEGER;
aChange:
TStyleChange;
tempChange:
TStyleChange;
prevStyle:
TTypeStyle;
lastDeleted:
INTEGER;
BEGIN
{$IFC fTrace}BP(8);{$ENDC}
tStyles := SELF.typeStyles;
lastDeleted := -1;
i := 1;
WHILE i <= tStyles.size DO
BEGIN
tStyles.GetAt(i, @aChange);
IF atLP <= aChange.lp THEN
BEGIN
IF i < tStyles.size THEN
aChange.lp := aChange.lp - replacedChars;
{if we deleted some chars, we must delete associated run info}
IF aChange.lp <= atLP THEN
BEGIN
{save type style since we may have deleted only part of this run}
tempChange := aChange;
{assume whole run deleted, reinsert later if not}
tStyles.DelAt(i);
lastDeleted := i;
i := i-1;
END
ELSE
BEGIN
IF i = lastDeleted THEN
{put back run info for last run deleted if part of it still remains and is not
the same as the run before the changes}
IF (aChange.lp <> atLP) AND
(TFakeTStyle(tempChange.newStyle) <> TFakeTStyle(prevStyle)) THEN
BEGIN
tempChange.lp := atLP + insertedChars;
tStyles.InsAt(i, @tempChange);
i := i+1;
END;
IF i < tStyles.size THEN
BEGIN
aChange.lp := aChange.lp + insertedChars;
tStyles.PutAt(i, @aChange);
END;
END;
END
ELSE
prevStyle := aChange.newStyle;
i := i+1;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S TK2Start}
FUNCTION TParagraph.Width(i: LONGINT; howMany: INTEGER): INTEGER;
VAR theWidth:
INTEGER;
dumIndex:
INTEGER;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
dumIndex := 1;
SELF.DrawLine(i-1, i + howMany - 2, FALSE, TRUE, theWidth, dumIndex);
Width := theWidth;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtIni}
BEGIN
fParaTrace := FALSE;
END;
METHODS OF TEditPara;
{$S SgTxtCld}
FUNCTION TEditPara.CREATE(object: TObject; heap: THeap; initialSize: INTEGER;
itsFormat: TParaFormat): TEditPara;
VAR imgList:
TList;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF object = NIL THEN
object := NewDynObject(heap, THISCLASS, initialSize);
SELF := TEditPara(TParagraph.CREATE(object, heap, initialSize, itsFormat.dfltTStyle));
imgList := TList.CREATE(NIL, heap, 0);
WITH SELF DO
BEGIN
bsCount := 0;
nestLevel := 0;
format := itsFormat;
beingFiltered := FALSE;
(*
numImages := 0;
maxImages := 1;
images[1] := NIL;
*)
images := imgList;
END;
itsFormat.ChangeRefCountBy(1);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TEditPara.Free;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.format.ChangeRefCountBy(-1);
SELF.images.FreeObject; {Free the list, but not its members}
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
{$IFC fParaTrace}
PROCEDURE TEditPara.Fields(PROCEDURE Field(nameAndType: S255));
VAR str:
STR255;
BEGIN
SUPERSELF.Fields(Field);
Field('bsCount: INTEGER');
Field('nestLevel: INTEGER');
Field('format: TParaFormat');
Field('beingFiltered: BOOLEAN');
(*
Field('maxImages: INTEGER');
Field('numImages: INTEGER');
IntToStr(SELF.numImages, @str);
Field(CONCAT('images: ARRAY[1..', CONCAT(str, '] OF TParaImage')));
*)
Field('images: TList');
Field('');
END;
{$ENDC}
{$S SgTxtHot}
PROCEDURE TEditPara.BeginInsertion(atLP: INTEGER; size:INTEGER);
{Changes the text buffer so that the empty space is located at position
expands the buffer (if necessary) so that there is at least size empty
(size = 0 means about to backspace; this does nothing if the paragraph
setup to backspace at atLP.)
}
BEGIN
{$IFC fTrace} BP(6); {$ENDC}
IF (atLP <> SELF.holeStart) OR (size <> 0) THEN {nothing to do--must be
BEGIN
SELF.EditAt(atLP + 1, size);
SELF.bsCount := 0;
END;
atLP;
characters.
is already
backspacing}
{$IFC fRngText}{$R+}{$ENDC}
numImages := numImages-numDeleted;
END;
END;
*)
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TEditPara.EachImage(PROCEDURE ImageProc(paraImage: TParaImage));
(*
VAR i: INTEGER;
*)
PROCEDURE DoIt(object: TObject);
BEGIN
ImageProc(TParaImage(object));
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.images.Each(DoIt);
(*
FOR i := 1 TO SELF.numImages DO
{$R-} ImageProc(SELF.images[i]); {$IFC fRngText}{$R+}{$ENDC}
*)
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TEditPara.EndInsertion;
{After calling this:
holeStart = emptyPos = # chars in paragraph
}
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
SELF.StopEdit;
SELF.bsCount := 0;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
FUNCTION TEditPara.GrowSize: INTEGER;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
GrowSize := 200;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TEditPara.InsertOneChar(ch: CHAR; atLP: INTEGER);
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.BeginInsertion(atLP, 1);
{UNDO}
{ now we have SELF.holeStart = atLP }
SELF.PutAt(atLP+1, ch);
SELF.UpdateRuns(atLP, 0, 1);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TEditPara.InsImage(paraImage: TParaImage);
(*
VAR i:
INTEGER;
found: BOOLEAN;
*)
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.images.InsLast(paraImage);
(*
IF SELF.numImages = SELF.maxImages THEN
BEGIN
SELF.ResizeCollection(SELF.size + SELF.holeSize + 4);
SELF.ShiftCollection(0, 4, SELF.size + SELF.holeSize);
WITH SELF DO
BEGIN
dynStart := dynStart + 4;
maxImages := maxImages + 1;
END;
END;
WITH SELF DO
BEGIN
numImages := numImages + 1;
{$R-}
images[numImages] := paraImage;
{$IFC fRngText}{$R+}{$ENDC}
END;
*)
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TEditPara.SetTypeStyle(tStyle: TTypeStyle);
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.format.SetTypeStyle(tStyle);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtIni}
END;
METHODS OF TLineInfo;
{$S SgTxtWrm}
FUNCTION TLineInfo.CREATE(object: TObject; heap: THeap): TLineInfo;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TLineInfo(object);
WITH SELF DO
BEGIN
valid := FALSE;
startLP := 0;
lastDrawnLP := 0;
endLP := 0;
lineLRect := zeroLRect;
lineAscent := 0;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
{$IFC fParaTrace}
PROCEDURE TLineInfo.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('valid: BOOLEAN');
Field('startLP: INTEGER');
Field('lastDrawnLP: INTEGER');
Field('endLP: INTEGER');
Field('lineLRect: LRect');
Field('lineAscent: INTEGER');
Field('');
END;
{$ENDC}
{$S SgTxtHot}
FUNCTION TLineInfo.LeftCoord(proposedLeftPixel: LONGINT): LONGINT;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
{Default is to not change the parameter; TLineInfo subclassers may choose to do otherwise}
LeftCoord := proposedLeftPixel;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
FUNCTION TLineInfo.RightCoord(proposedRightPixel: LONGINT): LONGINT;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
{Default is to not change the parameter; TLineInfo subclassers may choose to do otherwise}
RightCoord := proposedRightPixel;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtIni}
END;
METHODS OF TParaImage;
{$S SgTxtWrm}
FUNCTION TParaImage.CREATE(object: TObject; heap: THeap; itsView: TView; itsParagraph: TEditPara;
itsLRect: LRect; lineTop: LONGINT; lineLeft: LONGINT): TParaImage;
VAR aLineList: TList;
lineInfo:
TLineInfo;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TParaImage(TImage.CREATE(object, heap, itsLRect, itsView));
SELF.paragraph := itsParagraph;
SELF.extentLRect := itsLRect;
aLineList := TList.CREATE(NIL, heap, 0);
lineInfo := SELF.DfltLineInfo(lineTop, lineLeft);
aLineList.InsLast(lineInfo);
WITH SELF DO
BEGIN
height := lineInfo.lineLRect.bottom - lineInfo.lineLRect.top;
lineList := aLineList;
tickcount := 0;
changed := TRUE;
startLP := 0;
endLP := 0;
textImage := NIL;
wasOffset := FALSE;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtWrm}
PROCEDURE TParaImage.Free;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
Free(SELF.lineList);
(* Since caller of this may be scanning the paragraph's image list we can't delete it from the
list here lest we screw up the caller's scanner. So the caller will have to to do this}
SELF.paragraph.DelImage(SELF, FALSE);
*)
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
{$IFC fParaTrace}
PROCEDURE TParaImage.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('paragraph: TEditPara');
Field('height: INTEGER');
Field('lineList: TList');
Field('changed: BOOLEAN');
Field('tickCount: INTEGER');
Field('startLP: INTEGER');
Field('endLP: INTEGER');
Field('textImage: TTextImage');
Field('wasOffset: BOOLEAN');
Field('');
END;
{$ENDC}
{$S SgTxtHot}
PROCEDURE TParaImage.AdjustLineLPs(atLP, deltaLP: INTEGER);
{positive deltaLP implies character(s) were inserted, negative deltaLP implies they were deleted}
PROCEDURE AdjustLP(obj: TObject);
BEGIN
WITH TLineInfo(obj) DO
BEGIN
{$H-}
IF startLP > atLP THEN
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.lineList.Each(AdjustLP);
WITH SELF DO
BEGIN
{$H-}
IF startLP > atLP THEN
startLP := Max(atLP, startLP + deltaLP);
IF endLP >= atLP THEN
endLP := Max(atLP, endLP + deltaLP);
{$H+}
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TParaImage.ComputeLineInfo(curLine: TLineInfo; maxLineLen: INTEGER;
VAR nextLP: INTEGER; VAR lRectNeeded: LRect);
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtWrm}
FUNCTION TParaImage.DfltLineInfo(lineTop: LONGINT; lineLeft: LONGINT): TLineInfo;
VAR lineInfo:
TLineInfo;
fInfo:
FontInfo;
i:
INTEGER;
format:
TParaFormat;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
lineInfo := TLineInfo.CREATE(NIL, SELF.Heap);
format := SELF.GetFormat;
format.SetTypeStyle(format.dfltTStyle);
GetFontInfo(fInfo);
i := SELF.paragraph.size;
maxLP:
INTEGER;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
{$IFC fParaTrace}
IF fParaTrace THEN
writeln('** DrawLine: startLP=', startLP:1, ', maxLP=',maxLP:1, ', fDraw=', fDraw,
', stopWidth=',stopWidth:1, ', wrapWidth=',wrapWidth:1);
{$ENDC}
maxLP := SELF.paragraph.size-1;
IF maxLP < startLP THEN
BEGIN
lineWidth := 0;
lastToDraw := maxLP;
endLP := maxLP;
END
ELSE
BEGIN
paragraph := SELF.paragraph;
format := SELF.GetFormat;
breakIndex := 0;
lastToDraw := 0;
lineWidth := 0;
cWidth := 0;
curIndex := paragraph.FixLP(startLP);
styles := paragraph.typeStyles;
styles.GetAt(1, @styleChange);
styleIndex := 1;
REPEAT
prevChange := styleChange;
styleIndex := styleIndex + 1;
styles.GetAt(styleIndex, @styleChange);
UNTIL curIndex < styleChange.lp;
format.SetTypeStyle(prevChange.newStyle);
firstStyleIndex := styleIndex-1;
startPP := curIndex;
maxPP := MIN(paragraph.size, paragraph.FixLP(maxLP));
{$IFC fParaTrace}
IF fParaTrace THEN
writeln('** DrawLine: About enter loop, maxPP =',maxPP:1,'
' holeSize=',paragraph.holeSize:1);
{$ENDC}
WHILE curIndex <= maxPP DO
BEGIN
holeStart=',paragraph.holeStart:1,
1:
lastToDraw := curIndex;
{$IFC fParaTrace}
IF fParaTrace THEN
writeln('** DrawLine: About to figure endLP, curIndex =',curIndex:1);
{$ENDC}
endLP := curIndex;
{$IFC fParaTrace}
IF fParaTrace THEN
writeln('** DrawLine: endLP figured =',endLP:1);
{$ENDC}
IF (lastToDraw >= 0) AND fDraw THEN
SELF.FastDrawLine(paragraph.fixLP(startLP), lastToDraw, TRUE,
FALSE, dummy, firstStyleIndex);
END;
{$IFC fParaTrace}
IF fParaTrace THEN
BEGIN
writeln('** DrawLine done: endLP=',endLP:1,', lineWidth=',lineWidth:1);
writeln('** DrawLine done: final lastToDraw=',lastToDraw:1);
WriteLn;
END;
{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TParaImage.DrawParaImage(limitLRect: LRect; startLP: INTEGER; drawAction: TDrawAction;
invalBits: BOOLEAN; VAR drawnLRect: LRect);
{Note: DrawParaImage now assumes that the paragraph was changed}
LABEL 1;
VAR paragraph:
TEditPara;
fInfo:
FontInfo;
lineInfo:
TLineInfo;
firstLineInfo: TLineInfo;
lineList:
TList;
lineSpacing:
INTEGER;
curBase:
LONGINT;
leftMargin:
LONGINT;
curLP:
INTEGER;
endLP:
INTEGER;
numChars:
INTEGER;
lineLen:
INTEGER;
maxLineLen:
INTEGER;
lineIndex:
INTEGER;
pixel:
LONGINT;
lastDrawnLP:
INTEGER;
testLPoint:
LPoint;
format:
TParaFormat;
firstFudge:
INTEGER;
startOfNewPara: BOOLEAN;
anLRect:
LRect;
sLine:
TListScanner;
genRest:
BOOLEAN;
genBefore:
BOOLEAN;
oldEndLP:
INTEGER;
prevLineInfo:
TLineInfo;
prevLen:
INTEGER;
prevPImage:
TParaImage;
prevTxtImage:
TTextImage;
origStart:
INTEGER;
dummy:
INTEGER;
styleIndex:
INTEGER;
r:
LRect;
{$IFC fParaTrace}
str:
STR255;
{$ENDC}
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
{$IFC fParaTrace}
IF fParaTrace THEN
BEGIN
WITH limitLRect DO
WriteLn('## Entering DrawParaImage: limitLRect=[(',left:1,',',top:1,'),(',
right:1,',', bottom:1,')]');
LIntToHex(ORD(SELF), @str);
WriteLn(
'
SELF = ', str,' startLP=',startLP:1,' drawAction=',ORD(drawAction));
END;
{$ENDC}
drawnLRect := limitLRect;
endLP := startLP;
paragraph := SELF.paragraph;
format := SELF.GetFormat;
IF drawAction = actionDraw THEN WITH SELF DO
tickCount := (tickCount+1) MOD MAXINT;
PicGrpBegin;
PenNormal;
genRest := FALSE;
genBefore := FALSE;
curLP := startLP;
numChars := paragraph.size;
SELF.startLP := curLP;
format.SetTypeStyle(format.dfltTStyle);
GetFontInfo(fInfo);
WITH fInfo DO
lineSpacing := ascent + descent + leading + format.lineSpacing;
lineList := SELF.lineList;
curBase := limitLRect.top;
prevLineInfo := NIL;
IF lineList.Size > 0 THEN
BEGIN
sLine := lineList.Scanner;
{If existing lineInfo's start after startLP then we need to generate preceeding lineInfo's}
IF TLineInfo(lineList.First).startLP > startLP THEN
BEGIN
origStart := TLineInfo(lineList.First).startLP;
genBefore := TRUE;
END
ELSE WHILE sLine.Scan(lineInfo) DO
BEGIN
{delete lineinfo's that start before the startLP parameter}
IF lineInfo.endLP < startLP THEN
sLine.Delete(TRUE)
ELSE
BEGIN
IF lineInfo.valid THEN
BEGIN
prevLineInfo := lineInfo;
curBase := lineInfo.lineLRect.bottom;
END
ELSE
GOTO 1;
END;
END;
END
ELSE
lineInfo := NIL;
1:
IF NOT genBefore THEN
IF lineInfo = NIL THEN
BEGIN
genRest := TRUE;
curLP := Max(startLP, SELF.endLP);
END
ELSE
curLP := Max(startLP, lineInfo.startLP);
startOfNewPara := curLP = 0;
curBase := curBase + fInfo.ascent;
IF startOfNewPara THEN
BEGIN
curBase := curBase + format.spaceAbovePara;
leftMargin := limitLRect.left + format.firstIndent;
{ The first line maxLineLen might be different (due to firstIndent)}
firstFudge := format.firstIndent - format.leftIndent;
END
ELSE
BEGIN
leftMargin := limitLRect.left + format.leftIndent;
firstFudge := 0;
END;
limitLRect.left := limitLRect.left + format.leftIndent;
limitLRect.right := limitLRect.right - format.rightIndent;
maxLineLen := lengthLRect(limitLRect, h) - firstFudge;
sLine.Replace(lineInfo, TRUE);
genRest := NOT sLine.Scan(lineInfo);
END;
{These two assignments distinguish (for the calling routine) whether an empty
paragraph did or did not fit in the limitLRect. Assuming curLP = 0, SELF.endLP
will be 0 for a paragraph that did fit and -1 for one that did not fit. The calling
routine checks this value against paragraph.size to see if the paragraph fit}
IF LPtInLRect(testLPoint, limitLRect) THEN
BEGIN
SELF.endLP := curLP;
{Erase the old line}
IF drawAction = actionDraw THEN
FillLRect(r, lPatWhite)
ELSE IF drawAction = actionInval THEN
thePad.InvalLRect(r);
END
ELSE
SELF.endLP := curLP-1;
{$IFC fParaTrace}
IF fParaTrace THEN
BEGIN
WriteLn('## DrawParaImage: Empty para or cannot fit; endLP set to ',SELF.endLP:1);
END;
{$ENDC}
END
{Otherwise, set up lineLRect and call DrawLine while there are still characters to display
and we still fit in limitLRect}
ELSE
BEGIN
{Layout line previous to first invalid line to see if characters from the
invalid line can wrap back. First, however, we must check for special case
of the previous line being in another textImage.}
IF NOT startOfNewPara AND (prevLineInfo = NIL) THEN
BEGIN
prevTxtImage := SELF.textImage.prevTxtImg;
IF prevTxtImage <> NIL THEN
BEGIN
prevPImage := TParaImage(prevTxtImage.imageList.Last);
prevLineInfo := TLineInfo(prevPImage.lineList.Last);
prevLen := LengthLRect(prevPImage.extentLRect, h) - format.leftIndent
- format.rightIndent;
END;
END
ELSE
BEGIN
prevLen := maxLineLen;
prevPImage := SELF;
END;
END;
END;
END;
END;
WITH fInfo DO
SetLRect(anLRect, leftMargin, curBase - ascent,
leftMargin + maxlineLen, curBase + descent + leading);
leftMargin := limitLRect.left;
{Setup GrafPort for first line (after prev line)}
IF drawAction = actionDraw THEN
MoveToL(leftMargin + firstFudge, curBase);
WHILE (curLP < numChars) AND (LPtInLRect(testLPoint, limitLRect)) DO
BEGIN
IF genRest OR genBefore THEN
lineInfo := TLineInfo.CREATE(NIL, paragraph.heap);
IF NOT lineInfo.valid THEN
BEGIN
WITH fInfo, lineInfo DO
BEGIN
startLP := curLP;
lineAscent := ascent;
lineLRect := anLRect;
END;
r := anLRect;
r.left := lineInfo.LeftCoord(SELF.textImage.extentLRect.left-1);
IF SELF.textImage.useFirstPixel THEN
BEGIN
r.left := Max(r.left, SELF.textImage.firstLinePixel);
SELF.textImage.useFirstPixel := FALSE;
END;
r.right := lineInfo.RightCoord(SELF.textImage.extentLRect.right+1);
IF drawAction = actionDraw THEN
FillLRect(r, lPatWhite)
ELSE IF drawAction = actionInval THEN
thePad.InvalLRect(r);
oldEndLP := lineInfo.endLP;
SELF.DrawLine(curLP, drawAction = actionDraw, maxLineLen, maxLineLen,
lineLen, lastDrawnLP, endLP);
{$IFC fParaTrace}
IF (curLP > endLP) AND (curLP < numChars)THEN
BEGIN
BEGIN
endLP := lineInfo.endLP;
oldEndLP := endLP;
END;
{This field is used by caller in case the entire paragraph didn't fit, so that the
caller knows where to start subsequent display}
SELF.endLP := endLP + 1;
{Setup for next line}
curLP := endLP+1;
curBase := curBase + lineSpacing;
maxLineLen := maxLineLen + firstFudge;
firstFudge := 0;
IF genBefore THEN
genBefore := origStart > curLP;
IF NOT (genRest OR genBefore) THEN
BEGIN
IF sLine.Scan(lineInfo) THEN
IF lineInfo.startLP <> curLP THEN
lineInfo.valid := FALSE
ELSE
ELSE
genRest := TRUE;
END;
{ setup GrafPort and lineRect for next line}
IF drawAction = actionDraw THEN
MoveToL(leftMargin, curBase);
WITH fInfo DO
SetLRect(anLRect,
leftMargin, curBase - ascent,
leftMargin + maxLineLen, curBase + descent + leading);
SetLPt(testLPoint, leftMargin, testLPoint.v + lineSpacing);
END; {WHILE}
END; {IF}
{We don't want to delete the lineInfo we just sLine.appended so advance scanner}
IF genBefore THEN
sLine.Skip(1);
IF NOT genRest THEN
REPEAT
sLine.Delete(TRUE);
UNTIL NOT sLine.Scan(lineInfo);
IF SELF.changed THEN
SELF.changed := NOT invalBits;
PicGrpEnd;
lineInfo := TLineInfo(SELF.lineList.Last);
firstLineInfo := TLineInfo(SELF.lineList.First);
SELF.height := lineInfo.lineLRect.bottom - firstLineInfo.lineLRect.top;
drawnLRect.bottom := lineInfo.lineLRect.bottom;
SELF.extentLRect := drawnLRect;
{$IFC fParaTrace}
IF fParaTrace THEN
BEGIN
WITH drawnLRect DO
WriteLn('## Exiting DrawParaImage: drawnLRect=[(',left:1,',',top:1,'),(',
right:1,',', bottom:1,')]',
'; height = ',SELF.height:1);
END;
{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TParaImage.Draw;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.RedrawLines(0, MAXINT);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TParaImage.FastDrawLine(startLP, endLP: INTEGER; fDraw: BOOLEAN; fWidth: BOOLEAN;
VAR width: INTEGER; VAR styleIndex: INTEGER);
{If fDraw = TRUE, draws a line of characters from startLP to endLP; does not worry about word wrap.
If fWidth = TRUE, returns width of characters. Also accepts an initial styleIndex (index into
run array) to make typestyle scanning faster. Returns styleIndex of run of last character drawn.}
VAR saveFormat: TParaFormat;
paragraph: TEditPara;
format:
TParaformat;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
paragraph := SELF.paragraph;
saveFormat := paragraph.format;
format := SELF.GetFormat;
paragraph.format := format;
paragraph.DrawLine(startLP, endLP, fDraw, fWidth, width, styleIndex);
paragraph.format := saveFormat;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
{Returns paragraph's paraFormat; can be overriden by application}
FUNCTION TParaImage.GetFormat: TParaFormat;
VAR styleIndex:
INTEGER;
BEGIN
{$IFC fTrace}BP(7);{$ENDC}
GetFormat := SELF.paragraph.format;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TParaImage.InvalLinesWith(startLP, endLP: INTEGER);
VAR s:
TListScanner;
lineInfo:
TLineInfo;
prevLineInfo:
TLineInfo;
numChars:
INTEGER;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
SELF.changed := TRUE;
s := SELF.lineList.Scanner;
IF s.Scan(prevLineInfo) THEN
BEGIN
WHILE s.Scan(lineInfo) DO
BEGIN
{If its already invalid, don't muck with it}
IF prevLineInfo.valid THEN
prevLineInfo.valid := (lineInfo.startLP <= startLP) OR (prevLineInfo.startLP > endLP);
prevLineInfo := lineInfo;
END;
{last line}
IF prevLineInfo.valid THEN
BEGIN
numChars := SELF.paragraph.size;
prevLineInfo.valid := (numChars < startLP) OR (prevLineInfo.startLP > endLP);
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtWrm}
IF LP < 0 THEN
LP := 0;
s := SELF.lineList.Scanner;
lineIndex := 0;
WHILE s.Scan(lineInfo) DO
BEGIN
IF LP < lineInfo.startLP THEN
s.Done
ELSE
BEGIN
lineIndex := lineIndex + 1;
lstLnInfo := lineInfo;
END;
END;
IF lineIndex=0 THEN
BEGIN
{$IFC fParaTrace}
IF fParaTrace THEN
writeln(chr(7), 'LocateLP: no TLineInfo in TParaImage, lineIndex=0');
{$ENDC}
lineIndex := 1;
lineInfo := SELF.DfltLineInfo(0, 0);
pixel := lineInfo.lineLRect.left - 1;
{ leave 1 pixel space before character }
SELF.lineList.InsLast(lineInfo);
END
ELSE
BEGIN
pixel := lstLnInfo.lineLRect.left + SELF.ParaTextWidth(lstLnInfo.startLP, LP-1) - 1;
{ leave 1 pixel space before character }
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
FUNCTION TParaImage.LpWithLPt(pt: LPoint): INTEGER;
VAR lineIndex: INTEGER;
lineInfo:
TLineInfo;
endLP:
INTEGER;
lineLen:
INTEGER;
charWid:
INTEGER;
paragraph: TEditPara;
wrapMargin: INTEGER;
lastLP:
INTEGER;
PROCEDURE DrawLine(obj: TObject); {This routine gets filtered after a type style change}
BEGIN
WHILE s.Scan(lineInfo) DO
{$H-}
OffsetLRect(lineInfo.lineLRect, h, v);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$H+}
{$S SgTxtHot}
{Returns width of characters in range startLP, endLP. (NOTE: startLP=endLP for width of one char)}
FUNCTION TParaImage.ParaTextWidth(startLP, endLP: INTEGER): INTEGER;
VAR styleIndex:
INTEGER;
width:
INTEGER;
PROCEDURE FastDraw(obj: TObject); {This routine gets filtered after a type style change}
BEGIN
SELF.FastDrawLine(startLP, endLP, FALSE, TRUE, width, styleIndex);
END;
BEGIN
{$IFC fTrace}BP(8);{$ENDC}
styleIndex := 1;
IF endLP < startLP THEN
width := 0
ELSE
SELF.FilterAndDo(SELF, FastDraw);
ParaTextWidth := width;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TParaImage.RedrawLines(startLine: INTEGER; endLine: INTEGER);
VAR s:
TListScanner;
i:
INTEGER;
lineInfo:
TLineInfo;
prevLineInfo:
TLineInfo;
styleIndex:
INTEGER;
dummy:
INTEGER;
PROCEDURE FastDraw(obj: TObject); {This routine gets filtered after a type style change}
BEGIN
SELF.FastDrawLine(lineInfo.startLP, lineInfo.lastDrawnLP, TRUE,
FALSE, dummy, styleIndex);
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
PicGrpBegin;
s := SELF.lineList.Scanner;
i := 0;
endLine := Min(endLine, SELF.lineList.Size);
startLine := Max(startLine, 1);
styleIndex := 1;
WHILE s.scan(lineInfo) DO
BEGIN
i := i+1;
IF i < startLine THEN {nothing}
ELSE
BEGIN
IF LRectIsVisible(lineInfo.lineLRect) THEN
BEGIN
{$IFC fParaTrace}
IF fParaTrace THEN
writeln('## ReDrawLines: About to call FastDraw; i=', i:1);
{$ENDC}
MoveToL(lineInfo.lineLRect.left, lineInfo.lineLRect.top+lineInfo.lineAscent);
SELF.FilterAndDo(SELF, FastDraw);
END;
IF i = endLine THEN
s.Done;
END;
END;
PicGrpEnd;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
FUNCTION TParaImage.SeesSameAs(image: TImage): BOOLEAN;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF SELF = image THEN
SeesSameAs := TRUE
ELSE IF NOT InClass(image, TParaImage) THEN
SeesSameAs := FALSE
ELSE
SeesSameAs := SELF.paragraph = TParaImage(image).paragraph;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtIni}
END;
{$S SgTxtIni}
{UText3}
{TStyleSheet, TText, TTextImage, TTextView, TTextWriteUnivText}
{changed
{changed
{changed
{changed
{changed
{changed
05/11/84
04/26/84
04/25/84
04/25/84
04/24/84
04/20/84
1135
1308
1250
1135
1637
1102
04/17/84
04/16/84
04/16/84
04/16/84
04/13/84
1110
1539
1446
1015
1818
{changed
{changed
{changed
{changed
04/13/84
04/13/84
04/10/84
04/09/84
1537
0209
1400
1337
{$S SgTxtHot}
METHODS OF TStyleSheet;
{$S SgTxtIni}
FUNCTION TStyleSheet.CREATE(object: TObject; heap: THeap): TStyleSheet;
VAR aList: TList;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TStyleSheet(object);
aList := TList.CREATE(NIL, heap, 0);
SELF.formats := aList;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TStyleSheet.Free;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
Free(SELF.formats);
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtIni}
PROCEDURE TStyleSheet.InitDefault;
VAR paraFormat: TParaFormat;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
paraFormat := TParaFormat.CREATE(NIL, SELF.Heap, SELF);
SELF.formats.InsLast(paraFormat);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
{$IFC fTextTrace}
PROCEDURE TStyleSheet.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('formats: TList');
Field('');
END;
{$ENDC}
{$S SgTxtIni}
END; {Methods of TStyleSheet}
METHODS OF TTextRange;
{$S SgTxtHot}
FUNCTION TTextRange.CREATE(object: TObject; heap: THeap;
beginPara: TEditPara; beginIndex: LONGINT; beginLP: INTEGER;
endPara: TEditPara; endIndex: LONGINT; endLP: INTEGER): TTextRange;
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TTextRange(object);
WITH SELF DO
BEGIN
firstPara := beginPara;
firstIndex := beginIndex;
firstLP := beginLP;
lastPara := endPara;
lastIndex := endIndex;
lastLP := endLP;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
{$IFC fTextTrace}
PROCEDURE TTextRange.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('firstPara: TEditPara');
Field('firstIndex: LONGINT');
Field('firstLP: INTEGER');
Field('lastPara: TEditPara');
Field('lastIndex: LONGINT');
Field('lastLP: INTEGER');
Field('');
END;
{$ENDC}
{$S SgTxtCld}
PROCEDURE TTextRange.AdjustBy(delta: INTEGER);
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtIni}
END;
METHODS OF TText;
{$S SgTxtIni}
FUNCTION TText.CREATE(object: TObject; heap: THeap; itsStyleSheet: TStyleSheet): TText;
VAR aList:
TList;
anotherList:
TList;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TText(object);
aList := TList.CREATE(NIL, heap, 0);
anotherList := TList.CREATE(NIL, heap, 0);
WITH SELF DO
BEGIN
paragraphs := aList;
txtImgList := anotherList;
styleSheet := itsStyleSheet;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TText.Free;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.FreeSelf(TRUE);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
{$IFC fTextTrace}
PROCEDURE TText.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('paragraphs: TList');
Field('styleSheet: TStyleSheet');
Field('txtImgList: TList');
Field('');
END;
{$ENDC}
{$S SgTxtCld}
PROCEDURE TText.FreeSelf(freeParas: BOOLEAN);
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.txtImgList.Free;
IF freeParas THEN
Free(SELF.paragraphs)
{Free the paragraphs}
ELSE IF SELF.paragraphs <> NIL THEN
{ OR }
SELF.paragraphs.FreeObject;
{Just Free the list}
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtWrm}
PROCEDURE TText.ChangeSelInOtherPanels(textSelection: TTextSelection);
PROCEDURE ChngPanelSel(obj: TObject);
VAR textImage: TTextImage;
selection: TSelection;
panel:
TPanel;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
textImage := TTextImage(obj);
panel := textImage.view.panel;
selection := panel.selection;
{We only unhighlight and replace the last non-NIL coSelection. In most cases, where
there is no coSelection, we unhighlight and replace the panel selection and
everything is hunky-dory}
WHILE selection.coSelection <> NIL DO
selection := selection.coSelection;
{Don't change selection in same panel}
IF selection.panel <> textSelection.panel THEN
selection := selection.FreedAndReplacedBy(textSelection.ReplicateForOtherPanel(textImage));
{$IFC fTrace}EP;{$ENDC}
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF SELF.txtImgList.size > 1 THEN
SELF.txtImgList.Each(ChngPanelSel);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TText.DelPara(delPara: TEditPara;
VAR (*
i:
INTEGER;
numImages: INTEGER;
*)
s:
TListScanner;
paraImage: TParaImage;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
(*
numImages := delPara.NumImages;
FOR i := 1 TO numImages DO
*)
s := delPara.images.Scanner;
WHILE s.Scan(paraImage) DO
fFree: BOOLEAN);
BEGIN
(*
paraImage := delPara.images[1];
*)
paraImage.textImage.imageList.DelObject(paraImage, FALSE);
s.Delete(FALSE);
paraImage.Free;
END;
{NOTE: We do not delete the paragraph from our own paragraphs list because this is usually
called while scanning that list and we would screw up its scanner if we removed the
paragraph from the list}
IF fFree THEN
delPara.free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TText.Draw;
PROCEDURE DrawInImage(obj: TObject);
VAR textImage: TTextImage;
PROCEDURE DrawOnPad;
BEGIN
textImage.Draw;
END;
BEGIN
textImage := TTextImage(obj);
textImage.view.panel.OnAllPadsDo(DrawOnPad)
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.txtImgList.Each(DrawInImage);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TText.HiliteRange(highTransit: THighTransit; textRange: TTextRange; wholePara: BOOLEAN);
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
WITH textRange DO
{$H-}
SELF.HiliteParagraphs(highTransit, firstIndex, firstLP, lastIndex, lastLP, wholePara);
{$H+}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
{ TText.HiliteParagraphs tells each text image to hilite its panel's text selection on each pad. It
calls TTextImage.HiliteText which assumes we are already focussed on a pad }
PROCEDURE TText.HiliteParagraphs(highTransit: THighTransit;
startIndex: LONGINT; startLP: INTEGER;
endIndex: LONGINT; endLP: INTEGER; wholePara: BOOLEAN);
PROCEDURE HiliteInImage(obj: TObject);
VAR selection: TSelection;
textImage: TTextImage;
PROCEDURE HiliteOnPad;
BEGIN
textImage.HiliteText(highTransit, startIndex, startLP, endIndex, endLP, wholePara);
END;
BEGIN
selection := TTextImage(obj).view.panel.selection;
WHILE selection.coSelection <> NIL DO
selection := selection.coSelection;
textImage := TTextSelection(selection).textImage;
textImage.view.panel.OnAllPadsDo(HiliteOnPad);
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.txtImgList.Each(HiliteInImage);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtIni}
FUNCTION TText.DfltTextImage(view: TView; imageLRect: LRect; imgIsGrowable: BOOLEAN): TTextImage;
VAR textImage: TTextImage;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
textImage := TTextImage.CREATE(NIL, SELF.Heap, view, imageLRect, SELF, imgIsGrowable);
SELF.txtImgList.InsLast(textImage);
SELF.paragraphs.InsLast(textImage.NewEditPara(0, TParaFormat(SELF.styleSheet.formats.First)));
SELF.RecomputeImages;
DfltTextImage := textImage;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TText.InsParaAfter(existingPara: TEditPara;
newPara: TEditPara);
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.txtImgList.Each(InsertPara);
SELF.paragraphs.InsAt(SELF.paragraphs.Pos(0, existingPara) + 1, newPara);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TText.Invalidate;
PROCEDURE InvalInImage(obj: TObject);
VAR textImage: TTextImage;
PROCEDURE InvalOnPad;
BEGIN
textImage.Invalidate;
END;
BEGIN
textImage := TTextImage(obj);
IF textImage.imageList.Size > 0 THEN
textImage.view.panel.OnAllPadsDo(InvalOnPad);
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.txtImgList.Each(InvalInImage);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TText.MarkChanged(textRange: TTextRange);
PROCEDURE Mark(obj: TObject);
VAR textImage: TTextImage;
selection: TSelection;
BEGIN
selection := TTextImage(obj).view.panel.selection;
WHILE selection.coSelection <> NIL DO
selection := selection.coSelection;
textImage := TTextSelection(selection).textImage;
WITH textRange DO
{$H-}
textImage.MarkChanged(firstIndex, firstLP, lastIndex, lastLP);
{$H+}
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.txtImgList.Each(Mark);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TText.RecomputeImages;
PROCEDURE ReImage(obj: TObject);
VAR textImage: TTextImage;
padCount:
INTEGER;
numPads:
INTEGER;
PROCEDURE ImageOnPad;
BEGIN
padCount := padCount+1;
{The first parameter in textImage.RecomputeImages says we want to draw, but it will
call view.OKToDrawIn to be sure its Okay.
The last parameter is TRUE when we are drawing on the last pad. RecomputeImages
and DrawOrInval will then set the valid bits on the images to TRUE}
IF padCount = 1 THEN
textImage.RecomputeImages(actionDraw, (numPads = 1))
ELSE
textImage.DrawOrInval(padCount = numPads);
END;
BEGIN
textImage := TTextImage(obj);
numPads := textImage.view.panel.panes.size;
padCount := 0;
textImage.view.panel.OnAllPadsDo(ImageOnPad);
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.txtImgList.Each(ReImage);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtWrm}
FUNCTION TText.SelectAll(textImage: TTextImage): TTextSelection;
VAR lastPara:
TEditPara;
textSelection:
TTextSelection;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
lastPara := TEditPara(SELF.paragraphs.Last);
textSelection := textImage.NewTextSelection(TEditPara(SELF.paragraphs.First), 1, 0,
lastPara, SELF.paragraphs.Size, lastPara.size);
SelectAll := textSelection;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtIni}
BEGIN
fTextTrace := FALSE;
END; {Methods of TText}
METHODS OF TTextImage;
{$S SgTxtIni}
FUNCTION TTextImage.CREATE(object: TObject; heap: THeap; itsView: TView;
itsLRect: LRect; itsText: TText; isGrowable: BOOLEAN): TTextImage;
VAR imgList:
TList;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TTextImage(TImage.CREATE(object, heap, itsLRect, itsView));
imgList := TList.CREATE(NIL, heap, 0);
WITH SELF DO
BEGIN
text := itsText;
imageList := imgList;
tickCount := 0;
growsDynamically := isGrowable;
minHeight := itsLRect.bottom - itsLRect.top;
formerBottom := itsLRect.top;
updateLRect := zeroLRect;
firstLinePixel := 0;
useFirstPixel := FALSE;
firstIndex := 1;
startLP := 0;
endLP := 0;
{app must set these properly if using multiple linked text images}
prevTxtImg := NIL;
nextTxtImg := NIL;
headTxtImg := SELF;
tailTxtImg := SELF;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
{This frees all text images and their paraImages in the text image chain.
It does NOT free any paragraphs, text objects, or paraFormats. Call this only once
for each text image chain (NOT for each text image in the chain}
PROCEDURE TTextImage.Free;
VAR textImage: TTextImage;
next:
TTextImage;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF SELF.headTxtImg = SELF THEN
{Think about freeing text here if this is its only text image, but beware of circular frees}
BEGIN
textImage := SELF;
WHILE textImage <> NIL DO
BEGIN
textImage.imageList.Free;
next := textImage.nextTxtImg;
textImage.FreeObject;
textImage := next;
END;
END
ELSE
SELF.headTxtImg.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
{Frees just one text image in the chain; pays no attention to links}
PROCEDURE TTextImage.FreeOneTextImage;
VAR textImage: TTextImage;
next:
TTextImage;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.imageList.Free;
SELF.FreeObject;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
{$IFC fTextTrace}
PROCEDURE TTextImage.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('text: TText');
Field('imageList: TList');
Field('tickCount: INTEGER');
Field('growsDynamically: BOOLEAN');
Field('minHeight: INTEGER');
Field('formerBottom: LONGINT');
Field('updateLRect: LRect');
Field('firstLinePixel: LONGINT');
Field('useFirstPixel: BOOLEAN');
Field('firstIndex: LONGINT');
Field('startLP: INTEGER');
Field('endLP: INTEGER');
Field('prevTxtImg: TTextImage');
Field('nextTxtImg: TTextImage');
Field('headTxtImg: TTextImage');
Field('tailTxtImg: TTextImage');
Field('');
END;
{$ENDC}
{$S SgTxtCld}
PROCEDURE TTextImage.AddImage(paraImage: TParaImage);
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.imageList.InsLast(paraImage);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TTextImage.DelImagesWith(delPara: TEditPara);
VAR (*
i,j:
INTEGER;
numImages: INTEGER;
*)
s:
TListScanner;
paraImage: TParaImage;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
s := delPara.images.Scanner;
WHILE s.Scan(paraImage) DO
IF paraImage.textImage.headTxtImg = SELF.headTxtImg THEN
BEGIN
paraImage.textImage.imageList.DelObject(paraImage, FALSE);
s.Delete(FALSE);
paraImage.Free;
END;
(*
numImages := delPara.NumImages;
j := 1;
FOR i := 1 TO numImages DO
BEGIN
{paraImage.Free calls paragraph.DelImage which shifts rest
*)
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtWrm}
PROCEDURE TTextImage.Draw;
PROCEDURE ReDraw(obj: TObject);
BEGIN
IF LRectIsVisible(TParaImage(obj).extentLRect) THEN
TParaImage(obj).RedrawLines(0, MAXINT);
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
PicGrpBegin;
SELF.imageList.Each(ReDraw);
{Now tell the next textImage in the chain to draw itself}
IF SELF.nextTxtImg <> NIL THEN
SELF.nextTxtImg.Draw;
PicGrpEnd;
{$IFC fTrace}EP;{$ENDC}
END; {Draw}
{$S SgTxtCld}
PROCEDURE TTextImage.DrawImages(fDraw: BOOLEAN);
PROCEDURE ReDraw(obj: TObject);
BEGIN
IF LRectIsVisible(TParaImage(obj).extentLRect) THEN
TParaImage(obj).RedrawLines(0, MAXINT);
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.imageList.Each(ReDraw);
{Now tell the next textImage in the chain to draw itself}
IF SELF.nextTxtImg <> NIL THEN
SELF.nextTxtImg.DrawImages(fDraw);
{$IFC fTrace}EP;{$ENDC}
END; {DrawImages}
{$S SgTxtCld}
PROCEDURE TTextImage.DrawOrInval(invalBits: BOOLEAN);
VAR fDraw:
BOOLEAN;
r:
LRect;
PROCEDURE DrawFiltImage(obj: TObject);
VAR paraImage: TParaImage;
PROCEDURE DrawImage(obj: TObject);
VAR leftPixel: LONGINT;
rightPixel: LONGINT;
styleIndex: INTEGER;
PROCEDURE DrawLine(obj: TObject);
VAR lineInfo:
TLineInfo;
dummy:
INTEGER;
BEGIN
lineInfo := TLineInfo(obj);
IF NOT lineInfo.valid THEN
BEGIN
r := lineInfo.lineLRect;
r.left := lineInfo.leftCoord(leftPixel);
r.right := lineInfo.leftCoord(rightPixel);
IF fDraw THEN
BEGIN
FillLRect(r, lPatWhite);
IF lineInfo.startLP <> lineInfo.lastDrawnLP THEN
BEGIN
MoveToL(lineInfo.lineLRect.left, lineInfo.lineLRect.top+lineInfo.lineAscent);
paraImage.FastDrawLine(lineInfo.startLP, lineInfo.lastDrawnLP, TRUE,
FALSE, dummy, styleIndex);
END;
END
ELSE
thePad.InvalLRect(r);
lineInfo.valid := invalBits;
END;
END;
BEGIN
IF paraImage.wasOffset THEN
BEGIN
{possibly use ScrollRect here later?}
r := paraImage.extentLRect;
InsetLRect(r, -1, 0);
IF fDraw THEN
BEGIN
FillLRect(r, lPatWhite);
paraImage.RedrawLines(0, MAXINT);
END
ELSE
thePad.InvalLRect(r);
paraImage.wasOffset := NOT invalBits;
END
ELSE IF paraImage.changed THEN
BEGIN
leftPixel := paraImage.extentLRect.left-1;
rightPixel := paraImage.extentLRect.right+1;
styleIndex := 1;
paraImage.lineList.Each(DrawLine);
paraImage.changed := NOT invalBits;
END;
END;
BEGIN
paraImage := TParaImage(obj);
SELF.FilterAndDo(paraImage, DrawImage);
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
fDraw := SELF.view.OKToDrawIn(SELF.extentLRect) AND NOT deferUpdate;
SELF.imageList.Each(DrawFiltImage);
IF NOT EmptyLRect(SELF.updateLRect) THEN
BEGIN
IF fDraw THEN
FillLRect(SELF.updateLRect, lPatWhite)
ELSE
thePad.InvalLRect(SELF.updateLRect);
IF invalBits THEN
SELF.updateLRect := zeroLRect;
END;
{Now tell the next textImage in the chain to draw itself}
IF SELF.nextTxtImg <> NIL THEN
SELF.nextTxtImg.DrawOrInval(invalBits);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TTextImage.FindParaAndLp(lPt: LPoint; VAR paraImage: TParaImage;
VAR paraIndex: LONGINT; VAR aLP: INTEGER);
VAR distanceDown:
INTEGER;
s:
TListScanner;
{$IFC fTextTrace}
str:
STR255;
{$ENDC}
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
{It is assumed that the caller of this routine has already determined that lPt is in this
textImage, so we will not check nextTextImg if the image list is exhausted}
distanceDown := SELF.extentLRect.top;
s := SELF.imageList.Scanner;
WHILE s.Scan(paraImage) DO
BEGIN
distanceDown := distanceDown + paraImage.height;
paraIndex := s.Position;
IF lPt.v <= distanceDown THEN
s.Done;
END;
paraIndex := paraIndex + SELF.firstIndex - 1;
IF lPt.v > distanceDown THEN
paraImage := TParaImage(SELF.imageList.Last);
aLP := paraImage.LpWithLPt(lPt);
{$IFC fTextTrace}
IF fTextTrace THEN
BEGIN
LIntToHex(ORD(paraImage), @str);
writeln('*** End FindParaAndLp: lPt= (',lPt.v:4, ',', lPt.h:4, ');
str, ',', paraIndex:1, ',', aLP:3, ')');
END;
{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
FUNCTION TTextImage.FindTextImage(VAR mouseLPt: LPoint; VAR firstTxtImg: TTextImage): TTextImage;
VAR textImage:
TTextImage;
stillLooking:
BOOLEAN;
foundIt:
BOOLEAN;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
{This looks around for a textImage that contains the mouseLPt and has some images. If it
finds a textImage that contains the point but does not have any images, then it
returns the first previous textImage that does have some images and changes mouseLPt to be
the bottom right point of that textImage.
If it doesn't find any textImages that contain the point it returns the first previous
textImage that does have some images. Also, it returns which of the textImages
(SELF or the found one) that comes first in the textImage chain}
firstTxtImg := SELF;
{Start with most common case and then try others}
IF (SELF.imageList.Size > 0) AND
(LPtInLRect(mouseLPt, SELF.extentLRect) OR SELF.growsDynamically) THEN
FindTextImage := SELF
ELSE
BEGIN
textImage := SELF;
stillLooking := TRUE;
foundIt := FALSE;
WHILE stillLooking DO
BEGIN
{First look in following boxes}
IF LPtInLRect(mouseLPt, textImage.extentLRect) THEN
BEGIN
{if box found but no images in it, then link back}
WHILE (textImage <> textImage.headTxtImg) AND (textImage.imageList.Size = 0) DO
BEGIN
textImage := textImage.prevTxtImg;
mouseLPt := textImage.extentLRect.botRight;
END;
foundIt := TRUE;
stillLooking := FALSE;
END
ELSE IF textImage.nextTxtImg <> NIL THEN
textImage := textImage.nextTxtImg
ELSE stillLooking := FALSE;
END;
IF foundIt THEN
FindTextImage := textImage
ELSE
{Still didn't find it? Look in previous boxes}
BEGIN
stillLooking := TRUE;
WHILE stillLooking DO
BEGIN
IF LPtInLRect(mouseLPt, textImage.extentLRect) THEN
BEGIN
WHILE (textImage <> textImage.headTxtImg) AND (textImage.imageList.Size = 0) DO
BEGIN
textImage := textImage.prevTxtImg;
mouseLPt := textImage.extentLRect.botRight;
END;
foundIt := TRUE;
stillLooking := FALSE;
END
ELSE IF textImage.prevTxtImg <> NIL THEN
textImage := textImage.prevTxtImg
ELSE stillLooking := FALSE;
END;
IF foundIt THEN
BEGIN
FindTextImage := textImage;
firstTxtImage := textImage;
END
ELSE
BEGIN
{mouseLPt didn't fall in any of the text images, so return SELF or the first previous
text image that has a paraimage}
textImage := SELF;
WHILE (textImage <> textImage.headTxtImg) AND (textImage.imageList.Size = 0) DO
BEGIN
textImage := textImage.prevTxtImg;
mouseLPt := textImage.extentLRect.botRight;
END;
FindTextImage := textImage;
END;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TTextImage.GetImageRange(firstIndex: LONGINT; VAR firstLP: INTEGER;
lastIndex: LONGINT; VAR lastLP: INTEGER;
VAR firstImage, lastImage: TParaImage);
{Diagram of input vs output:
------------xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx---------^
^
^
^
^
^ ^
1
2
3
4
5
6 7
input
1,2
1,3
1,4
1,5
imageWith
N,N
N,3
N,4
N,5
output
N,N
N,3
3,4
3,5
1,6
3,3
3,4
4,5
4,6
5,5
5,6
6,7
N,N
3,3
3,4
4,5
4,N
5,5
5,N
N,N
3,5
3,3
3,4
4,5
4,5
5,5
5,N
N,N
N = NIL
BEGIN
firstImage := GetFirstOrLast(firstIndex, firstLP);
lastImage := GetFirstOrLast(lastIndex, lastLP);
IF (firstImage = lastImage) AND (firstLP = lastLP) THEN
BEGIN
firstImage := NIL;
lastImage := NIL;
END;
END
ELSE
BEGIN
lastImage := GetFirstOrLast(lastIndex, lastLP);
IF (firstImage = lastImage) THEN
IF (firstLP = lastLP) THEN
lastImage := NIL;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TTextImage.HiliteText(highTransit: THighTransit;
startIndex: LONGINT; startLP: INTEGER;
endIndex: LONGINT; endLP: INTEGER; wholePara: BOOLEAN);
LABEL 1;
VAR startImage:
TParaImage;
endImage:
TParaImage;
r:
LRect;
lineInfo:
TLineInfo;
paraImage:
TParaImage;
sImg, sViewSt: TListScanner;
startLine:
INTEGER;
endLine:
INTEGER;
startPixel:
LONGINT;
endPixel:
LONGINT;
lMargPixel:
LONGINT;
rMargPixel:
LONGINT;
i:
INTEGER;
textImage:
TTextImage;
stillOkay:
BOOLEAN;
{$IFC fTextTrace}
str1:
STR255;
{for debug output}
str2:
STR255;
{for debug output}
{$ENDC}
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
{$IFC fTextTrace}
IF fTextTrace THEN
BEGIN
Writeln('*** In HiliteText:
sImg := textImage.imageList.Scanner;
WHILE sImg.Scan(paraImage) DO
END;
paraImage.LocateLP(endLP, endLine, endPixel);
IF startImage <> endImage THEN
BEGIN
PaintLRect(r);
sViewSt := paraImage.lineList.Scanner;
IF sViewSt.Scan(lineInfo) THEN
BEGIN
r := lineInfo.lineLRect;
r.left := lineInfo.LeftCoord(lMargPixel);
r.right := lineInfo.RightCoord(rMargPixel);
END;
i := 1;
END;
WHILE i <> endLine DO
BEGIN
PaintLRect(r);
IF sViewSt.Scan(lineInfo) THEN
BEGIN
r := lineInfo.lineLRect;
r.left := lineInfo.LeftCoord(lMargPixel);
r.right := lineInfo.RightCoord(rMargPixel);
END;
i := i+1;
END;
IF wholePara THEN
r.right := lineInfo.RightCoord(rMargPixel)
ELSE
BEGIN
r.right := endPixel;
{Add extra pixel if this is insertion point}
IF (startImage = endImage) AND (startLP = endLP) THEN
r.right := r.right + 1;
END;
PaintLRect(r);
Free(sViewSt);
Free(sImg);
IF highTransit = hDimToOff THEN { XORing out gray leaves holes in chars }
BEGIN
{later, we'll minimize this, if necessary}
SELF.Draw;
{ so redraw characters }
END;
END;
END
ELSE
BEGIN
{$IFC fTextTrace}
IF fTextTrace THEN
BEGIN
Writeln('*** In HiliteText:
END;
{$ENDC}
END;
{$IFC fTrace}EP;{$ENDC}
END; {HiliteText}
{$S SgTxtHot}
{Given a paragraph and lp finds the paraImage that displays it in this textImage chain.
Returns NIL if not found.}
FUNCTION TTextImage.ImageWith(paragraph: TEditPara; lp: INTEGER): TParaImage;
VAR paraImage:
TParaImage;
altParaImage:
TParaImage;
s:
TListScanner;
(*
i:
INTEGER;
*)
{$IFC fTextTrace}
str:
STR255;
{$ENDC}
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
{$IFC fTextTrace}
IF fTextTrace THEN
BEGIN
LIntToHex(ORD(paragraph), @str);
WriteLn('$$$ In ImageWith: paragraph,lp = (',str, ',', lp:1, ')' );
END;
{$ENDC}
altParaImage := NIL;
s := paragraph.images.Scanner;
WHILE s.Scan(paraImage) DO
IF ((paraImage.textImage.headTxtImg = SELF.headTxtImg) AND
(paraImage.startLP <= lp) AND
(lp <= paraImage.endLP)) THEN
IF lp = paraImage.endLP THEN
IF paraImage.textImage <> SELF THEN
altParaImage := paraImage
ELSE
s.Done
ELSE
s.Done;
IF paraImage = NIL THEN
paraImage := altParaImage;
(*
i := 1;
WITH paragraph DO
{$R-}
WHILE (i <= numImages) DO
IF ((images[i].textImage.headTxtImg = SELF.headTxtImg) AND
(images[i].startLP <= lp) AND
(lp <= images[i].endLP)) THEN
BEGIN
paraImage := images[i];
i := MAXINT;
END
ELSE
i := i + 1;
{$IFC fRngText}{$R+}{$ENDC}
*)
{$IFC fTextTrace}
IF fTextTrace THEN
BEGIN
LIntToHex(ORD(paraImage), @str);
WriteLn('$$$ In ImageWith: paraImage found= ',str);
END;
{$ENDC}
ImageWith := paraImage;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
FUNCTION TTextImage.ImageBottom: LONGINT;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
IF SELF.imageList.Size > 0 THEN
ImageBottom := TParaImage(SELF.imageList.Last).extentLRect.bottom
ELSE
ImageBottom := SELF.extentLRect.top;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
IF paraImage.wasOffset THEN
BEGIN
r := paraImage.extentLRect;
InsetLRect(r, -1, 0);
thePad.InvalLRect(r);
paraImage.wasOffset := FALSE;
paraImage.changed := FALSE;
END
ELSE IF paraImage.changed THEN
BEGIN
paraImage.changed := FALSE;
sLine := paraImage.lineList.Scanner;
WHILE sLine.Scan(lineInfo) DO
IF NOT lineInfo.valid THEN
BEGIN
lineInfo.valid := TRUE;
r := lineInfo.lineLRect;
r.left := paraImage.extentLRect.left;
r.right := paraImage.extentLRect.right;
InsetLRect(r, -1, 0);
thePad.InvalLRect(r);
END;
END;
IF NOT EmptyLRect(SELF.updateLRect) THEN
BEGIN
thePad.InvalLRect(SELF.updateLRect);
SELF.updateLRect := zeroLRect;
END;
IF SELF.nextTxtImg <> NIL THEN
SELF.nextTxtImg.Invalidate;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TTextImage.MarkChanged(startIndex: LONGINT; startLP: INTEGER;
endIndex: LONGINT; endLP: INTEGER);
VAR sImg:
TListScanner;
firstImage: TParaImage;
lastImage: TParaImage;
paraImage: TParaImage;
found:
BOOLEAN;
finished:
BOOLEAN;
textImage: TTextImage;
tempLP:
INTEGER;
stillOkay: BOOLEAN;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
stillOkay := TRUE;
IF (startIndex = endIndex) AND (startLP = endLP) THEN
BEGIN
firstImage := SELF.ImageWith(TEditPara(SELF.text.paragraphs.At(startIndex)), startLP);
lastImage := firstImage;
stillOkay := firstImage <> NIL;
END
ELSE
BEGIN
SELF.GetImageRange(startIndex, startLP, endIndex, endLP, firstImage, lastImage);
IF firstImage = NIL THEN
IF lastImage = NIL THEN
stillOkay := FALSE
ELSE
BEGIN
firstImage := lastImage;
startLP := endLP;
END
ELSE IF lastImage = NIL THEN
BEGIN
lastImage := firstImage;
endLP := startLP;
END;
END;
IF stillOkay THEN
BEGIN
IF firstImage = lastImage THEN
firstImage.InvalLinesWith(startLP, endLP)
ELSE
BEGIN
textImage := firstImage.textImage;
found := FALSE;
finished := FALSE;
WHILE NOT finished AND (textImage <> NIL) DO
BEGIN
sImg := textImage.imageList.Scanner;
WHILE sImg.Scan(paraImage) DO
BEGIN
found := found OR (paraImage = firstImage);
IF found THEN
BEGIN
IF paraImage = lastImage THEN
BEGIN
tempLP := endLP;
finished := TRUE;
sImg.Done;
END
ELSE
tempLP := paraImage.endLP;
paraImage.InvalLinesWith(startLP, tempLP);
startLP := 0;
END;
END;
textImage := textImage.nextTxtImg;
END;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TTextImage.MousePress(mouseLPt: LPoint);
VAR currParaImage: TParaImage;
currLP:
INTEGER;
textImage:
TTextImage;
firstTxtImg:
TTextImage;
selection:
TSelection;
paraIndex:
LONGINT;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
selection := SELF.view.panel.selection;
WHILE selection.coSelection <> NIL DO
selection := selection.coSelection;
IF (clickState.fShift OR (clickState.clickCount > 1)) AND InClass(selection, TTextSelection) THEN
{ let the selection extend itself }
selection.MousePress(mouseLPt)
ELSE
BEGIN
textImage := SELF.FindTextImage(mouseLPt, firstTxtImg);
textImage.FindParaAndLp(mouseLPt, currParaImage, paraIndex, currLP);
{If we are a coSelection then BeginSelection should already have been called when
panel selection was created}
IF SELF.view.panel.selection.coSelection = NIL THEN
SELF.view.panel.BeginSelection
ELSE
selection.Highlight(hOnToOff);
selection := selection.FreedAndReplacedBy(TInsertionPoint.CREATE(NIL,
SELF.Heap, SELF.view, textImage, mouseLPt,
currParaImage.paragraph, paraIndex, currLP));
SELF.text.ChangeSelInOtherPanels(TTextSelection(selection));
SELF.text.HiliteParagraphs(hOffToOn, paraIndex, currLP, paraIndex, currLP, FALSE);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
FUNCTION TTextImage.NewEditPara(initialSize: INTEGER; itsFormat: TParaFormat): TEditPara;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
NewEditPara := TEditPara.CREATE(NIL, SELF.Heap, initialSize, itsFormat);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
FUNCTION TTextImage.NewParaImage(itsParagraph: TEditPara; itsLRect: LRect;
lineTop: LONGINT; lineLeft: LONGINT): TParaImage;
VAR paraImage: TParaImage;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
paraImage := TParaImage.CREATE(NIL, SELF.Heap, SELF.view, itsParagraph, itsLRect, lineTop, lineLeft);
paraImage.textImage := SELF;
itsParagraph.InsImage(paraImage);
NewParaImage := paraImage;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
FUNCTION TTextImage.NewTextImage(heap: THeap; itsView: TView; itsLRect: LRect;
itsText:TText; isGrowable: BOOLEAN): TTextImage;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
NewTextImage := TTextImage.CREATE(NIL, heap, itsView, itsLRect, itsText, isGrowable);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
FUNCTION TTextImage.NewTextSelection(firstPara: TEditPara; firstIndex: LONGINT; firstLP: INTEGER;
lastPara: TEditPara; lastIndex: LONGINT; lastLP: INTEGER
): TTextSelection;
VAR textSel:
TTextSelection;
heap:
THeap;
view:
TView;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
heap := SELF.Heap;
view := SELF.view;
IF firstPara = lastPara THEN
IF firstLP = lastLP THEN
textSel := TInsertionPoint.CREATE(NIL, heap, view, SELF, zeroLPt,
firstPara, firstIndex, firstLP)
ELSE
textSel := TOneParaSelection.CREATE(NIL, heap, view, SELF, zeroLPt,
firstPara, firstIndex, firstLP, lastLP)
ELSE
textSel := TMultiParaSelection.CREATE(NIL, heap, view, SELF, zeroLPt,
firstPara, firstIndex, firstLP,
lastPara, lastIndex, lastLP, TRUE);
NewTextSelection := textSel;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TTextImage.OffsetBy(deltaLPt: LPoint);
{ Can be used to quickly move a text image }
PROCEDURE OffsetImage(obj: TObject);
BEGIN
TParaImage(obj).OffsetBy(deltaLPt);
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
WITH deltaLPt DO
{$H-} OffsetLRect(SELF.extentLRect, h, v); {$H+}
SELF.imageList.Each(OffsetImage);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TTextImage.RecomputeImages(drawAction: TDrawAction; invalBits: BOOLEAN);
LABEL
1;
VAR drawLRect: LRect;
lastLP:
INTEGER;
lastDrawnImage: TParaImage;
nextTxtImg:
TTextImage;
paraImage:
TParaImage;
s:
TListScanner;
tempList:
TList;
beginAtLP:
INTEGER;
returnLRect:
LRect;
lastImage:
TParaImage;
firstImage:
TParaImage;
lastOneChanged: BOOLEAN;
deltaLPt:
LPoint;
currParaIndex: LONGINT;
paragraph:
TEditPara;
newBottom:
LONGINT;
realAction:
TDrawAction;
r:
LRect;
{$IFC fTextTrace}
str:
STR255;
{$ENDC}
FUNCTION OnlyPartDrawn(pImage: TParaImage): BOOLEAN;
VAR wontFit:
BOOLEAN;
sLine:
TListScanner;
deleteRest: BOOLEAN;
lineInfo:
TLineInfo;
PROCEDURE DrawPImage(obj: TObject);
VAR action: TDrawAction;
bits:
BOOLEAN;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
bits := invalBits;
action := realAction;
{If the paragraph was offset, we don't want DrawPara to draw the changed lines, so
we display the offset paragraph case below and pass actionNone to DrawPara.
However, we must pass FALSE for invalBits since we still need the wasOffset flag
set for the display code below}
IF pImage.wasOffset THEN
BEGIN
action := actionNone;
bits := FALSE;
END;
pImage.DrawParaImage(drawLRect, beginAtLP, action, bits, returnLRect);
{$IFC fTrace}EP;{$ENDC}
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
wontFit := FALSE;
lastOneChanged := FALSE;
pImage.textImage := SELF;
{$IFC fTextTrace}
IF fTextTrace THEN
BEGIN
LIntToHex(ORD(pImage), @str);
WriteLn('++ Entering OnlyPartDrawn: pImage =', str);
WriteLn('++
: deltaLPt.v =', deltaLPt.v:1, ' drawLRect.top = ',
END;
{$ENDC}
drawLRect.top:1);
beginAtLP := 0;
IF NOT wontFit THEN
currParaIndex := currParaIndex + 1;
{$IFC fTextTrace}
IF fTextTrace THEN
WriteLn('++ EXITING OnlyPartDrawn: deltaLPt.v =', deltaLPt.v:1, '
{$ENDC}
END
ELSE
BEGIN
{remove lastDrawnImage from nextTxtImg.imageList and install in
SELF.imageList}
s.Delete(FALSE);
SELF.imageList.InsLast(lastDrawnImage);
END;
END;
IF lastDrawnImage = NIL THEN
nextTxtImg := nextTxtImg.nextTxtImg;
END;
UNTIL (lastDrawnImage <> NIL) OR (nextTxtImg = NIL);
IF lastDrawnImage = NIL THEN
BEGIN
{We exhausted all of the images and there is still potentially some room, so
look at the paragraph list and see if there are some paragraphs for which no
paraImages have yet been generated.
NOTE: this is where initial imaging of text without paraImages will be routed}
IF currParaIndex <= SELF.text.paragraphs.Size THEN
BEGIN
s := SELF.text.paragraphs.ScannerFrom(currParaIndex-1, scanForward);
WHILE s.Scan(paragraph) DO
BEGIN
lastDrawnImage := SELF.NewParaImage(paragraph, drawLRect, 0, 0);
IF OnlyPartDrawn(lastDrawnImage) THEN
s.Done;
IF lastdrawnImage.endLP >= 0 THEN
SELF.imageList.InsLast(lastDrawnImage)
ELSE
BEGIN
lastDrawnImage.paragraph.images.DelObject(lastDrawnImage, TRUE);
lastDrawnImage := NIL;
END;
END;
END;
END;
END
ELSE IF nextTxtImg <> NIL THEN
BEGIN
IF lastOneChanged THEN
BEGIN
{we stopped displaying in the middle of a paragraph, so give the rest of our
paraImages to the next textImage (note that the scanner (s) is still valid
because we jumped out of scan loop above)}
{put rest of SELF.imageList paraImages in tempList, then insert tempList into nextTxtImg}
tempList := TList.CREATE(NIL, SELF.Heap, 0);
{if we didn't display any of the current paraImage then delete it from this list}
IF lastLP < 0 THEN
BEGIN
{$IFC fTextTrace}
IF fTextTrace THEN
BEGIN
LIntToHex(ORD(lastDrawnImage), @str);
WriteLn('++ RecomputeImages: lastLP < 0; lastdrawnImage=', str);
END;
{$ENDC}
s.Delete(FALSE);
paraImage := lastDrawnImage;
paraImage.endLP := 0;
END
ELSE
BEGIN
paraImage := nextTxtImg.NewParaImage(lastDrawnImage.paragraph,
lastDrawnImage.extentLRect, 0, 0);
{$IFC fTextTrace}
IF fTextTrace THEN
BEGIN
LIntToHex(ORD(paraImage), @str);
WriteLn('++ RecomputeImages: copy of lastDrawnImage =', str);
END;
{$ENDC}
END;
tempList.InsLast(paraImage);
{put the paraImages into tempList in reverse order so that we can scan it and insert
the images at the beginning of nextTxtImg.imageList (a double-reverse)}
WHILE s.Scan(paraImage) DO
BEGIN
{$IFC fTextTrace}
IF fTextTrace THEN
BEGIN
LIntToHex(ORD(paraImage), @str);
WriteLn('++ RecomputeImages: appending to tempList and deleting from SELF pImg=', str);
END;
{$ENDC}
tempList.InsFirst(paraImage);
s.Delete(FALSE);
END;
{Delete the last paraImage inserted in the tempList if it pointed to the same
paragraph as the next textImage's first paraImage}
IF nextTxtImg.imageList.Size > 0 THEN
BEGIN
firstImage := TParaImage(nextTxtImg.imageList.First);
lastImage := TParaImage(tempList.First);
{Set up new bottom and erase any garbage due to text moving up}
newBottom := SELF.ImageBottom;
IF newBottom < SELF.formerBottom THEN
WITH SELF, extentLRect DO
{$H-}
BEGIN
SetLRect(updateLRect, left-1, newBottom, right+1, formerBottom);
IF realAction = actionDraw THEN
FillLRect(updateLRect, lPatWhite)
ELSE IF realAction = actionInval THEN
thePad.invalLRect(updateLRect);
IF invalBits THEN
updateLRect := zeroLRect;
END;
{$H+}
SELF.formerBottom := newBottom;
IF SELF.growsDynamically THEN
WITH SELF, extentLRect DO
{$H-}
bottom := Max(newBottom, top + minHeight);
{$H+}
{Now tell the next textImage in the chain to recompute itself}
nextTxtImg := SELF.nextTxtImg;
IF nextTxtImg <> NIL THEN
BEGIN
{$IFC fTextTrace}
IF fTextTrace THEN
WriteLn('++ RecomputeImages: About to call RecomputeImages for nextTxtImg; nTI.imgLst.Size=',
nextTxtImg.imageList.Size:1);
{$ENDC}
IF lastDrawnImage = NIL THEN
nextTxtImg.startLP := 0
ELSE
{$H-} nextTxtImg.startLP := Max(0, lastDrawnImage.endLP); {$H+}
nextTxtImg.firstIndex := currParaIndex;
nextTxtImg.RecomputeImages(drawAction, invalBits);
END;
{$IFC fTrace}EP;{$ENDC}
END; {RecomputeImages}
{$S SgTxtCld}
PROCEDURE TTextImage.Resize(newExtent: LRect);
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.extentLRect := newExtent;
SELF.InvalAll;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
FUNCTION TTextImage.SeesSameAs(image: TImage): BOOLEAN;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
IF SELF = image THEN
SeesSameAs := TRUE
ELSE IF InClass(image, TParaImage) THEN
SeesSameAs := SELF.text = TParaImage(image).textImage.text
ELSE IF InClass(image, TTextImage) THEN
SeesSameAs := SELF.text = TTextImage(image).text
ELSE
SeesSameAs := FALSE;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TTextImage.SetFirstIndex;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.firstIndex := 1;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtWrm}
FUNCTION TTextImage.TxtImgForClipBoard(heap: THeap; itsView: TView; itsLRect: LRect;
itsText:TText; isGrowable: BOOLEAN): TTextImage;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
TxtImgForClipBoard := TTextImage.CREATE(NIL, heap, itsView, itsLRect, itsText, isGrowable);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtIni}
END; {Methods of TTextImage}
METHODS OF TTextView;
{$S SgTxtCld}
FUNCTION TTextView.CREATE(object: TObject; heap: THeap; itsPanel: TPanel; itsExtent: LRect): TTextView;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TTextView(itsPanel.NewView(object, itsExtent, TPrintManager.CREATE(NIL, heap),
stdMargins, FALSE {, Damnit!}));
SELF.textImage := NIL;
SELF.valid := FALSE;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
{$IFC fTextTrace}
PROCEDURE TTextView.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('textImage: TTextImage');
Field('valid: BOOLEAN');
Field('');
END;
{$ENDC}
{$S SgTxtCld}
{$IFC fUseUnivText}
PROCEDURE TTextView.CreateUniversalText;
VAR univText:
TTextWriteUnivText;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF NOT clipBoard.hasUniversalText THEN
BEGIN
univText := TTextWriteUnivText.CREATE(NIL, mainHeap, NIL, 512,
TTextSelection(SELF.panel.selection));
univText.Free;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$ENDC}
{$S SgTxtCld}
FUNCTION TTextView.CursorAt(mouseLPt: LPoint): TCursorNumber;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF LPtInLRect(mouseLPt, SELF.textImage.extentLRect) THEN
CursorAt := textCursor
ELSE
CursorAt := arrowCursor;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TTextView.Draw;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF NOT SELF.valid THEN
BEGIN
SELF.textImage.RecomputeImages(actionNone, TRUE);
SELF.valid := TRUE;
END;
SELF.textImage.Draw;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TTextView.MousePress(mouseLPt: LPoint);
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.textImage.MousePress(mouseLPt);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtIni}
END; {Methods of TTextView}
{$S SgTxtCld}
{$IFC fUseUnivText}
METHODS OF TTextWriteUnivText;
{$S SgTxtCld}
FUNCTION TTextWriteUnivText.CREATE(object: TObject; heap: THeap;
itsString: TString; itsDataSize: INTEGER;
itsTextSel: TTextSelection): TTextWriteUnivText;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
WITH TTextWriteUnivText(object) DO
BEGIN
textSelection := itsTextSel;
currIndex := 1;
currPara := itsTextSel.textRange.firstPara;
currLP := 0;
currStyleIndex := 1;
currTStyles := itsTextSel.textRange.firstPara.typeStyles;
END;
SELF := TTKWriteUnivText.CREATE(object, heap, itsString, itsDataSize);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
{$IFC fTextTrace}
PROCEDURE TTextWriteUnivText.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('textSelection: TTextSelection');
Field('currIndex: LONGINT');
Field('currPara: TEditPara');
Field('currLP: INTEGER');
Field('currStyleIndex: INTEGER');
Field('currTStyles: TArray');
Field('');
END;
{$ENDC}
{$S SgTxtCld}
PROCEDURE TTextWriteUnivText.FillParagraph;
VAR startPos:
INTEGER;
endPos:
INTEGER;
currChange: TStyleChange;
nextChange: TStyleChange;
numChars:
INTEGER;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
{$IFC fTextTrace}
IF fTextTrace THEN
BEGIN
WriteLn('<-> Entering FillRun: Current fields are:');
WriteLn('<->
currIndex = ', SELF.currIndex:1, ' currStyleIndex = ', SELF.currStyleIndex:1);
WriteLn('<->
currLP = ', SELF.currLP:1);
END;
{$ENDC}
SELF.data.DelAll;
IF SELF.currIndex <= SELF.textSelection.textRange.lastIndex THEN
BEGIN
WITH SELF.paragraphDescriptor, SELF.currPara.format DO
BEGIN
paragraphStart := SELF.textSelection.isParaSelection AND {LSR}
(SELF.currLP = 0);
firstLineMargin := firstIndent;
bodyMargin := leftIndent;
rightMargin := rightMargin - rightIndent; {????}
paraLeading := spaceBelowPara;
END;
IF SELF.currPara.size = 0 THEN
BEGIN
endPos := 0;
numChars := 0;
END
ELSE
BEGIN
REPEAT
SELF.currTStyles.GetAt(SELF.currStyleIndex, @currChange);
WITH SELF.characterDescriptor DO
BEGIN
{$H-}
font := QDFontNumber(currChange.newStyle);
{$H+}
face := currChange.newStyle.onFaces;
END;
startPos := Max(SELF.currLP, currChange.lp) + 1;
SELF.currTStyles.GetAt(SELF.currStyleIndex+1, @nextChange);
endPos := Min(SELF.currPara.size, nextChange.lp);
numChars := endPos - startPos + 1;
IF numChars = 0 THEN
SELF.currStyleIndex := SELF.currStyleIndex + 1;
UNTIL numChars > 0;
SELF.data.InsManyAt(1, SELF.currPara, startPos, numChars);
END;
IF endPos = SELF.currPara.size THEN
BEGIN
SELF.currIndex := SELF.currIndex + 1;
WITH SELF DO
IF currIndex <= textSelection.textRange.lastIndex THEN
BEGIN
currLP := 0;
currStyleIndex := 1;
{$H-}
currPara := TEditPara(SELF.textSelection.textImage.text.paragraphs.At(
SELF.currIndex));
{$H+}
currTStyles := currPara.typeStyles;
{$H-}
SELF.data.InsAt(numChars+1, CHR(ascReturn)); {last statement in IF!!}
{$H+}
END
ELSE IF textSelection.isParaSelection THEN
{$H-}
SELF.data.InsAt(numChars+1, CHR(ascReturn)); {last statement in IF!!}
{$H+}
END
ELSE
BEGIN
SELF.currLP := SELF.currLP + numChars;
SELF.paragraphDescriptor.additionalChrInParagraph := {LSR}
SELF.currPara.size - endPos + 1;
END;
END;
{$IFC fTextTrace}
IF fTextTrace THEN
BEGIN
WriteLn;
WriteLn('>-< EXITING FillRun: Current fields are:');
WriteLn('>-<
currIndex = ', SELF.currIndex:1, ' currStyleIndex = ', SELF.currStyleIndex:1);
WriteLn('>-<
currLP = ', SELF.currLP:1);
WriteLn('----------------------------------------------------------------');
END;
{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtIni}
END; {Methods of TTextWriteUnivText}
{$ENDC}
{$S SgTxtIni}
{UText4}
{changed
{changed
{changed
{changed
{changed
{changed
{changed
{changed
{changed
1307
1406
1250
1308
1720
1414
1322
1024
1736
04/13/84
04/09/84
04/09/84
04/09/84
0209
1530
1337
1202
Change to TTypingCmd.Perform}
Got rid of IF numParas = 1 in Adjust proc in InsertText}
Changed TStyleCmd.FilterAndDo back to filtering TParaImage for Compugraphic}
Set up fields for partial line erasing in KeyPause}
In TTextSelection.CutCopy, changed "IF firstLP >= 0" to "IF firstLP > 0"}
Set viewLRect origined at (0,0) in TTextSelection.CutCopy}
Set textImage.minHeight to 0 in TOnePara and TMultiPara.CopySelf}
Call recomputeImages in TOnePara and TMultiPara.CopySelf to set clipView size}
First parameter decremented in calls to TParagraph.StyleAt;
No longer set unHighlightBefore[doPhase] to FALSE in typingCmd;
Set TInsertionPoint.justReturned to FALSE in all Key methods (except KeyReturn);
Call StyleFromContext in TStyleCmd.Perform}
TStyleCmd.FilterAndDo now filters a TEditPara rather than a TParaImage;
Call StyleFromContext through a filter in TTextSelection.CREATE}
TInsertion.MousePress: Allow selecting of word when double click on last half
of last character in word}
Changed all calls to TEditPara.CREATE to TTextImage.NewEditPara}
Set highlightAfter[doPhase] FALSE in TTypingCmd.CREATE}
Set deferUpdate TRUE in TTypingCmd.Perform (do phase)}
TInsertion.MousePress: Made sure all insertion points had their isPara flags
set when triple click on an empty paragraph;
TInsertionPoint.MouseMove: Don't unHighlight if isPara was TRUE}
{$S SgTxtHot}
METHODS OF TTextSelection;
{$S SgTxtHot}
FUNCTION TTextSelection.CREATE(object: TObject; heap: THeap; itsView: TView;
itsTextImage: TTextImage; itsAnchorLPt: LPoint;
beginPara: TEditPara; beginIndex: LONGINT; beginLP: INTEGER;
endPara: TEditPara; endIndex: LONGINT; endLP: INTEGER
): TTextSelection;
{Need to filter paragraph before asking about its type styles}
PROCEDURE FindFilteredStyle(obj: TObject);
BEGIN
SELF.StyleFromContext;
END;
VAR range: TTextRange;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TTextSelection(TSelection.CREATE(object, heap, itsView, somethingKind, itsAnchorLPt));
range := TTextRange.CREATE(NIL, heap, beginPara, beginIndex, beginLP, endPara, endIndex, endLP);
WITH SELF DO
BEGIN
textImage := itsTextImage;
textRange := range;
isWordSelection := FALSE;
isParaSelection := FALSE;
amTyping := FALSE;
viewTick := -1; { force recalculation of selection range }
END;
SELF.textImage.FilterAndDo(TParaImage(beginPara.images.First), FindFilteredStyle);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TTextSelection.Free;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.textRange.Free;
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtWrm}
FUNCTION TTextSelection.Clone(heap: THeap): TObject;
VAR textSel:
TTextSelection;
range:
TTextRange;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
range := TTextRange(SELF.textRange.Clone(heap));
textSel := TTextSelection(SUPERSELF.Clone(heap));
textSel.textRange := range;
Clone := textSel;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
{$IFC fTextTrace}
PROCEDURE TTextSelection.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('textImage: TTextImage');
Field('textRange: TTextRange');
Field('isWordSelection: BOOLEAN');
Field('isParaSelection: BOOLEAN');
Field('viewTick: INTEGER');
Field('amTyping: BOOLEAN');
Field('onFaces: INTEGER');
Field('font: INTEGER');
Field('');
END;
{$ENDC}
{$S SgTxtHot}
FUNCTION TTextSelection.BecomeInsertionPoint: TInsertionPoint;
VAR insertionPt:
TInsertionPoint;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
insertionPt := TInsertionPoint(SELF.FreedAndReplacedBy(
TInsertionPoint.CREATE(NIL, SELF.Heap,
SELF.view, SELF.textImage, SELF.anchorLPt,
SELF.textRange.firstPara,
SELF.textRange.firstIndex,
SELF.textRange.firstLP)));
SELF.textImage.text.ChangeSelInOtherPanels(insertionPt);
BecomeInsertionPoint := insertionPt;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtWrm}
FUNCTION TTextSelection.CanDoCommand(cmdNumber: TCmdNumber; VAR checkIt: BOOLEAN): BOOLEAN;
VAR typeStyle: TTypeStyle;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
CASE cmdNumber OF
uModern, uClassic:
BEGIN
CanDoCommand := TRUE;
typeStyle := SELF.currTypeStyle;
checkIt := (cmdNumber - uModern + 1) = typeStyle.font.fontFamily;
END;
u20Pitch, u15Pitch, u12Pitch, u10Pitch, u12Point, u14Point, u18Point, u24Point:
BEGIN
CanDoCommand := TRUE;
typeStyle := SELF.currTypeStyle;
checkIt := (cmdNumber - u20Pitch + 1) = typeStyle.font.fontSize;
END;
{$IFC LibraryVersion <= 20}
uFnt0, uFnt1, uFnt2, uFnt3, uFnt4, uFnt5, uFnt6, uFnt7, uFnt8, uFnt9, uFnt10, uFnt11:
BEGIN
CanDoCommand := TRUE;
WITH SELF.currTypeStyle.font DO
CASE cmdNumber OF
uFnt0:
checkIt := fontFamily = famSystem;
uFnt1:
checkIt := (fontFamily = famModern) AND (fontSize = size15Pitch);
uFnt2:
checkIt := (fontFamily = famModern) AND (fontSize = size12Pitch);
uFnt3:
checkIt := (fontFamily = famClassic) AND (fontSize = size12Pitch);
uFnt4:
checkIt := (fontFamily = famModern) AND (fontSize = size10Pitch);
uFnt5:
checkIt := (fontFamily = famModern) AND (fontSize = size14Point);
uFnt6:
checkIt := (fontFamily = famModern) AND (fontSize = size12Point);
uFnt7:
checkIt := (fontFamily = famClassic) AND (fontSize = size12Point);
uFnt8:
checkIt := (fontFamily = famModern) AND (fontSize = size18Point);
uFnt9:
checkIt := (fontFamily = famClassic) AND (fontSize = size18Point);
uFnt10: checkIt := (fontFamily = famModern) AND (fontSize = size24Point);
uFnt11: checkIt := (fontFamily = famClassic) AND (fontSize = size24Point);
END;
END;
{$ENDC}
uPlain, uBold, uItalic, uUnderline, uShadow, uOutline:
BEGIN
CanDoCommand := TRUE;
typeStyle := SELF.currTypeStyle;
WITH typeStyle DO
CASE cmdNumber OF
uPlain:
checkIt := onFaces=[];
uBold:
checkIt := (bold
in onFaces);
uItalic:
checkIt := (italic
in onFaces);
uUnderline: checkIt := (underlined in onFaces);
uShadow:
checkIt := (shadow
in onFaces);
uOutline:
checkIt := (outline
in onFaces);
END;
END;
uCut, uCopy, uClear:
CanDoCommand := TRUE;
uPaste:
BEGIN
clipboard.Inspect;
IF (clipboard.hasView) OR (clipBoard.hasUniversalText) THEN
CanDoCommand := TRUE;
END;
OTHERWISE
CanDoCommand := SUPERSELF.CanDoCommand(cmdNumber, checkIt);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TTextSelection.ChangeStyle(cmdNumber: TCmdNumber);
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
Write(chr(7),'Change typestyle not implemented for this selection type. ');
WriteLn ('(cmdNumber= ',cmdNumber:1,')');
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TTextSelection.ChangeText(PROCEDURE TextEdit; PROCEDURE Adjust);
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.MarkChanged;
TextEdit;
Adjust;
IF NOT deferUpdate THEN
BEGIN
SELF.textImage.text.RecomputeImages;
(*SELF.textImage.text.Invalidate;*)
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
FUNCTION TTextSelection.CopySelf(heap: THeap; view: TView): TMultiParaSelection;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
CopySelf := NIL;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TTextSelection.CutCopy(clipSelection: TSelection; deleteOriginal: BOOLEAN);
VAR clipHeap:
THeap;
clipPanel:
TPanel;
clipView:
TTextView;
viewLRect:
LRect;
text:
TText;
insPt:
TInsertionPoint;
clipTextSelection: TMultiParaSelection;
selSize:
INTEGER;
checkLast:
BOOLEAN;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
clipHeap := clipSelection.heap;
clipPanel := clipSelection.panel;
viewLRect := SELF.textImage.extentLRect;
SetLRect(viewLRect, 0, 0, viewLRect.right - viewLRect.left + 2 * cHorizMargin,
viewLRect.bottom - viewLRect.top + 2 * cVertMargin);
clipView := TTextView.CREATE(NIL, clipHeap, clipPanel, viewLRect);
clipTextSelection := TMultiParaSelection(clipSelection.FreedAndReplacedBy(
SELF.CopySelf(clipHeap, clipView)));
clipView.valid := TRUE;
clipTextSelection.isParaSelection := SELF.isParaSelection;
clipTextSelection.isWordSelection := SELF.isWordSelection;
{Intelligence!! Even if word flag not set, let's see if we qualify as a word selection anyway}
IF NOT SELF.isWordSelection THEN
WITH SELF.textRange DO
{$H-}
clipTextSelection.isWordSelection := firstPara.Qualifies(firstLP) AND
lastPara.Qualifies(lastLP-1) AND
NOT firstPara.Qualifies(firstLP-1) AND
NOT lastPara.Qualifies(lastLP);
{$H+}
clipView.textImage := clipTextSelection.textImage;
IF deleteOriginal THEN
BEGIN
{Intelligent Cut: Delete extra space}
IF clipTextSelection.isWordSelection THEN
WITH SELF.textRange DO
BEGIN
{$H-}
checkLast := TRUE;
IF firstLP > 0 THEN
IF firstPara.At(firstLp) = ' ' THEN
BEGIN
firstLP := firstLP - 1;
checkLast := FALSE;
END;
IF checkLast AND (lastLP < lastPara.size) THEN
IF lastPara.At(lastLP + 1) = ' ' THEN
lastLP := lastLP + 1;
{$H+}
END;
SELF.DeleteAndFree;
insPt := SELF.BecomeInsertionPoint;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TTextSelection.DeleteAndFree;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
FUNCTION TTextSelection.DeleteButSave: TText;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
DeleteButSave := NIL;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TTextSelection.DoChangeStyle(cmdNumber: TCmdNumber; paragraph: TParagraph;
firstLP: INTEGER; lastLP: INTEGER; VAR newStyle: TTypeStyle);
VAR onFaces:
{$IFC LibraryVersion <= 20}TSeteface{$ELSEC}Style{$ENDC};
faceChange: BOOLEAN;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
{$IFC fTextTrace}
IF fTextTrace THEN
BEGIN
WriteLn('_+_ Entering TTextSelection.DoChangeStyle: firstLP = ', firstLP:1,
' lastLP = ', lastLP:1);
END;
{$ENDC}
faceChange := TRUE;
CASE cmdNumber OF
uPlain:
onFaces
uBold:
onFaces
uItalic:
onFaces
uUnderline:
onFaces
uShadow:
onFaces
uOutline:
onFaces
:= [];
:= [bold];
:= [italic];
:= [underlined];
:= [shadow];
:= [outline];
uModern, uClassic:
BEGIN
faceChange := FALSE;
paragraph.ChgFontFamily(firstLP, lastLP, cmdNumber - uModern + 1, newStyle);
END;
{$IFC LibraryVersion <= 20}
uFnt0, uFnt1, uFnt2, uFnt3, uFnt4, uFnt5, uFnt6, uFnt7, uFnt8, uFnt9, uFnt10, uFnt11:
BEGIN
faceChange := FALSE;
CASE cmdNumber OF
uFnt0:
paragraph.ChgFontFamily(firstLP, lastLP, famSystem, newStyle);
uFnt1:
BEGIN
paragraph.ChgFontFamily(firstLP, lastLP, famModern, newStyle);
paragraph.ChgFontSize(firstLP, lastLP, size15Pitch, newStyle);
END;
uFnt2:
BEGIN
paragraph.ChgFontFamily(firstLP, lastLP, famModern, newStyle);
paragraph.ChgFontSize(firstLP, lastLP, size12Pitch, newStyle);
END;
uFnt3:
BEGIN
paragraph.ChgFontFamily(firstLP, lastLP, famClassic, newStyle);
paragraph.ChgFontSize(firstLP, lastLP, size12Pitch, newStyle);
END;
uFnt4:
BEGIN
paragraph.ChgFontFamily(firstLP, lastLP, famModern, newStyle);
paragraph.ChgFontSize(firstLP, lastLP, size10Pitch, newStyle);
END;
uFnt5:
BEGIN
paragraph.ChgFontFamily(firstLP, lastLP, famModern, newStyle);
{$S SgTxtCld}
PROCEDURE TTextSelection.GetHysteresis(VAR hysterPt: Point);
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
hysterPt := zeroPt;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TTextSelection.Highlight(highTransit: THighTransit);
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
{Note that this is called from TPanel.Highlight which does an OnAllPadsDo, thus we do not
call TText.HiliteParagraphs, but rather we call TTextImage.HiliteText }
IF SELF.textImage.imageList.size > 0 THEN
WITH SELF.textRange DO
{$H-}
SELF.textImage.headTxtImg.HiliteText(highTransit, firstIndex, firstLP, lastIndex, lastLP,
SELF.isParaSelection);
{$H+}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TTextSelection.Invalidate;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.textImage.text.Invalidate;
{$IFC fTrace}EP;{$ENDC}
END;
(* This is now done automatically by the ToolKit
{$S SgTxtHot}
PROCEDURE TTextSelection.KeyClear;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.window.PerformCommand(TClearTextCmd.CREATE(NIL, SELF.Heap, uClear,
SELF.textImage, SELF.textImage.text));
{$IFC fTrace}EP;{$ENDC}
END;
*)
{$S SgTxtHot}
{$S SgTxtCld}
PROCEDURE TTextSelection.MousePress(mouseLPt: LPoint);
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF clickState.fShift THEN
SELF.MouseMove(mouseLPt)
ELSE
SELF.textImage.MousePress(mouseLPt);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TTextSelection.MouseRelease;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
ObscureCursor;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
FUNCTION TTextSelection.NewCommand(cmdNumber: TCmdNumber): TCommand;
VAR heap:
THeap;
textImage:
TTextImage;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
NewCommand := NIL;
heap := SELF.heap;
textImage := SELF.textImage;
CASE cmdNumber OF
u20Pitch, u15Pitch, u12Pitch, u10Pitch, u12Point, u14Point, u18Point, u24Point,
uModern, uClassic,
uPlain, uBold, uItalic, uUnderline, uShadow, uOutline:
NewCommand := SELF.NewStyleCmd(heap, cmdNumber, textImage);
{$IFC LibraryVersion <= 20}
uFnt0, uFnt1, uFnt2, uFnt3, uFnt4, uFnt5, uFnt6, uFnt7, uFnt8, uFnt9, uFnt10, uFnt11:
NewCommand := SELF.NewStyleCmd(heap, cmdNumber, textImage);
{$ENDC}
uCut, uCopy:
NewCommand := SELF.NewCutCopyCmd(heap, cmdNumber, textImage);
uClear:
NewCommand := TClearTextCmd.CREATE(NIL, SELF.Heap, uClear, textImage, textImage.text);
uPaste:
NewCommand := TTextPaste.CREATE(NIL, heap, textImage, textImage.text);
{cFormatChanges:}
OTHERWISE
NewCommand := SUPERSELF.NewCommand(cmdNumber);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
FUNCTION TTextSelection.NewCutCopyCmd(heap: THeap; cmdNumber: TCmdNumber;
textImage: TTextImage): TCommand;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
NewCutCopyCmd := TTextCutCopy.CREATE(NIL, heap, cmdNumber, textImage,
cmdNumber=uCut, textImage.text);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
FUNCTION TTextSelection.NewStyleCmd(heap: THeap; cmdNumber: TCmdNumber;
textImage: TTextImage): TCommand;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
WITH SELF.textRange DO
{$H-}
NewStyleCmd := TStyleCmd.CREATE(NIL, heap, cmdNumber, textImage, firstIndex, lastIndex,
firstLP, lastLP, SELF);
{$H+}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
FUNCTION TTextSelection.ReplicateForOtherPanel(itsTextImage: TTextImage): TTextSelection;
VAR sel:
TTextSelection;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
WITH SELF.textRange DO
{$H-}
sel := itsTextImage.NewTextSelection(firstPara, firstIndex, firstLP,
lastPara, lastIndex, lastLP);
{$H+}
sel.isParaSelection := SELF.isParaSelection;
sel.isWordSelection := SELF.isWordSelection;
ReplicateForOtherPanel := sel;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TTextSelection.StyleFromContext;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtIni}
END; {METHODS OF TTextSelection}
METHODS OF TInsertionPoint;
{$S SgTxtHot}
FUNCTION TInsertionPoint.CREATE(object: TObject; heap: THeap; itsView: TView; itsTextImage: TTextImage;
itsAnchorLPt: LPoint; itsParagraph: TEditPara; itsIndex: LONGINT;
itsLP: INTEGER): TInsertionPoint;
VAR s:
TListScanner;
paragraph: TEditPara;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
IF itsIndex <= 0 THEN
BEGIN
s := itsTextImage.text.paragraphs.Scanner;
WHILE s.Scan(paragraph) DO
IF paragraph = itsParagraph THEN
BEGIN
itsIndex := s.position;
s.Done;
END;
END;
SELF := TInsertionPoint(TTextSelection.CREATE(object, heap, itsView, itsTextImage, itsAnchorLPt,
itsParagraph, itsIndex, itsLP, itsParagraph, itsIndex, itsLP));
itsParagraph.bsCount := 0;
WITH SELF DO
BEGIN
typingCmd := NIL;
styleCmdNumber := 0;
newestLP := itsLP;
nextHighTransit := hOnToOff;
justReturned := FALSE;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TInsertionPoint.Free;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF SELF.typingCmd <> NIL THEN
WITH SELF, typingCmd.typingRange DO
BEGIN
lastPara := textrange.firstPara;
lastIndex := textrange.firstIndex;
lastLP := textrange.firstLP;
END;
(*
SELF.textRange.firstPara.StopEdit;
*)
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtWrm}
FUNCTION TInsertionPoint.Clone(heap: THeap): TObject;
VAR insPt: TInsertionPoint;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
insPt := TInsertionPoint(SUPERSELF.Clone(heap));
insPt.typingCmd := NIL;
insPt.amTyping := FALSE;
Clone := insPt;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
{$IFC fTextTrace}
PROCEDURE TInsertionPoint.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
TTextSelection.Fields(Field);
Field('typingCmd: TTypingCmd');
Field('styleCmdNumber: INTEGER');
Field('newestLP: INTEGER');
Field('justReturned: BOOLEAN');
Field('nextHighTransit: Byte');
Field('nextTransitTime: LONGINT');
Field('');
END;
{$ENDC}
{$S SgTxtHot}
FUNCTION TInsertionPoint.BecomeInsertionPoint: TInsertionPoint;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
BecomeInsertionPoint := SELF;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtWrm}
FUNCTION TInsertionPoint.CanDoCommand(cmdNumber: TCmdNumber; VAR checkIt: BOOLEAN): BOOLEAN;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
CASE cmdNumber OF
uCut, uCopy:
CanDoCommand := FALSE;
OTHERWISE
CanDoCommand := SUPERSELF.CanDoCommand(cmdNumber, checkIt);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TInsertionPoint.CutCopy(clipSelection: TSelection; deleteOriginal: BOOLEAN);
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
(* Staged Alert *)
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TInsertionPoint.FinishPaste(clipSelection: TSelection; pic: PicHandle);
VAR clipTextSelection: TMultiParaSelection;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF InClass(clipSelection, TMultiParaSelection) THEN
BEGIN
clipTextSelection := TMultiParaSelection(clipSelection);
SELF.InsertText(clipTextSelection.textImage.text, clipTextSelection.isParaSelection,
clipTextSelection.isWordSelection, FALSE);
END
{$IFC fUseUnivText}
ELSE IF clipBoard.hasUniversalText THEN
SELF.InsertText(NIL, FALSE, FALSE, TRUE)
{$ENDC};
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TInsertionPoint.IdleBegin(centiSeconds: LONGINT);
{Assumes highlighting is already on}
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF (SELF.kind = nothingKind) OR SELF.isParaSelection THEN
SELF.nextHighTransit := hNone
ELSE
BEGIN
SELF.textImage.text.HiliteRange(hOnToOff, SELF.textRange, FALSE);
SELF.nextHighTransit := hOffTOOn;
SELF.nextTransitTime := centiSeconds+blinkOffTime;
END;
SUPERSELF.IdleBegin(centiSeconds);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TInsertionPoint.IdleContinue(centiSeconds: LONGINT);
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF (SELF.nextHighTransit<>hNone) AND (centiSeconds > SELF.nextTransitTime) THEN
BEGIN
SELF.textImage.text.HiliteRange(SELF.nextHighTransit, SELF.textRange, FALSE);
WITH SELF DO
IF nextHighTransit = hOnToOff THEN
BEGIN
nextHighTransit := hOffToOn;
nextTransitTime := centiSeconds+blinkOffCentiSecs;
END
ELSE
BEGIN
nextHighTransit := hOnToOff;
nextTransitTime := centiSeconds+blinkOnCentiSecs;
END;
END;
SUPERSELF.IdleContinue(centiSeconds);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TInsertionPoint.IdleEnd(centiSeconds: LONGINT);
{ end with highlighting on }
BEGIN
{$IFC fTrace}BP(6);{$ENDC}
IF SELF.nextHighTransit=hOffToOn THEN
SELF.textImage.text.HiliteRange(hOffToOn, SELF.textRange, FALSE);
SELF.nextHighTransit := hNone;
SUPERSELF.IdleEnd(centiSeconds);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TInsertionPoint.InsertText(text: TText; isParaSelection: BOOLEAN; isWordSelection: BOOLEAN;
universalText: BOOLEAN);
VAR s:
TListScanner;
prevPara:
TEditPara;
newPara:
TEditPara;
aParagraph:
TEditPara;
newLP:
INTEGER;
textImage:
TTextImage;
insertIt:
BOOLEAN;
done:
BOOLEAN;
newParaImage:
TParaImage;
paraIndex:
LONGINT;
delta:
INTEGER;
numParas:
INTEGER;
needSpRight:
BOOLEAN;
{$IFC fUseUnivText}
readUnivText:
TTKReadUnivText;
univPara:
TEditPara;
univFormat:
TParaFormat;
{$ENDC}
PROCEDURE StartPaste;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF universalText THEN
BEGIN
{$IFC fUseUnivText}
univFormat := TParaFormat.CREATE(NIL, SELF.Heap, SELF.textImage.text.styleSheet);
univPara := textImage.NewEditPara(0, prevPara.format);
readUnivText := TTKReadUnivText.CREATE(NIL, SELF.Heap, NIL, 512,
[UTCharacters, UTParagraphs]);
numParas := 0;
{$ENDC}
END
ELSE
BEGIN
numParas := text.paragraphs.size;
s := text.paragraphs.Scanner;
END;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE EndPaste;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF universalText THEN
BEGIN
{$IFC fUseUnivText}
univPara.Free;
readUnivText.Free;
{$ENDC}
END;
{$IFC fTrace}EP;{$ENDC}
END;
FUNCTION GetParagraph(VAR paragraph: TEditPara): BOOLEAN;
VAR currPos:
INTEGER;
done:
BOOLEAN;
runSize:
INTEGER;
wasSomeText:
BOOLEAN;
ch:
CHAR;
typeStyle:
TTypeStyle;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
If universalText THEN
BEGIN
{$IFC fUseUnivText}
univPara.ReplPString(0, univPara.Size, NIL);
currPos := 0;
wasSomeText := FALSE;
done := FALSE;
REPEAT
readUnivText.ReadRun;
runSize := readUnivText.data.size;
IF runSize > 0 THEN
BEGIN
IF NOT wasSomeText THEN
BEGIN
WITH univFormat, readUnivText.paragraphDescriptor DO
BEGIN
firstIndent := firstLineMargin;
leftIndent := bodyMargin;
(* Can't use this because it's given as distance from left rather than
indent from right and I don't know what value of right edge of paper is.
rightIndent := rightMargin;
*)
spaceBelowPara := paraLeading;
END;
univPara.format := univFormat;
END;
wasSomeText := TRUE;
ch := readUnivText.data.At(runSize);
IF ORD(ch) = ascReturn THEN
BEGIN
readUnivText.data.DelAt(runSize);
runSize := runSize - 1;
numParas := numParas + 1;
done := TRUE;
END;
univPara.ReplTString(currPos, 0, readUnivText.data, 0, runSize);
typeStyle.onFaces := readUnivText.characterDescriptor.face;
typeStyle.font.fontFamily := uvFont[readUnivText.characterDescriptor.font].fontFamily;
typeStyle.font.fontSize := uvFont[readUnivText.characterDescriptor.font].fontSize;
univPara.NewStyle(currPos, currPos+runSize, typeStyle);
currPos := currPos + runSize;
END
ELSE
BEGIN
IF wasSomeText THEN
numParas := numParas + 1;
done := TRUE;
END;
UNTIL done;
IF wasSomeText THEN
paragraph := univPara
ELSE
paragraph := NIL;
GetParagraph := wasSomeText;
{$ELSEC}
paragraph := NIL;
GetParagraph := FALSE;
{$ENDC}
END
ELSE
GetParagraph := s.Scan(paragraph);
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE InsText;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
delta := 0;
textImage := SELF.textImage;
newLP := SELF.textRange.firstLP;
newPara := SELF.textRange.firstPara;
prevPara := newPara;
insertIt := FALSE;
IF isWordSelection THEN
BEGIN
needSpRight := newPara.Qualifies(newLP);
IF newPara.Qualifies(newLP-1) THEN
BEGIN
newPara.InsertOneChar(' ', newLP);
newLP := newLP + 1;
delta := 1;
END;
END;
(*
*)
{special case: if first paragraph in text is designated a whole paragraph (by isParaSelection) AND
if the insertion point (SELF) is at the end of the paragraph then we want to make a new
paragraph rather than append it to the current paragraph and consequently set the flag that
was supposed to prevent the first paragraph from being inserted}
IF isParaSelection AND (prevPara.size = newLP) THEN
BEGIN
newPara := textImage.NewEditPara(0, prevPara.format);
newLP := 0;
insertIt := TRUE;
END;
done := FALSE;
StartPaste;
IF GetParagraph(aParagraph) THEN
BEGIN
delta := delta + aParagraph.size;
REPEAT
PROCEDURE Adjust;
PROCEDURE AddDelta(paraImage: TParaImage);
BEGIN
paraImage.AdjustLineLPs(SELF.textRange.firstLP, delta);
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.textRange.firstPara.EachImage(AddDelta);
WITH SELF, textRange DO
BEGIN
firstPara := newPara;
lastPara := newPara;
firstLP := newLP;
lastLP := newLP;
firstIndex := firstIndex + numParas - 1;
lastIndex := firstIndex;
newestLP := newLP;
amTyping := FALSE;
END;
{$IFC fTrace}EP;{$ENDC}
END;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF (text <> NIL) OR universalText THEN
SELF.ChangeText(InsText, Adjust);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TInsertionPoint.KeyBack(fWord: BOOLEAN);
VAR paragraph:
TEditPara;
savedPara:
TEditPara;
lp:
INTEGER;
typingCmd:
TTypingCmd;
prevPara:
TEditPara;
textRange:
TTextRange;
PROCEDURE Adjust;
VAR c: CHAR;
PROCEDURE DelOne(paraImage: TParaImage);
BEGIN
paraImage.AdjustLineLPs(lp, -1);
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
paragraph := SELF.textRange.firstPara;
lp := SELF.newestLP;
IF fWord THEN
{&&& Move textRange.firstLP back to start of word};
paragraph.BeginInsertion(lp, 0);
IF (paragraph.holeStart < 1) AND (SELF.textRange.firstIndex = 1) THEN
SELF.CantDoIt
ELSE
BEGIN
prevPara := NIL;
IF paragraph.holeStart < 1 THEN
BEGIN
{Backspacing over beginning of paragraph}
textRange := SELF.textRange;
textRange.firstIndex := textRange.firstIndex - 1;
prevPara := TEditPara(SELF.textImage.text.paragraphs.At(textRange.firstIndex));
WITH textRange DO
BEGIN
firstPara := prevPara;
firstLP := prevPara.size;
lastIndex := firstIndex;
lastPara := firstPara;
lastLP := firstLP;
SELF.newestLP := firstLP;
END;
prevPara.ReplPara(prevPara.size, 0, paragraph, 0, paragraph.size);
SELF.textImage.text.DelPara(paragraph, FALSE);
SELF.textImage.text.paragraphs.DelObject(paragraph, FALSE);
END
ELSE
BEGIN
paragraph.bsCount := paragraph.bsCount + 1;
c := paragraph.At(paragraph.holeStart);
paragraph.DelAt(paragraph.holeStart);
paragraph.UpdateRuns(lp-1, 1, 0);
SELF.newestLP := lp-1;
END;
typingCmd := SELF.typingCmd;
IF prevPara = NIL THEN
BEGIN
typingCmd.newCharCount := typingCmd.newCharCount - 1;
IF typingCmd.newCharCount < 0 THEN
BEGIN
typingCmd.typingRange.firstLP := typingCmd.typingRange.firstLP - 1;
typingCmd.newCharCount := 0;
savedPara := TEditPara(typingCmd.savedText.paragraphs.First);
{$R-}
savedPara.InsertOneChar(c, 0);
{$IFC fRngText}{$R+}{$ENDC}
END;
END
ELSE
BEGIN
typingCmd.newParaCount := typingCmd.newParaCount - 1;
IF typingCmd.newParaCount < 0 THEN
BEGIN
typingCmd.typingRange.firstIndex := textRange.firstIndex;
typingCmd.typingRange.firstPara := textRange.firstPara;
typingCmd.typingRange.firstLP := textRange.firstLP;
typingCmd.savedText.paragraphs.InsFirst(paragraph);
paragraph.ReplPString(0, paragraph.size, NIL);
typingCmd.newCharCount := 0;
typingCmd.newParaCount := 0;
END
ELSE
paragraph.Free;
END;
deferUpdate := TRUE;
SELF.justReturned := FALSE;
END;
{$IFC fTrace}EP;{$ENDC}
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.KeyText;
Adjust;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TInsertionPoint.KeyChar(ch: CHAR);
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.KeyText;
SELF.textRange.firstPara.InsertOneChar(ch, SELF.newestLP);
WITH paragraph DO
BEGIN
bsCount := paragraph.bsCount - 1;
holeStart := paragraph.holeStart + 1;
holeSize := paragraph.holeSize - 1;
size := size + 1;
END;
paragraph.UpdateRuns(lp-1, 0, 1);
SELF.newestLP := lp+1;
WITH SELF.typingCmd DO
newCharCount := newCharCount + 1;
deferUpdate := TRUE;
END;
SELF.justReturned := FALSE;
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.KeyText;
Adjust;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TInsertionPoint.KeyPause;
{Called by ToolKit when there are no keystrokes pending}
VAR text:
TText;
diff:
INTEGER;
lp:
INTEGER;
textImage: TTextImage;
paraImage: TParaImage;
startLine: INTEGER;
startPixel: LONGINT;
PROCEDURE AddDiff(paraImage: TParaImage);
BEGIN
paraImage.AdjustLineLPs(lp, diff);
END;
PROCEDURE AdjustOtherInsPts(obj: TObject);
VAR insertPt:
TInsertionPoint;
BEGIN
insertPt := TInsertionPoint(obj);
textImage.useFirstPixel := TRUE;
END
ELSE
textImage.useFirstPixel := FALSE;
SELF.textRange.firstLP := SELF.newestLP;
SELF.textRange.lastLP := SELF.newestLP;
IF SELF.typingCmd <> NIL THEN
IF SELF.typingCmd.otherInsPts <> NIL THEN
SELF.typingCmd.otherInsPts.Each(AdjustOtherInsPts);
text.RecomputeImages;
{If view.OKToDrawIn was TRUE then we won't be going through the update cycle and hence the
ToolKit won't tell us to highlight, so we'll have to highlight ourselves}
IF SELF.view.OKToDrawIn(SELF.textImage.extentLRect) THEN
SELF.panel.Highlight(SELF, hOffToOn);
IF SELF.typingCmd <> NIL THEN
IF SELF.typingCmd.otherInsPts <> NIL THEN
SELF.typingCmd.otherInsPts.Each(HiliteOtherInsPts);
END;
deferUpdate := FALSE;
SELF.justReturned := FALSE;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtWrm}
PROCEDURE TInsertionPoint.KeyReturn;
VAR para1:
TEditPara;
newPara:
TEditPara;
selSize:
INTEGER;
PROCEDURE InsPara;
VAR styleChange:
TStyleChange;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
para1 := SELF.textRange.firstPara;
selSize := para1.size - SELF.textRange.firstLP;
newPara := SELF.textImage.NewEditPara(selSize, para1.format);
newPara.StartEdit(newPara.GrowSize);
newPara.ReplPara(0, 0, para1, SELF.textRange.firstLP, selSize);
IF TFakeTStyle(newPara.format.dfltTStyle) <> TFakeTStyle(SELF.currTypeStyle) THEN
BEGIN
styleChange.lp := -1;
styleChange.newStyle := SELF.currTypeStyle;
newPara.typeStyles.PutAt(1, @styleChange);
END;
IF insertPt.view.OKToDrawIn(insertPt.textImage.extentLRect) THEN
insertPt.panel.Highlight(insertPt, hOffToOn);
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.KeyText;
SELF.ChangeText(InsPara, Adjust);
{If view.OKToDrawIn was TRUE then we won't be going through the update cycle and hence the
ToolKit won't tell us to highlight, so we'll have to highlight ourselves}
IF SELF.view.OKToDrawIn(SELF.textImage.extentLRect) THEN
SELF.panel.Highlight(SELF, hOffToOn);
IF SELF.typingCmd.otherInsPts <> NIL THEN
SELF.typingCmd.otherInsPts.Each(HiliteOtherInsPts);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TInsertionPoint.KeyTab;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.KeyChar(' ');
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TInsertionPoint.MarkChanged;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF SELF.newestLP < SELF.textRange.firstLP THEN
BEGIN
SELF.textRange.firstLP := SELF.newestLP;
SELF.textRange.lastLP := SELF.newestLP;
SUPERSELF.MarkChanged;
END
ELSE
BEGIN
SUPERSELF.MarkChanged;
SELF.textRange.firstLP := SELF.newestLP;
SELF.textRange.lastLP := SELF.newestLP;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
END;
oneParaSelection.textImage.text.HiliteRange(hOffToOn, oneParaSelection.textRange, FALSE);
END;
END
ELSE IF clickState.clickCount = 3 THEN {triple click, happens if double click didn't select word}
BEGIN
{Turn insertion point off first}
SELF.textImage.text.HiliteRange(hOnToOff, SELF.textRange, SELF.isParaSelection);
IF SELF.textRange.firstPara.size = 0 THEN
{This case precipitates the odd notion of an "insertion point" the width of the textImage;
(ie. when one triple clicks on an empty paragraph) A special check in IdleBegin makes sure
it doesn't blink.}
BEGIN
WITH SELF, textRange DO
{$H-}
funnnyInsPoint := TInsertionPoint(SELF.FreedAndReplacedBy(
TInsertionPoint.CREATE(NIL, SELF.Heap,
view, textImage, anchorLPt,
firstPara, firstIndex, 0)));
{$H+}
WITH funnnyInsPoint DO
BEGIN
isParaSelection := TRUE;
isWordSelection := FALSE;
END;
funnnyInsPoint.textImage.text.HiliteRange(hOffToOn, SELF.textRange, TRUE);
END
ELSE
BEGIN
WITH SELF, textRange DO
{$H-}
oneParaSelection := TOneParaSelection(SELF.FreedAndReplacedBy(
TOneParaSelection.CREATE(NIL, SELF.Heap,
view, textImage, anchorLPt,
firstPara, firstIndex, 0, firstPara.size)));
{$H+}
WITH oneParaSelection DO
BEGIN
isParaSelection := TRUE;
isWordSelection := FALSE;
anchorBegin := 0;
anchorEnd := textRange.lastLP;
END;
oneParaSelection.textImage.text.HiliteRange(hOffToOn, oneParaSelection.textRange, TRUE);
END;
END
ELSE
SELF.textImage.MousePress(mouseLPt);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
FUNCTION TInsertionPoint.NewStyleCmd(heap: THeap; cmdNumber: TCmdNumber;
textImage: TTextImage): TCommand;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
{Do stuff but set NewStyleCmd NIL so last cmd not committed};
SELF.styleCmdNumber := cmdNumber;
WITH SELF.currTypeStyle, font DO
CASE cmdNumber OF
uPlain:
onFaces := [];
uBold:
onFaces := onFaces + [bold];
uItalic:
onFaces := onFaces + [italic];
uUnderline:
onFaces := onFaces + [underlined];
uShadow:
onFaces := onFaces + [shadow];
uOutline:
onFaces := onFaces + [outline];
uModern, uClassic:
font.fontFamily := cmdNumber - uModern + 1;
{$IFC LibraryVersion <= 20}
uFnt0, uFnt1, uFnt2, uFnt3, uFnt4, uFnt5, uFnt6, uFnt7, uFnt8, uFnt9, uFnt10, uFnt11:
CASE cmdNumber OF
uFnt0:
fontFamily := famSystem;
uFnt1:
BEGIN
fontFamily := famModern;
fontSize := size15Pitch;
END;
uFnt2:
BEGIN
fontFamily := famModern;
fontSize := size12Pitch;
END;
uFnt3:
BEGIN
fontFamily := famClassic;
fontSize := size12Pitch;
END;
{$ENDC}
uFnt4:
BEGIN
fontFamily := famModern;
fontSize := size10Pitch;
END;
uFnt5:
BEGIN
fontFamily := famModern;
fontSize := size14Point;
END;
uFnt6:
BEGIN
fontFamily := famModern;
fontSize := size12Point;
END;
uFnt7:
BEGIN
fontFamily := famClassic;
fontSize := size12Point;
END;
uFnt8:
BEGIN
fontFamily := famModern;
fontSize := size18Point;
END;
uFnt9:
BEGIN
fontFamily := famClassic;
fontSize := size18Point;
END;
uFnt10:
BEGIN
fontFamily := famModern;
fontSize := size24Point;
END;
uFnt11:
BEGIN
fontFamily := famClassic;
fontSize := size24Point;
END;
END;
OTHERWISE
font.fontSize := cmdNumber - u20Pitch + 1;
END;
NewStyleCmd := NIL;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
FUNCTION TInsertionPoint.NewCutCopyCmd(heap: THeap; cmdNumber: TCmdNumber;
textImage: TTextImage): TCommand;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
{don't create a new command object for insertion point style change}
NewCutCopyCmd := NIL;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
FUNCTION TInsertionPoint.SelSize: INTEGER;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
SelSize := 0;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TInsertionPoint.StyleFromContext;
VAR typeStyle:
TTypeSTyle;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
SELF.textRange.firstPara.StyleAt(Max(SELF.textRange.firstLP - 1, 0), typeStyle);
SELF.currTypeStyle := typeStyle;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtIni}
BEGIN
{temp patch to get fonts from universal text}
uvFont[4].fontFamily := famModern;
uvFont[5].fontFamily := famModern;
uvFont[6].fontFamily := famModern;
uvFont[7].fontFamily := famModern;
uvFont[8].fontFamily := famModern;
uvFont[9].fontFamily := famModern;
uvFont[10].fontFamily := famClassic;
uvFont[11].fontFamily := famClassic;
uvFont[12].fontFamily := famClassic;
uvFont[13].fontFamily := famClassic;
uvFont[14].fontFamily := famClassic;
uvFont[4].fontSize := 5;
uvFont[5].fontSize := 7;
uvFont[6].fontSize := 8;
uvFont[7].fontSize := 2;
uvFont[8].fontSize := 3;
uvFont[9].fontSize := 4;
uvFont[10].fontSize := 5;
uvFont[11].fontSize := 7;
uvFont[12].fontSize := 8;
uvFont[13].fontSize := 3;
uvFont[14].fontSize := 6;
END; {Methods of TInsertionPoint}
METHODS OF TOneParaSelection;
{$S SgTxtHot}
FUNCTION TOneParaSelection.CREATE(object: TObject; heap: THeap; itsView: TView; itsTextImage: TTextImage;
itsAnchorLPt: LPoint; itsParagraph: TEditPara; itsIndex: LONGINT;
oldLP: INTEGER; currLP: INTEGER): TOneParaSelection;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TOneParaSelection(TTextSelection.CREATE(object, heap, itsView, itsTextImage, itsAnchorLPt,
itsParagraph, itsIndex, Min(oldLP, currLP),
itsParagraph, itsIndex, Max(oldLP, currLP)));
WITH SELF DO
BEGIN
anchorBegin := oldLP;
anchorEnd := oldLP;
viewTick := -1; { force recalculation of extent }
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
{$IFC fTextTrace}
PROCEDURE TOneParaSelection.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
TTextSelection.Fields(Field);
Field('anchorBegin: INTEGER');
Field('anchorEnd: INTEGER');
Field('');
END;
{$ENDC}
{$S SgTxtCld}
PROCEDURE TOneParaSelection.ChangeStyle(cmdNumber: TCmdNumber);
VAR newTypeStyle:
TTypeStyle;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
WITH SELF.textRange DO
{$H-}
SELF.DoChangeStyle(cmdNumber, firstPara, firstLP, lastLP, newTypeStyle);
{$H+}
SELF.currTypeStyle := newTypeStyle;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
{CopySelf is used for copying to the clipboard}
FUNCTION TOneParaSelection.CopySelf(heap: THeap; view: TView): TMultiParaSelection;
VAR paragraph:
TEditPara;
selSize:
INTEGER;
newImage:
TParaImage;
lastLine:
TLineInfo;
textImage:
TTextImage;
text:
TText;
imageLRect:
LRect;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
text := TText.CREATE(NIL, heap, TStyleSheet.CREATE(NIL, heap));
imageLRect := view.extentLRect;
InsetLRect(imageLRect, cHorizMargin, cVertMargin);
textImage := SELF.textImage.TxtImgForClipBoard(heap, view, imageLRect, text, TRUE);
textImage.minHeight := 0;
text.txtImgList.InsLast(textImage);
selSize := SELF.textRange.lastLP-SELF.textRange.firstLP;
paragraph := textImage.NewEditPara(selSize, TParaFormat(SELF.textRange.firstPara.format.Clone(heap)));
paragraph.ReplPara(0, 0, SELF.textRange.firstPara, SELF.textRange.firstLP, selSize);
newImage := textImage.NewParaImage(paragraph, textImage.extentLRect, 0, 0);
textImage.imageList.InsLast(newImage);
textImage.text.paragraphs.InsLast(paragraph);
{ make view extentLRect exactly fit the lines }
textImage.RecomputeImages(actionNone, TRUE);
WITH textImage.extentLRect DO
view.extentLRect.bottom := bottom - top + 2 * cVertMargin;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.ChangeText(DelText, Adjust);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
FUNCTION TOneParaSelection.DeleteButSave: TText;
VAR oldPara:
TEditPara;
selSize:
INTEGER;
newPara:
TEditPara;
text:
TText;
PROCEDURE DelText;
BEGIN
oldPara := SELF.textRange.firstPara;
IF SELF.isParaSelection AND
(SELF.textRange.firstIndex <> SELF.textImage.text.paragraphs.size) THEN
BEGIN
SELF.textImage.text.DelPara(oldPara, FALSE);
SELF.textImage.text.paragraphs.DelObject(oldPara, FALSE);
newPara := oldPara;
END
ELSE
BEGIN
selSize := SELF.textRange.lastLP-SELF.textRange.firstLP;
newPara := SELF.textImage.NewEditPara(selSize, oldPara.format);
newPara.ReplPara(0, 0, oldPara, SELF.textRange.firstLP, selSize);
oldPara.ReplPString(SELF.textRange.firstLP, selSize, NIL);
END;
text := TText.CREATE(NIL, SELF.Heap, NIL);
text.paragraphs.InsLast(newpara);
END;
PROCEDURE Adjust;
PROCEDURE Subtract(paraImage: TParaImage);
BEGIN
paraImage.AdjustLineLPs(SELF.textRange.firstLP, -selSize);
END;
BEGIN
WITH SELF.textRange DO
BEGIN
IF SELF.isParaSelection THEN
BEGIN
{$H-}
firstPara := TEditPara(SELF.textImage.text.paragraphs.At(firstIndex));
{$H+}
firstLP := 0;
lastPara := firstPara;
END;
lastLP := firstLP;
END;
IF NOT SELF.isParaSelection THEN
SELF.textRange.firstPara.EachImage(Subtract);
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.ChangeText(DelText, Adjust);
DeleteButSave := text;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtHot}
PROCEDURE TOneParaSelection.MouseMove(mouseLPt: LPoint);
{ assumes highlighting is ON }
VAR currPImage:
TParaImage;
currLP:
INTEGER;
oldLP:
INTEGER;
{ end (ie. not the anchor) of indication }
multiParaSelection: TMultiParaSelection;
textImage:
TTextImage;
firstTxtImg:
TTextImage;
first, last:
INTEGER;
paraSelect:
BOOLEAN;
paraIndex:
LONGINT;
PROCEDURE HiExtOnPads(highTransit: THighTransit; startLP,endLP: INTEGER);
BEGIN
SELF.textImage.text.HiliteParagraphs(highTransit, SELF.textRange.firstIndex, startLP,
SELF.textRange.firstIndex, endLP,
SELF.isParaSelection);
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.currLPt := mouseLPt;
textImage := SELF.textImage.FindTextImage(mouseLPt, firstTxtImg);
textImage.FindParaAndLp(mouseLPt, currPImage, paraIndex, currLP);
IF currPImage.paragraph <> SELF.textRange.firstPara THEN
BEGIN
{call new with same paraImage, followed by MouseMove so highlighting will work correctly}
paraSelect := SELF.isParaSelection;
first := SELF.anchorBegin;
last := SELF.anchorEnd;
WITH SELF, textRange DO
{$H-}
multiParaSelection := TMultiParaSelection(SELF.FreedAndReplacedBy(
TMultiParaSelection.CREATE(NIL, SELF.Heap,
view, firstTxtImg, anchorLPt,
firstPara, firstIndex, firstLP,
firstPara, firstIndex, lastLP, firstLP = anchorBegin)));
{$H+}
WITH multiParaSelection DO
BEGIN
isParaSelection := paraSelect;
anchorBegin := first;
anchorEnd := last;
isWordSelection := NOT paraSelect AND (first <> last);
END;
multiParaSelection.MouseMove(mouseLPt);
END
ELSE IF NOT SELF.isParaSelection THEN
BEGIN
IF SELF.isWordSelection THEN
BEGIN
{So dragging over last half of last character of word doesn't select space}
WITH SELF.textRange DO
BEGIN
{$H-}
IF NOT firstPara.Qualifies(currLP) THEN
IF currLP > 0 THEN
currLP := currLP - 1;
{$H+}
END;
SELF.textRange.firstPara.FindWordBounds(currLP, first, last);
IF first <= SELF.anchorBegin THEN
currLP := first
ELSE
currLP := last;
END;
IF currLP <= SELF.anchorBegin THEN
BEGIN
oldLP := SELF.textRange.firstLP;
IF SELF.anchorEnd <> SELF.textRange.lastLP THEN
HiExtOnPads(hOnToOff, SELF.anchorEnd, SELF.textRange.lastLP);
SELF.textRange.firstLP := currLP;
SELF.textRange.lastLP := SELF.anchorEnd;
END
ELSE
BEGIN
oldLP := SELF.textRange.lastLP;
IF SELF.anchorBegin <> SELF.textRange.firstLP THEN
{$S SgTxtHot}
PROCEDURE TOneParaSelection.StyleFromContext;
VAR typeStyle: TTypeStyle;
BEGIN
{$IFC fTrace}BP(8);{$ENDC}
SELF.textRange.firstPara.StyleAt(SELF.textRange.firstLP, typeStyle);
SELF.currTypeStyle := typeStyle;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtIni}
END; {Methods of TOneParaSelection}
METHODS OF TMultiParaSelection;
{$S SgTxtCld}
FUNCTION TMultiParaSelection.CREATE(object: TObject; heap: THeap; itsView: TView;
itsTextImage: TTextImage; itsAnchorLPt: LPoint;
beginPara: TEditPara; beginIndex: LONGINT; beginLP: INTEGER;
endPara: TEditPara; endIndex: LONGINT; endLP: INTEGER;
beginIsAnchor: BOOLEAN): TMultiParaSelection;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TMultiParaSelection(TTextSelection.CREATE(object, heap, itsView, itsTextImage, itsAnchorLPt,
beginPara, beginIndex, beginLP,
endPara, endIndex, endLP));
WITH SELF DO
BEGIN
IF beginIsAnchor THEN
BEGIN
anchorPara := beginPara;
anchorIndex := beginIndex;
anchorBegin := beginLP;
anchorEnd := beginLP;
END
ELSE
BEGIN
anchorPara := endPara;
anchorIndex := endIndex;
anchorBegin := endLP;
anchorEnd := endLP;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
{$IFC fTextTrace}
PROCEDURE TMultiParaSelection.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
TTextSelection.Fields(Field);
Field('anchorPara: TEditPara');
Field('anchorIndex: LONGINT');
Field('anchorBegin: INTEGER');
Field('anchorEnd: INTEGER');
Field('');
END;
{$ENDC}
{$S SgTxtCld}
PROCEDURE TMultiParaSelection.ChangeStyle(cmdNumber: TCmdNumber);
VAR newTypeStyle:
TTypeStyle;
s:
TListScanner;
paragraph:
TEditPara;
lastPara:
TEditPara;
endRng:
INTEGER;
paraImage:
TParaImage;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
newTypeStyle := SELF.currTypeStyle;
lastPara := SELF.textRange.lastPara;
s := SELF.textImage.text.paragraphs.ScannerFrom(SELF.textRange.firstIndex-1, scanForward);
WHILE s.Scan(paragraph) DO
IF paragraph = SELF.textRange.firstPara THEN
BEGIN
SELF.DoChangeStyle(cmdNumber, paragraph, SELF.textRange.firstLP,
paragraph.size, newTypeStyle);
SELF.currTypeStyle := newTypeStyle;
IF paragraph = lastPara THEN
s.Done;
END
ELSE
BEGIN
IF paragraph = lastPara THEN
BEGIN
endRng := SELF.textRange.lastLP;
s.Done;
END
ELSE
endRng := paragraph.size;
SELF.DoChangeStyle(cmdNumber, paragraph, 0, endRng, newTypeStyle);
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
{CopySelf is used for copying to the clipboard}
FUNCTION TMultiParaSelection.CopySelf(heap: THeap; view: TView): TMultiParaSelection;
VAR srcPara:
TEditPara;
cpyPara:
TEditPara;
cpyFirstPara:
TEditPara;
srcLastPara:
TEditPara;
cpyLastPara:
TEditPara;
selSize1:
INTEGER;
selSize2:
INTEGER;
textImage:
TTextImage;
s:
TListScanner;
text:
TText;
textRange:
TTextRange;
imageLRect:
LRect;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
text := TText.CREATE(NIL, heap, TStyleSheet.CREATE(NIL, heap));
imageLRect := view.extentLRect;
InsetLRect(imageLRect, cHorizMargin, cVertMargin);
textImage := SELF.textImage.TxtImgForClipBoard(heap, view, imageLRect, text, TRUE);
textImage.minHeight := 0;
text.txtImgList.InsLast(textImage);
textRange := SELF.textRange;
srcPara := textRange.firstPara;
selSize1 := srcPara.size-textRange.firstLP;
cpyPara := textImage.NewEditPara(selSize1, TParaFormat(srcPara.format.clone(heap)));
cpyPara.ReplPara(0, 0, srcPara, textRange.firstLP, selSize1);
cpyFirstPara := cpyPara;
textImage.text.paragraphs.InsLast(cpyFirstPara);
IF textRange.firstPara <> textRange.lastPara THEN
BEGIN
srcLastPara := textRange.lastPara;
selSize2 := textRange.lastLP;
cpyLastPara := textImage.NewEditPara(selSize2, TParaFormat(srcLastPara.format.clone(heap)));
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
{If saveIt is TRUE, we want to save the text we're deleting, so create a text object}
IF saveIt THEN
BEGIN
text := TText.CREATE(NIL, SELF.Heap, NIL);
paraList := text.paragraphs;
END
ELSE
text := NIL;
textRange := SELF.textRange;
firstPara := textRange.firstPara;
lastPara := textRange.lastPara;
numParas := SELF.textImage.text.paragraphs.size;
{If the last paragraph is selected, treat this like a non-para selection, so that one
empty para will be left at the end after the delete}
IF textRange.lastIndex = numParas THEN
SELF.isParaSelection := FALSE;
s := SELF.textImage.text.paragraphs.ScannerFrom(textRange.firstIndex-1, scanForward);
WHILE s.Scan(paragraph) DO
IF paragraph = firstPara THEN
BEGIN
IF SELF.isParaSelection THEN
{If isParaSelection is TRUE then insert it in our save list and
delete it from the textImage's list}
BEGIN
IF saveIt THEN
paraList.InsLast(firstPara);
SELF.textImage.text.DelPara(firstPara, FALSE);
s.Delete(NOT saveIt);
END
ELSE
{If the beginning of the selection is part of a paragraph, then save
the characters in a new paragraph and delete them in the old}
BEGIN
selSize := firstPara.size - textRange.firstLP;
IF saveIt THEN
BEGIN
paragraph := SELF.textImage.NewEditPara(selSize, firstPara.format);
paragraph.ReplPara(0, 0, firstPara, textRange.firstLP, selSize);
paraList.InsLast(paragraph);
END;
firstPara.ReplPString(textRange.firstLP, selSize, NIL);
END;
IF firstPara = lastPara THEN
s.Done
END
ELSE
BEGIN
s.Delete(FALSE);
IF paragraph = lastPara THEN
BEGIN
s.Done;
IF NOT SELF.isParaSelection THEN
{If the end of the selection is a part of a paragraph, then save the
selected characters in a new paragraph and append the rest to the
first paragraph. Finally, delete and free the last paragraph }
BEGIN
selSize := textRange.lastLP;
IF saveIt THEN
BEGIN
paragraph := SELF.textImage.NewEditPara(selSize, lastPara.format);
paragraph.ReplPara(0, 0, lastPara, 0, selSize);
END;
firstPara.ReplPara(firstPara.size, 0, lastPara, selSize,
lastPara.size-selSize);
SELF.textImage.text.DelPara(lastPara, TRUE);
END
ELSE
SELF.textImage.text.DelPara(paragraph, NOT saveIt);
END
ELSE
{Delete entire intermediate paragraphs from the textImage}
SELF.textImage.text.DelPara(paragraph, NOT saveIt);
IF saveIt THEN
paraList.InsLast(paragraph);
END;
{$IFC fTrace}EP;{$ENDC}
END; {DelText}
PROCEDURE SetRange;
BEGIN
WITH SELF, textRange DO
IF isParaSelection THEN
BEGIN
{$H-}
firstPara := TEditPara(textImage.text.paragraphs.At(firstIndex));
{$H+}
firstLP := 0;
END;
WITH SELF.textRange DO
BEGIN
END;
lastPara := firstPara;
lastIndex := firstIndex;
lastLP := firstLP;
END;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
SELF.ChangeText(DelText, SetRange);
Delete := text;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TMultiParaSelection.DeleteAndFree;
VAR text:
TText; {dummy var since Delete returns TText; will always be NIL}
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
text := SELF.Delete(FALSE);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
FUNCTION TMultiParaSelection.DeleteButSave: TText;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
DeleteButSave := SELF.Delete(TRUE);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TMultiParaSelection.MouseMove(mouseLPt: LPoint);
{ assumes highlighting is ON }
VAR endPara:
TEditPara;
currPara:
TEditPara;
currPImage:
TParaImage;
oldPImage:
TParaImage;
oldPara:
TEditPara;
paragraph:
TEditPara;
textrange:
TTextRange;
textImage:
TTextImage;
firstTxtImg:
TTextImage;
s:
TListScanner;
paraImage:
TParaImage;
newText:
TText;
currLP:
oldLP:
mouseBeforeAnchor:
oldBeforeCurr:
beginIsAnchor:
currIndex:
oldIndex:
startIndex:
endIndex:
startLP:
endLP:
first, last:
selChanged:
{$IFC fTextTrace}
str1:
str2:
{$ENDC}
INTEGER;
INTEGER;
BOOLEAN;
BOOLEAN;
BOOLEAN;
LONGINT;
LONGINT;
LONGINT;
LONGINT;
INTEGER;
INTEGER;
INTEGER;
BOOLEAN;
STR255;
STR255;
PROCEDURE NextIndex(oldIndex: LONGINT; oldLP: INTEGER; VAR newIndex: LONGINT; VAR newLP: INTEGER);
BEGIN
IF oldIndex < SELF.textImage.text.paragraphs.size THEN
BEGIN
newIndex := oldIndex + 1;
newLP := 0;
END
ELSE
BEGIN
newIndex := oldIndex;
newLP := oldLP;
END;
END;
PROCEDURE PrevIndex(oldIndex: LONGINT; oldLP: INTEGER; VAR newIndex: LONGINT; VAR newLP: INTEGER);
BEGIN
IF oldIndex > 1 THEN
BEGIN
newIndex := oldIndex - 1;
newLP := TEditPara(SELF.textImage.text.paragraphs.At(newIndex)).size;
END
ELSE
BEGIN
newIndex := oldIndex;
newLP := oldLP;
END;
END;
PROCEDURE HiExtOnPads(highTransit: THighTransit;
startIndex: LONGINT; startLP: INTEGER;
ELSE
BEGIN
startIndex := SELF.anchorIndex;
startLP := SELF.anchorBegin;
END;
HiExtOnPads(hOnToOff, textRange.firstIndex, textRange.firstLP, startIndex, startLP);
END;
WITH SELF, textRange DO
BEGIN
lastPara := currPara;
lastIndex := currIndex;
firstPara := anchorPara;
firstIndex := anchorIndex;
firstLP := anchorBegin;
lastLP := currLP;
END;
END;
IF mouseBeforeAnchor = beginIsAnchor THEN
oldBeforeCurr := NOT mouseBeforeAnchor
ELSE IF currIndex = oldIndex THEN
oldBeforeCurr := oldLP < currLP
ELSE
oldBeforeCurr := oldIndex < currIndex;
IF oldBeforeCurr THEN
BEGIN
startIndex := oldIndex;
startLP := oldLP;
endIndex := currIndex;
endLP := currLP;
END
ELSE
BEGIN
startIndex := currIndex;
startLP := currLP;
endIndex := oldIndex;
endLP := oldLP;
END;
selChanged := TRUE;
IF SELF.isParaSelection THEN
IF startIndex = endIndex THEN
selChanged := FALSE
ELSE IF mouseBeforeAnchor THEN
PrevIndex(endIndex, endLP, endIndex, endLP)
ELSE
NextIndex(startIndex, startLP, startIndex, startLP)
ELSE
selChanged := (startIndex <> endIndex) OR (startLP <> endLP);
IF selChanged THEN
HiExtOnPads(hOffToOn, startIndex, startLP, endIndex, endLP);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TMultiParaSelection.MousePress(mouseLPt: LPoint);
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF clickState.fShift THEN
SELF.MouseMove(mouseLPt)
ELSE IF clickState.clickCount > 1 THEN
BEGIN
{For now do nothing if some jerk starts double/triple clicking while dragging}
END
ELSE
SELF.textImage.MousePress(mouseLPt);
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TMultiParaSelection.MouseRelease;
VAR insPt:
TInsertionPoint;
oneParaSel: TOneParaSelection;
first,last: INTEGER;
isPara:
BOOLEAN;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF SELF.textRange.firstPara = SELF.textRange.lastPara THEN
BEGIN
isPara := SELF.isParaSelection;
IF SELF.textRange.firstLP = SELF.textRange.lastLP THEN
BEGIN
insPt := SELF.BecomeInsertionPoint;
insPt.isParaSelection := isPara;
IF NOT isPara THEN
insPt.textImage.text.HiliteRange(hOffToOn, insPt.textRange, FALSE);
END
ELSE
BEGIN
first := SELF.anchorBegin;
last := SELF.anchorEnd;
END
ELSE
SELF.textImage.text.ChangeSelInOtherPanels(SELF);
SUPERSELF.MouseRelease;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
FUNCTION TMultiParaSelection.SelSize: INTEGER;
VAR size:
INTEGER;
s:
TListScanner;
paragraph: TEditPara;
BEGIN
{$IFC fTrace}BP(9);{$ENDC}
IF SELF.textRange.firstPara = SELF.textRange.lastPara THEN
size := SELF.textRange.lastLP - SELF.textRange.firstLP
ELSE
BEGIN
size := SELF.textRange.firstPara.size - SELF.textRange.firstLP;
{skip first paragraph by not subtracting one from firstIndex}
s := SELF.textImage.text.paragraphs.ScannerFrom(SELF.textRange.firstIndex, scanForward);
WHILE s.Scan(paragraph) DO
IF paragraph = SELF.textRange.lastPara THEN
BEGIN
size := size + SELF.textRange.lastLP;
s.Done;
END
ELSE
size := size + paragraph.size;
END;
SelSize := size;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
PROCEDURE TMultiParaSelection.StyleFromContext;
VAR typeStyle: TTypeStyle;
BEGIN
{$IFC fTrace}BP(8);{$ENDC}
SELF.textRange.firstPara.StyleAt(SELF.textRange.firstLP, typeStyle);
SELF.currTypeStyle := typeStyle;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtIni}
END; {Methods of TMultiParaSelection}
{$S SgTxtCld}
METHODS OF TClearTextCmd;
FUNCTION TClearTextCmd.CREATE(object: TObject; heap: THeap; itsCmdNumber: TCmdNumber;
itsImage: TImage; itsText: TText): TClearTextCmd;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TClearTextCmd(TCommand.CREATE(object, heap, itsCmdNumber, itsImage, TRUE, revealAll));
WITH SELF DO
BEGIN
savedText := NIL;
text := itsText;
END;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TClearTextCmd.Free;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF SELF.savedText <> NIL THEN
SELF.savedText.FreeSelf(FALSE);
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fTextTrace}
PROCEDURE TClearTextCmd.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('savedText: TText');
Field('text: TText');
Field('');
END;
{$ENDC}
PROCEDURE TClearTextCmd.Commit;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
Free(SELF.savedText);
SELF.savedText := NIL;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TClearTextCmd.Perform(cmdPhase: TCmdPhase);
var textSel:
TTextSelection;
insertionPt:
TInsertionPoint;
text:
TText;
selection:
TSelection;
panel:
TPanel;
{$IFC fTextTrace}
junk:
TObject;
str1:
STR255;
str2:
STR255;
{$ENDC}
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
panel := SELF.image.view.panel;
text := SELF.text;
CASE cmdPhase OF
doPhase, redoPhase:
BEGIN
selection := panel.selection;
WHILE selection.coSelection <> NIL DO
selection := selection.coSelection;
{$IFC fTextTrace}
IF fTextTrace THEN
BEGIN
LIntToHex(ORD(selection), @str1);
Writeln('*** Clear Cmd Perfrom; panel last coselection = ', str1);
junk := SELF.text.paragraphs.First; {So can set break point here}
END;
{$ENDC}
textSel := TTextSelection(selection.FreedAndReplacedBy(
text.SelectAll(TTextSelection(selection).textImage)));
text.ChangeSelInOtherPanels(textSel);
text.HiliteRange(hOffToOn, textSel.textRange, FALSE);
text := textSel.DeleteButSave;
SELF.savedText := text;
insertionPt := textSel.BecomeInsertionPoint;
{$IFC fTextTrace}
IF fTextTrace THEN
BEGIN
LIntToHex(ORD(insertionPt), @str1);
Writeln('*** Clear Cmd Perfrom; final insertionPt = ', str1);
junk := SELF.text.paragraphs.First; {So can set break point here}
END;
{$ENDC}
END;
undoPhase:
BEGIN
selection := panel.selection;
WHILE selection.coSelection <> NIL DO
selection := selection.coSelection;
insertionPt := TInsertionPoint(selection);
insertionPt.InsertText(SELF.savedText, FALSE, FALSE, FALSE);
Free(SELF.savedText);
SELF.savedtext := NIL;
{$$ Need to hilte before, after?}
SELF.text.ChangeSelInOtherPanels(insertionPt);
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtIni}
END; {METHODS OF TClearTextCmd}
{$S SgTxtCld}
METHODS OF TStyleCmd;
FUNCTION TStyleCmd.CREATE(object: TObject; heap: THeap; itsCmdNumber: TCmdNumber;
itsImage: TImage;
itsFirstIndex: LONGINT; itsLastIndex: LONGINT;
itsLPFirst: INTEGER; itsLPLast: INTEGER;
itsSelection: TTextSelection): TStyleCmd;
VAR sel:
TTextSelection;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TStyleCmd(TCommand.CREATE(object, heap, itsCmdNumber, itsImage, TRUE, revealSome));
sel := TTextSelection(itsSelection.Clone(SELF.Heap));
WITH SELF DO
BEGIN
textSelection := sel;
text := sel.textImage.text;
firstFiltParaIndex := itsFirstIndex;
lastFiltParaIndex := itsLastIndex;
filtFirstLP := itsLPFirst;
filtLastLP := itsLPLast;
currFilteredPara := NIL;
filteredStyles := NIL;
END;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TStyleCmd.Free;
VAR sPar:
TListScanner;
paragraph: TEditPara;
paraImage: TParaImage;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
sPar := SELF.text.paragraphs.ScannerFrom(SELF.firstFiltParaIndex - 1, scanForward);
WHILE sPar.Scan(paragraph) DO
BEGIN
paragraph.beingFiltered := FALSE;
IF sPar.position = SELF.lastFiltParaIndex THEN
sPar.Done;
END;
SELF.textSelection.Free;
Free(SELF.filteredStyles);
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fTextTrace}
PROCEDURE TStyleCmd.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('text: TText');
Field('textSelection: TTextSelection');
Field('firstFiltParaIndex: LONGINT');
Field('lastFiltParaIndex: LONGINT');
Field('filtFirstLP: INTEGER');
Field('filtLastLP: INTEGER');
Field('currFilteredPara: TEditPara');
Field('filteredStyles: TArray');
Field('');
END;
{$ENDC}
PROCEDURE TStyleCmd.Commit;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
SELF.textSelection.ChangeStyle(SELF.cmdNumber);
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TStyleCmd.FilterAndDo(actualObject: TObject;
PROCEDURE DoToObject(filteredObject: TObject));
VAR savedStyles:
TArray;
paragraph:
TEditPara;
typeStyle:
TTypeStyle;
firstLP:
INTEGER;
lastLP:
INTEGER;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
paragraph := TParaImage(actualObject).paragraph;
IF paragraph.beingFiltered THEN
BEGIN
IF paragraph = SELF.currFilteredPara THEN
BEGIN
savedStyles := paragraph.typeStyles;
paragraph.typeStyles := SELF.filteredStyles;
END
ELSE
BEGIN
IF paragraph = TEditPara(SELF.text.paragraphs.At(SELF.firstFiltParaIndex)) THEN
firstLP := SELF.filtFirstLP
ELSE
firstLP := 0;
IF paragraph = TEditPara(SELF.text.paragraphs.At(SELF.lastFiltParaIndex)) THEN
lastLP := SELF.filtLastLP
ELSE
lastLP := paragraph.size;
Free(SELF.filteredStyles);
savedStyles := TArray(paragraph.typeStyles.Clone(SELF.heap));
SELF.textSelection.DoChangeStyle(SELF.cmdNumber, paragraph, firstLP, lastLP, typeStyle);
SELF.currFilteredPara := paragraph;
SELF.filteredStyles := paragraph.typeStyles;
END;
DoToObject(TParaImage(actualObject));
paragraph.typeStyles := savedStyles;
END
ELSE
DoToObject(TParaImage(actualObject));
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TStyleCmd.Perform(cmdPhase: TCmdPhase);
VAR textSelection: TTextSelection;
selection:
TSelection;
sPar:
TListScanner;
paragraph:
TEditPara;
{Need to filter paragraph before asking about its type styles}
PROCEDURE FindFilteredStyle(obj: TObject);
BEGIN
textSelection.StyleFromContext;
END;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
selection := SELF.image.view.panel.selection;
WHILE selection.coSelection <> NIL DO
selection := selection.coSelection;
textSelection := TTextSelection(selection);
IF cmdPhase = doPhase THEN
BEGIN
sPar := SELF.text.paragraphs.ScannerFrom(SELF.firstFiltParaIndex - 1, scanForward);
WHILE sPar.Scan(paragraph) DO
BEGIN
paragraph.beingFiltered := TRUE;
IF sPar.position = SELF.lastFiltParaIndex THEN
sPar.Done;
END;
END;
textSelection.MarkChanged;
textSelection.textImage.text.RecomputeImages;
SELF.FilterAndDo(TParaImage(TEditPara(SELF.text.paragraphs.At(
SELF.firstFiltParaIndex)).images.First), FindFilteredStyle);
(*textSelection.Invalidate;*)
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtIni}
END; {METHODS OF TStyleCmd}
{$S SgTxtCld}
METHODS OF TTextCutCopy;
FUNCTION TTextCutCopy.CREATE(object: TObject; heap: THeap; itsCmdNumber: TCmdNumber;
itsImage: TImage; isCutCmd: BOOLEAN; itsText: TText): TTextCutCopy;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TTextCutCopy(TCutCopyCommand.CREATE(object, heap, itsCmdNumber, itsImage, isCutCmd));
WITH SELF DO
BEGIN
text := itsText;
IF itsCmdNumber = uCopy THEN
BEGIN
unHiliteBefore[doPhase] := FALSE;
hiliteAfter[doPhase] := FALSE;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fTextTrace}
PROCEDURE TTextCutCopy.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
TCutCopyCommand.Fields(Field);
Field('text: TText');
Field('');
END;
{$ENDC}
PROCEDURE TTextCutCopy.DoCutCopy(clipSelection: TSelection; deleteOriginal: BOOLEAN;
cmdPhase: TCmdPhase);
VAR textSel:
TTextSelection;
insertionPt:
TInsertionPoint;
multiParaSel:
TMultiParaSelection;
heap:
THeap;
firstPara:
TEditPara;
firstLP:
INTEGER;
panel:
selection:
saveTextSel:
firstIndex:
TPanel;
TSelection;
TTextSelection;
LONGINT;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
heap := SELF.Heap;
panel := SELF.image.view.panel;
CASE cmdPhase OF
doPhase, redoPhase:
BEGIN
selection := panel.selection;
{we know that the last coSelection must be the textSelection since textSelections
do not have coSelections}
WHILE selection.coSelection <> NIL DO
selection := selection.coSelection;
textSel := TTextSelection(selection);
IF (cmdPhase = redoPhase) AND deleteOriginal THEN
SELF.text.HiliteRange(hOffToOn, textSel.textRange, textSel.isParaSelection);
textSel.CutCopy(clipSelection, deleteOriginal);
END;
undoPhase:
BEGIN
IF deleteOriginal THEN
BEGIN
selection := panel.selection;
WHILE selection.coSelection <> NIL DO
selection := selection.coSelection;
insertionPt := TInsertionPoint(selection);
firstPara := insertionPt.textRange.firstPara;
firstLP := insertionPt.textRange.firstLP;
firstIndex := insertionPt.textRange.firstIndex;
{get the cut text from the clipboard and insert it back into the text}
multiParaSel := TMultiParaSelection(clipSelection);
insertionPt.InsertText(multiParaSel.textImage.text, multiParaSel.isParaSelection,
multiParaSel.isWordSelection, FALSE);
IF multiParaSel.isParaSelection THEN
BEGIN
WITH insertionPt DO
IF textRange.firstIndex > 1 THEN
BEGIN
textRange.firstIndex := textRange.firstIndex - 1;
{$H-}
textRange.firstPara := TEditPara(SELF.text.paragraphs.At(textRange.firstIndex));
textRange.firstLP := textRange.firstPara.size;
{$H+}
END;
END
ELSE IF multiParaSel.isWordSelection THEN
{don't want to select extra blank generated by insert}
WITH insertionPt DO
{$H-}
IF firstPara.At(firstLP + 1) = ' ' THEN
firstLP := firstLP + 1
ELSE IF textRange.firstPara.At(textRange.firstLP) = ' ' THEN
textRange.firstLP := textRange.firstLP - 1;
{$H+}
BEGIN
pasteRange := range;
text := itsText;
savedText := NIL;
origIsPara := FALSE;
origIsWord := FALSE;
clipIsPara := FALSE;
END;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TTextPaste.Free;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
IF SELF.savedText <> NIL THEN
SELF.savedText.FreeSelf(FALSE);
Free(SELF.pasteRange);
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$IFC fTextTrace}
PROCEDURE TTextPaste.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('savedText: TText');
Field('pasteRange: TTextRange');
Field('text: TText');
Field('origIsPara: BOOLEAN');
Field('origIsWord: BOOLEAN');
Field('clipIsPara: BOOLEAN');
Field('');
END;
{$ENDC}
PROCEDURE TTextPaste.Commit;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
Free(SELF.savedText);
SELF.savedText := NIL;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TTextPaste.DoPaste(clipSelection: TSelection; pic: PicHandle; cmdPhase: TCmdPhase);
VAR heap:
THeap;
textSel:
TTextSelection;
saveTextSel:
TTextSelection;
insertionPt:
TInsertionPoint;
insPtBefore:
TInsertionPoint;
insPtAfter:
TInsertionPoint;
text:
TText;
firstPara:
TEditPara; {bad choice of var names; change later (screws up WITH's)}
firstLP:
INTEGER;
firstIndex:
LONGINT;
panel:
TPanel;
selection:
TSelection;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
heap := SELF.Heap;
panel := SELF.image.view.panel;
CASE cmdPhase OF
doPhase, redoPhase:
BEGIN
IF InClass(clipSelection, TTextSelection) OR (clipBoard.hasUniversalText) THEN
BEGIN
selection := panel.selection;
{we know that the last coSelection must be the textSelection since textSelections
do not have coSelections}
WHILE selection.coSelection <> NIL DO
selection := selection.coSelection;
textSel := TTextSelection(selection);
SELF.origIsPara := textSel.isParaSelection;
SELF.origIsWord := textSel.isWordSelection;
IF InClass(clipSelection, TTextSelection) THEN
SELF.clipIsPara := TTextSelection(clipSelection).isParaSelection;
{delete the selected text, leaving an insertion point}
text := textSel.DeleteButSave;
SELF.savedText := text;
insertionPt := textSel.BecomeInsertionPoint;
WITH SELF, insertionPt DO
BEGIN
pasteRange.firstPara := textRange.firstPara;
pasteRange.firstIndex := textRange.firstIndex;
pasteRange.firstLP := textRange.firstLP;
END;
insertionPt.FinishPaste(clipSelection, pic);
WITH SELF, insertionPt DO
IF clipIsPara THEN
BEGIN
{$H-}
pasteRange.lastIndex := Max(1, textRange.firstIndex - 1);
pasteRange.lastPara := TEditPara(SELF.text.paragraphs.At(pasteRange.lastIndex));
pasteRange.lastLP := pasteRange.lastPara.size;
{$H+}
END
ELSE
BEGIN
pasteRange.lastPara := textRange.firstPara;
pasteRange.lastIndex := textRange.firstIndex;
pasteRange.lastLP := textRange.firstLP;
END;
SELF.text.ChangeSelInOtherPanels(insertionPt);
END
ELSE
BEGIN
panel.selection.CantDoIt;
SELF.undoable := FALSE;
END;
END;
undoPhase:
BEGIN
WITH SELF.pasteRange DO
{$H-}
textSel := TTextImage(SELF.image).NewTextSelection(firstPara, firstIndex, firstLP,
lastPara, lastIndex, lastLP);
{$H+}
textSel.isParaSelection := SELF.clipIsPara;
{user feedback: highlight pasted text}
SELF.text.HiliteRange(hOffToOn, SELF.pasteRange, textSel.isParaSelection);
{get rid of pasted text; can get it from clipboard for redo}
textSel.DeleteAndFree;
insertionPt := textSel.BecomeInsertionPoint;
firstPara := insertionPt.textRange.firstPara;
firstLP := insertionPt.textRange.firstLP;
firstIndex := insertionPt.textRange.firstIndex;
{put back any text that was pasted over}
insertionPt.InsertText(SELF.savedText, SELF.origIsPara, SELF.origIsWord, FALSE);
WITH insertionPt DO
IF SELF.origIsPara THEN
BEGIN
{$H-}
textRange.firstIndex := Max(1, textRange.firstIndex - 1);
textRange.firstPara := TEditPara(SELF.text.paragraphs.At(textRange.firstIndex));
textRange.firstLP := textRange.firstPara.size;
{$H+}
END;
Free(SELF.savedText);
SELF.savedText := NIL;
selection := panel.selection;
WHILE selection.coSelection <> NIL DO
selection := selection.coSelection;
{build original selection (ie before the paste)}
textSel := TTextSelection(selection.FreedAndReplacedBy(
insertionPt.textImage.NewTextSelection(
firstPara, firstIndex, firstLP, insertionPt.textRange.firstPara,
insertionPt.textRange.firstIndex, insertionPt.textRange.firstLP)));
textSel.isParaSelection := SELF.origIsPara;
textSel.isWordSelection := SELF.origIsWord;
SELF.text.ChangeSelInOtherPanels(textSel);
insertionPt.Free;
END;
END;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtIni}
END; {METHODS OF TTextPaste}
{$S SgTxtHot}
METHODS OF TTypingCmd;
FUNCTION TTypingCmd.CREATE(object: TObject; heap: THeap; itsImage: TImage;
itsText: TText): TTypingCmd;
VAR range: TTextRange;
BEGIN
{$IFC fTrace}BP(11);{$ENDC}
IF object = NIL THEN
object := NewObject(heap, THISCLASS);
SELF := TTypingCmd(TCommand.CREATE(object, heap, uTyping, itsImage, TRUE, revealAll));
range := TTextRange.CREATE(NIL, heap, NIL, 0, 0, NIL, 0, 0); {Perform initializes}
WITH SELF DO
BEGIN
newCharCount := 0;
newParaCount := 0;
text := itsText;
savedText := NIL;
typingRange := range;
otherInsPts := NIL;
hiliteAfter[doPhase] := FALSE;
END;
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE TTypingCmd.Free;
VAR selection: TSelection;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
Free(SELF.savedText);
selection := SELF.image.view.panel.selection;
WHILE selection.coSelection <> NIL DO
selection := selection.coSelection;
IF InClass(selection, TInsertionPoint) THEN
BEGIN
TInsertionPoint(selection).typingCmd := NIL;
TInsertionPoint(selection).amTyping := FALSE;
END;
SELF.typingRange.Free;
IF SELF.otherInsPts <> NIL THEN
SELF.otherInsPts.FreeObject;
SUPERSELF.Free;
{$IFC fTrace}EP;{$ENDC}
END;
{$S SgTxtCld}
{$IFC fTextTrace}
PROCEDURE TTypingCmd.Fields(PROCEDURE Field(nameAndType: S255));
BEGIN
SUPERSELF.Fields(Field);
Field('');
Field('savedText: TText');
Field('text: TText');
Field('newCharCount: INTEGER');
Field('newParaCount: INTEGER');
Field('typingRange: TTextRange');
Field('otherInsPts: TList');
Field('');
END;
{$ENDC}
{$S SgTxtHot}
PROCEDURE TTypingCmd.Perform(cmdPhase: TCmdPhase);
VAR text:
TText;
insertionPt:
TInsertionPoint;
selection:
heap:
firstPara:
firstLP:
textSel:
panel:
firstIndex:
aList:
typeStyle:
TSelection;
THeap;
TEditPara;
INTEGER;
TTextSelection;
TPanel;
LONGINT;
TList;
TTypeStyle;
firstPara := insertionPt.textRange.firstPara;
firstIndex := insertionPt.textRange.firstIndex;
firstLP := insertionPt.textRange.firstLP;
lastPara := firstPara;
lastIndex := firstIndex;
lastLP := firstLP;
END;
IF cmdPhase = doPhase THEN
BEGIN
WITH insertionPoint DO
BEGIN
amTyping := TRUE;
typingCmd := SELF;
IF TFakeTStyle(currTypeStyle) <> TFakeTStyle(typeStyle) THEN
BEGIN
styleCmdNumber := -1; {so correct typeStyle will be used}
currTypeStyle := typeStyle;
END;
END;
{If there is more than one panel displaying this text, then store the insertion points
of the other panels in a list for quick access while typing}
IF SELF.text.txtImgList.size > 1 THEN
BEGIN
aList := TList.CREATE(NIL, heap, 0);
SELF.text.txtImgList.Each(InstallInsPt);
SELF.otherInsPts := aList;
END;
insertionPt.textRange.firstPara.StartEdit(insertionPt.textRange.firstPara.GrowSize);
END
ELSE
BEGIN
firstPara := insertionPt.textRange.firstPara;
firstLP := insertionPt.textRange.firstLP;
firstIndex := insertionPt.textRange.firstIndex;
{put back the typed text}
deferUpdate := FALSE;
insertionPt.InsertText(SELF.savedText, FALSE, FALSE, FALSE);
Free(SELF.savedText);
WITH SELF.typingRange DO
BEGIN
lastPara := insertionPt.textRange.firstPara;
lastIndex := insertionPt.textRange.firstIndex;
lastLP := insertionPt.textRange.firstLP;
END;
{build typed selection}
textSel := TTextSelection(insertionPt.FreedAndReplacedBy(
insertionPt.textImage.NewTextSelection(
firstPara, firstIndex, firstLP, insertionPt.textRange.firstPara,
insertionPt.textRange.firstIndex, insertionPt.textRange.firstLP)));
SELF.text.ChangeSelInOtherPanels(textSel);
END;
{We always need a valid savedText object, even if no characters were initially typed
over, in case previous characters get backspaced over. See code in KeyBack }
IF text = NIL THEN
BEGIN
text := TText.CREATE(NIL, heap, NIL);
text.paragraphs.InsLast(
TTextImage(SELF.image).NewEditPara(0, SELF.typingRange.firstPara.format));
END;
SELF.savedText := text;
END;
undoPhase:
BEGIN
WITH SELF.typingRange DO
{$H-}
textSel := TTextImage(SELF.image).NewTextSelection(firstPara, firstIndex, firstLP,
lastPara, lastIndex, lastLP);
{$H+}
{user feedback: highlight typed text}
SELF.text.HiliteRange(hOffToOn, SELF.typingRange, textSel.isParaSelection);
{delete but save typed text}
text := textSel.DeleteButSave;
insertionPt := textSel.BecomeInsertionPoint;
firstPara := insertionPt.textRange.firstPara;
firstLP := insertionPt.textRange.firstLP;
firstIndex := insertionPt.textRange.firstIndex;
{put back any text that was typed over}
insertionPt.InsertText(SELF.savedText, FALSE, FALSE, FALSE);
Free(SELF.savedText);
SELF.savedText := text;
selection := panel.selection;
WHILE selection.coSelection <> NIL DO
selection := selection.coSelection;
{$E+}
{$E ERR1.TEXT}
{------------------------------------------------------------------------------------------------------------}
{
UUniversalText V0.3
}
{------------------------------------------------------------------------------------------------------------}
{$SETC ForOS := TRUE }
{$DECL WithUObject}
{$SETC WithUObject := TRUE}
{Note: TRUE/FALSE status MUST agree with below}
{$IFC IsIntrinsic}
INTRINSIC;
{$ENDC}
{$IFC NOT WithUObject}
{$SETC LibraryVersion := 30 } { 10 = 1.0 libraries; 13 = 1.3 libraries; 20 = Pepsi, 30 = Spring, etc. }
{$ENDC}
INTERFACE
USES
{$IFC WithUObject}
{$U libtk/UObject}
{$SETC fTrce := fTrace}
{$ENDC}
{$U libsm/UnitStd.obj }
{$U libsm/UnitHz.obj }
{$IFC NOT WithUObject}
{$U libpl/UClascal}
{$U libqd/Storage.obj }
{$ENDC}
UObject,
UnitStd,
UnitHz,
UClascal,
Storage,
{Must be FALSE}
{$DECL fDbgObject}
{$DECL fTrce}
{$SETC fTrce := FALSE}
{Must be FALSE}
{Normal}
{$DECL PasteTrace}
{$SETC PasteTrace := FALSE}
TYPE
{$IFC NOT WithUObject}
S255 = STRING[255];
THeap = Ptr;
{alias for THz}
TClass = Ptr;
{alias for TPSliceTable in UClascal}
TCollecHeader =
classPtr:
size:
dynStart:
RECORD
TClass;
LONGINT;
INTEGER;
holeStart:
holeSize:
holeStd:
END;
INTEGER;
INTEGER;
INTEGER;
TFastString = RECORD
{only access ch[i] when hole is at end & TString is not subclassed}
header:
TCollecHeader;
ch:
PACKED ARRAY[1..32740] OF CHAR;
END;
TPFastString = ^TFastString;
THFastString = ^TPFastString;
TUTObject = SUBCLASS OF NIL
FUNCTION
FUNCTION
PROCEDURE
PROCEDURE
FUNCTION
END;
LONGINT;
INTEGER;
INTEGER;
INTEGER;
INTEGER;
FUNCTION
FUNCTION
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
PROCEDURE
END;
{$ENDC}
TEnumLevelOfGranularity = (UTCharacters, UTParagraphs);
TLevelOfGranularity = SET OF TEnumLevelOfGranularity;
TCharDescriptor = RECORD
{ character descroptor record }
font:
INTEGER;
{ font number }
face:
{$IFC LibraryVersion <= 20}TSeteface{$ELSEC}style{$ENDC};
superscript:
-128..127;
{ number of bits to superscript }
keepOnSamePage: BOOLEAN;
END;
TTabTypes
TTabFill
TParaTypes
= (qLeftTab,
= (tNoFill,
= (qLeftPara,
TTabDescriptor = RECORD
position:
fillBetweenTabs:
tabType:
END;
TParaDescriptor = RECORD
paragraphStart:
qCenterTab,
tDotFill,
qCenterPara,
INTEGER;
TTabFill;
TTabTypes;
BOOLEAN;
qRightTab,
tHyphenFill,
qRightPara,
{ formating }
qPeriodTab,
qCommaTab);
tUnderLineFill);
qJustPara);
{$IFC WithUObject}
additionalChrInParagraph:
INTEGER;
{$ENDC}
firstLineMargin:
INTEGER;
{Left margin of first line}
bodyMargin:
INTEGER;
{Left margin of subsequent lines}
rightMargin:
INTEGER;
{Right margin}
paraLeading:
INTEGER;
{Paragraph leading}
lineSpacing:
0..63;
{Inter-line spacing }
{$IFC WithUObject}
tabTable:
TArray {OF TTabDescriptor}; { table of tabs }
{$ELSEC}
tabTable:
TUTArray {OF TTabDescriptor}; { table of tabs }
{$ENDC}
paraType:
TParaTypes;
{Paragraph adjustment }
hasPicture:
BOOLEAN;
{Is there a picture avaible for this paragraph?}
END;
{$IFC WithUObject}
TTKUnivText = SUBCLASS OF TOBJECT
{$ELSEC}
TUnivText
= SUBCLASS OF TUTObject
{$ENDC}
paragraphDescriptor:
TParaDescriptor;
characterDescriptor:
TCharDescriptor;
maxDataSize:
INTEGER;
{$IFC WithUObject}
data:
TString;
{$ELSEC}
data:
TUTString;
{$ENDC}
itsOurTString:
BOOLEAN;
{$IFC WithUObject}
FUNCTION {TTKUnivText.}CREATE(object: TObject;
itsHeap: THeap;
itsTString: TString;
itsDataSize: INTEGER) : TTKUnivText;
{$ELSEC}
FUNCTION {TUnivText.}CREATE(object: TUTObject;
itsHeap: THeap;
itsTString: TUTString;
itsDataSize: INTEGER) : TUnivText;
{$ENDC}
PROCEDURE {TUnivText.}Free; OVERRIDE;
PROCEDURE {TUnivText.}RunToStream;
PROCEDURE {TUnivText.}StreamToTRun;
PROCEDURE {TUnivText.}TabTableToArgTbd;
PROCEDURE {TUnivText.}ArgTbdToTabTable;
END;
{$IFC WithUObject}
TTKReadUnivText = SUBCLASS OF TTKUnivText
{$ELSEC}
TReadUnivText
= SUBCLASS OF TUnivText
{$ENDC}
{$IFC WithUObject}
buffer:
{$ELSEC}
buffer:
{$ENDC}
columnCount:
dataBeforeTab:
TString;
TUTString;
INTEGER;
BOOLEAN;
{$IFC WithUObject}
FUNCTION {TReadUnivText.}CREATE(object: TObject;
itsHeap: THeap;
itsTString: TString;
itsDataSize: INTEGER;
LevelOfGranularity: TLevelOfGranularity)
: TTKReadUnivText;
{$ELSEC}
FUNCTION {TReadUnivText.}CREATE(object: TUTObject;
itsHeap: THeap;
itsTString: TUTString;
itsDataSize: INTEGER;
LevelOfGranularity: TLevelOfGranularity)
: TReadUnivText;
{$ENDC}
PROCEDURE {TReadUnivText.}Free; OVERRIDE;
PROCEDURE {TReadUnivText.}ReadRun;
{ Returns one run of text each time called }
PROCEDURE {TReadUnivText.}Restart;
{ Resets the object to read from the begining }
PROCEDURE {TReadUnivText.}ScanTable(VAR rows,
tabColumns,
tabStopColumns: INTEGER);
{ Returns number of rows and colums of scrap if a valid table }
FUNCTION
{TReadUnivText.}ReadField(
VAR
VAR
VAR
maxFieldSize: INTEGER;
fieldOverflow: BOOLEAN;
fieldTerminator: CHAR;
tabType: TTabTypes)
: BOOLEAN;
FUNCTION
END;
{TReadUnivText.}ReadLine(
maxLineSize: INTEGER;
VAR lineOverflow: BOOLEAN;
VAR lineTerminator: CHAR)
: BOOLEAN;
{ Returns one line of text each time called }
{TReadUnivText.}GetParaPicture(heap: THeap)
: PicHandle;
{ Copies the picture for the current paragraph into heap }
{$IFC WithUObject}
TTKWriteUnivText = SUBCLASS OF TTKUnivText
{$ELSEC}
TWriteUnivText
= SUBCLASS OF TUnivText
{$ENDC}
{$IFC WithUObject}
FUNCTION {TWriteUnivText.}CREATE(object: TObject;
itsHeap: THeap;
itsTString: TString;
itsDataSize: INTEGER)
: TTKWriteUnivText;
{$ELSEC}
FUNCTION {TWriteUnivText.}CREATE(object: TUTObject;
itsHeap: THeap;
itsTString: TUTString;
itsDataSize: INTEGER)
: TWriteUnivText;
{$ENDC}
PROCEDURE {TWriteUnivText.}FillParagraph;
{Writes one run of text each time called}
END;
{$IFC NOT WithUObject}
FUNCTION NewUTObject(heap: THeap; itsClass: TClass): TUTObject;
{$ENDC}
{$IFC fUniversalTextTrace}
VAR
fPrintSecrets: BOOLEAN;
{$ENDC}
IMPLEMENTATION
{$IFC fDbgOk}
{$R+}
{$ELSEC}
{$R-}
{$ENDC}
{$IFC fSymOk}
{$D+}
{$ELSEC}
{$D-}
{$ENDC}
{$SETC doTraceUT := FALSE}
{$SetC fTraceUT := doTraceUT AND fUniversalTextTrace}
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{$I libut/UUnivText2.text}
{$IFC WithUObject}
{$S TKUTInit}
{$ELSEC}
{$S UTInit}
{$ENDC}
END.
Added EqualBytes
Moved several routines to CLASLIB so they can go into PASLIB;
Here we still have (in SgCLAres):
LIntDivLint, LIntDivInt, LIntMulInt, LIntAndLInt, LIntOrLInt,
XferLeft, XferRight, RotatePattern, EnterLisabug}
Added %_JmpTo, %_ExitCaller, %_ExitFunny, %_CallMethod, %_Super;
Replaced IsJsr by %_NextMethod;
Deleted XPNewMethod;
Changed Segment from SgABCres to SgCLAres & added some SgCLAini procedures;
Added $D information conditioned on DEBUGF flag;
(Note: SP=A7)}
RELEASE TK7D TO TOOLKIT TEAM}
RELEASE TK7C TO TOOLKIT TEAM}
;=============================================================================================
DEBUGF .EQU 1
; 1 to include $D+ info, 0 to exclude it
;=============================================================================================
.MACRO HEAD
.IF DEBUGF
LINK
A6,#0
MOVE.L (SP)+,A6
.ENDC
.ENDM
.MACRO TAIL
.IF DEBUGF
UNLK
A6
RTS
.ASCII %1
.ENDC
.ENDM
;=============================================================================================
.SEG
'SgXFER'
;=============================================================================================
.PROC XFERLEFT
HEAD
; PROCEDURE XferLeft(source, dest: TP; nBytes: INTEGER);
;
; uses A0,A1,D0,D1
;
XFER
MOVE.L
MOVE.W
MOVE.L
MOVE.L
MOVE.L
(SP)+,D1
(SP)+,D0
(SP)+,A1
(SP)+,A0
D1,-(SP)
;
;
;
;
;
SUB.W
#1,D0
; DECREMENT NBYTES
BLT.S
RTSLEFT
MOVE.B
DBF
(A0)+,(A1)+
D0,XFER
RTSLEFT RTS
TAIL
'XFERLEFT'
;=============================================================================================
.PROC XFERRIGH
HEAD
; PROCEDURE XferRight(source, dest: TP; nBytes: INTEGER);
;
; uses A0,A1,D0,D1
;
MOVE.L
MOVE.W
MOVE.L
MOVE.L
MOVE.L
(SP)+,D1
(SP)+,D0
(SP)+,A1
(SP)+,A0
D1,-(SP)
;
;
;
;
;
TST.W
BLE.S
D0
RTSRIGH
; TEST NBYTES
; NBYTES <= 0, SO EXIT
ADDA.W
ADDA.W
D0,A0
D0,A1
SUB.W
#1,D0
; DECREMENT NBYTES
XFER
MOVE.B
DBF
-(A0),-(A1)
D0,XFER
RTSRIGH RTS
TAIL
'XFERRIGH'
;=============================================================================================
.PROC EqualBytes
HEAD
; PROCEDURE EqualBytes(source, dest: TP; nBytes: INTEGER);
;
; uses A0,A1,D0,D1
;
XFER
MOVE.L
MOVE.W
MOVE.L
MOVE.L
MOVE.L
(SP)+,D1
(SP)+,D0
(SP)+,A1
(SP)+,A0
D1,-(SP)
;
;
;
;
;
MOVE.B
#1,4(SP)
SUB.W
#1,D0
; DECREMENT NBYTES
BLT.S
RTSEQUL
MOVE.B
CMP.B
BNE
DBF
(A0)+,D1
(A1)+,D1
UNEQUL
D0,XFER
RTSEQUL RTS
UNEQUL
CLR.B
RTS
4(SP)
TAIL
'EQUALBYT'
; RETURN FALSE
;=============================================================================================
.PROC ROTATEPA
HEAD
; PROCEDURE RotatePattern(pInPat, pOutPat: ^Pattern; dh, dv: LONGINT);
;
; uses A0-A2,D0-D4
;
MOVEM.L (SP)+,D0-D2/A0-A1
MOVE.L D0,-(SP)
MOVEM.L A2/D3-D4,-(SP)
AND.L
; dh := dh MOD 8
#7,D2
; *****
#7,D3
; Loop count
BEGIN *****
MOVE.B
ROL.B
D2,D0
MOVE.W
SUB.W
AND.W
D3,D4
D1,D4
#7,D4
MOVE.B
DBF
D3,RLOOP
END; *****
MOVEM.L (SP)+,A2/D3-D4
; Restore A2,D3,D4
RTS
TAIL
'ROTATEPA'
;=============================================================================================
.FUNC LINTDIVL
HEAD
; FUNCTION LIntDivLint(i, j: LONGINT): LONGINT;
;
; uses A0,D0,D1
;
.REF
LD
CHEK
MOVE.L
(SP)+,A0
; Return address
MOVE.L
MOVE.L
(SP)+,D0
(SP)+,D1
; D0 := j
; D1 := i
CMP.L
BGT
CMP.L
BLT
JMP
#32767,D0
TOOLONG
#-32768,D0
TOOLONG
LD
TOOLONG ASR.L
ASR.L
JMP
TAIL
; Too small
; Can't BGT LD in this assembler
#1,D0
#1,D1
CHEK
'LINTDIVL'
;=============================================================================================
.FUNC LINTDIVI
HEAD
; FUNCTION LIntDivInt(i: LONGINT; j: INTEGER): LONGINT;
;
; uses A0,D0,D1,D2
;
LD
JPOS
.DEF
LD
MOVE.L
(SP)+,A0
; Return address
MOVE.W
MOVE.L
(SP)+,D0
(SP)+,D1
; D0 := j
; D1 := i
CMP.W
BEQ
#1,D0
DV1
; IF j = 1, return i
MOVE.L
MOVE.W
D1,-(SP)
D0,-(SP)
; Push i as LONGINT
; Push j as INTEGER
CLR.L
D1
TST.W
BGE
NEG.W
NEG.L
(SP)
JPOS
(SP)
2(SP)
TST.L
2(SP)
; negate j
; negate i
SMI
BGE
NEG.L
D2
IPOS
2(SP)
; D2 := (i < 0)
MOVE.W
DIVU
2(SP),D1
(SP),D1
; Divide MSW of i by j
MOVE.L
MOVE.W
DIVU
D1,D0
4(SP),D0
(SP)+,D0
SWAP
MOVE.W
D1
D0,D1
TST.B
BEQ
NEG.L
D2
DUN
D1
; Was i negative?
DUN
ADD.L
#4,SP
; Popeye
DV1
MOVE.L
D1,(SP)
JMP
(A0)
; Return
TAIL
'LINTDIVI'
IPOS
; negate i
;=============================================================================================
.FUNC LINTMULI
HEAD
; FUNCTION LIntMulInt(i: LONGINT; j: INTEGER): LONGINT;
;
; uses A0,D0,D1,D2
;
MOVE.L
(SP)+,A0
; Return address
MOVE.W
MOVE.L
(SP)+,D1
(SP)+,D0
; D1 := j
; D0 := i
CMP.W
BEQ
#1,D1
MU1
; IF j = 1, return i
MOVE.L
D2,-(SP)
; Save D2
MOVE.W
SWAP
D0,D2
D0
; D2 := LSW of I
; D0 := MSW of I
MU1
MULU
LSL.L
LSL.L
MULU
ADD.L
D1,D0
#8,D0
#8,D0
D1,D2
D2,D0
; D0 := D0 * j
MOVE.L
(SP)+,D2
; restore D2
MOVE.L
D0,(SP)
JMP
(A0)
; Return
TAIL
'LINTMULI'
; D0 := product
;=============================================================================================
.FUNC LINTANDL
HEAD
; FUNCTION LIntAndLInt(i, j: LONGINT): LONGINT;
;
; uses A0,D0
;
MOVE.L
(SP)+,A0
; Return address
MOVE.L
AND.L
(SP)+,D0
(SP)+,D0
; D0 := j
; D0 := i AND j
MOVE.L
D0,(SP)
JMP
(A0)
; Return
TAIL
'LINTANDL'
;=============================================================================================
.FUNC LINTORLI
HEAD
; FUNCTION LIntOrLInt(i, j: LONGINT): LONGINT;
;
; uses A0,D0
;
MOVE.L
(SP)+,A0
; Return address
MOVE.L
OR.L
(SP)+,D0
(SP)+,D0
; D0 := j
; D0 := i OR j
MOVE.L
D0,(SP)
JMP
(A0)
; Return
TAIL
'LINTORLI'
;=============================================================================================
.FUNC LINTXORL
HEAD
; FUNCTION LIntXorLInt(i, j: LONGINT): LONGINT;
;
; uses A0,D0, D1
;
MOVE.L
(SP)+,A0
; Return address
MOVE.L
MOVE.L
EOR.L
(SP)+,D0
(SP)+,D1
D1,D0
; D0 := j
; D1 := i
; D0 := i XOR j
MOVE.L
D0,(SP)
JMP
(A0)
; Return
TAIL
'LINTXORL'
;=============================================================================================
.PROC ENTERLIS
HEAD
; PROCEDURE EnterLisabug;
TRAP
RTS
#0
TAIL
'ENTERLIS'
;=============================================================================================
.END
{The maximum number of tabstops on a ruler allowed by LisaWrite and its ilk}
{Maximum number of chars saved for backing up the lpLim during Write UT}
TYPE
TPtrToolKitUT = ^ToolKitUT;
ToolKitUT =
Tcs;
TSavedPara =
RECORD
firstLp:
TLp;
theArce:
TArce;
theArpe:
TArpe;
{$IFC WithUObject}
theText:
TString;
{$ELSEC}
theText:
TUTString;
{$ENDC}
END;
PSavedPara =
^TSavedPara;
HSavedPara =
^PSavedPara;
{$IFC NOT WithUObject}
Byte =
-128..127;
TpLONGINT =
^LONGINT;
TPByte =
^Byte;
{$ENDC}
{private types not used in the Toolkit; used in place of the Toolkit's type coercion to a
Handle, since a Handle outside of the Toolkit is a double-indeirect pointer to a byte}
UTpLongint = ^LONGINT;
UTppLongint = ^UTpLongint;
{ Carefull, carefull, carefull here kids. Since I can't have private fields and/or methods in my classes
inorder to resolve a few types I am forced to do this thing to keep you innocents from having to
include an ugly list of units. Only one instance of these variabes exists ever! Therefore I can only
do things one at a time.}
TSecretThings = RECORD
streamArrayIndex:
lpd:
achad:
END;
Byte;
TALpd;
TAchad;
VAR
{$IFC WithUObject}
activeStream:
{$ELSEC}
activeStream:
{$ENDC}
secrets:
currentLpd:
dataIndex:
dataLp:
savedPara:
nOfSavedPara:
{$IFC WithUObject}
theData:
{$ELSEC}
theData:
{$ENDC}
TTKWriteUnivText;
TWriteUnivText;
TSecretThings;
TLpd;
INTEGER;
TLp;
ARRAY [1..maxBacking] OF HSavedPara;
0..maxBacking;
TString;
TUTString;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{--------------------------------------------------------------------------------------------------------}
FUNCTION Max(i, j: LONGINT): LONGINT;
{--------------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
IF i > j THEN
Max := i
ELSE
Max := j;
END;
{$IFC WithUObject}
{$S TKUTInit}
{$ELSEC}
{$S UTInit}
{$ENDC}
{--------------------------------------------------------------------------------------------------------}
PROCEDURE ABCBreak(s: S255; errCode: LONGINT);
{--------------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
{$IFC fDbgObject}
WriteLn;
Write(CHR(7), s);
{Beep}
IF errCode <> 0 THEN
Write(': ', errCode:1);
WriteLn;
{$ENDC}
HALT;
END;
{$IFC WithUObject}
{$S TKUTInit}
{$ELSEC}
{$S UTInit}
{$ENDC}
{--------------------------------------------------------------------------------------------------------}
PROCEDURE SetCp(object: TUTObject; itsClass: TClass);
{--------------------------------------------------------------------------------------------------------}
pointer}
index}
byte, store it...}
conversion (cf ConvertHeap: FindClasses)}
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{--------------------------------------------------------------------------------------------------------}
FUNCTION NewDynObject(heap: THeap; itsClass: TClass; dynBytes: INTEGER): TUTObject;
{--------------------------------------------------------------------------------------------------------}
VAR nBytes: INTEGER;
object: TUTObject;
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
nBytes := SizeOfCp(TPSliceTable(itsClass)) + dynBytes;
object := POINTER(ORD(HAllocate(THz(heap), nBytes)));
{TUTObject() won't work until after SetCp}
IF ORD(object) = ORD(hNIL) THEN
ABCBreak('NewObject: Heap full, can''t make an object of size', nBytes);
SetCp(object, itsClass);
NewDynObject := object;
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{--------------------------------------------------------------------------------------------------------}
FUNCTION NewUTObject(heap: THeap; itsClass: TClass): TUTObject;
{--------------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
NewUTObject := NewDynObject(heap, itsClass, 0);
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{--------------------------------------------------------------------------------------------------------}
PROCEDURE ResizeDynObject(object: TUTObject; newTotalBytes: INTEGER);
{--------------------------------------------------------------------------------------------------------}
VAR i: INTEGER;
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
IF (newTotalBytes < 0) OR (newTotalBytes > (MAXINT-20)) THEN
ABCBreak('New size must lie between 0 and 32K-20, not', newTotalBytes);
ChangeSizeH(THz(object.Heap), TH(object), newTotalBytes);
IF CbDataOfH(THz(object.Heap), TH(object)) < newTotalBytes THEN
ABCBreak('ResizeDynObject: Heap full, size can''t change to', newTotalBytes);
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{--------------------------------------------------------------------------------------------------------}
FUNCTION ClassPtr(hndl: UTppLongint): TClass;
{--------------------------------------------------------------------------------------------------------}
VAR stp: RECORD
CASE INTEGER OF
1: (asLong: LONGINT);
2: (asBytes: PACKED ARRAY [0..3] OF TByte);
3: (asClass: TClass);
END;
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
stp.asLong := hndl^^;
stp.asBytes[0] := 0;
ClassPtr := stp.asClass;
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{--------------------------------------------------------------------------------------------------------}
FUNCTION SizeOfClass(class: TClass): INTEGER;
{--------------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
SizeOfClass := SizeOfCp(TPSliceTable(class));
END;
{$IFC WithUObject}
{$S TKUTInit}
{$ELSEC}
{$S UTInit}
{$ENDC}
{--------------------------------------------------------------------------------------------------------}
PROCEDURE InitObject;
{--------------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
{Do very little for the time beeing}
END;
{$IFC WithUObject}
{$S TKUTInit}
{$ELSEC}
{$S UTInit}
{$ENDC}
{--------------------------------------------------------------------------------------------------------}
PROCEDURE ClascalError(error: INTEGER); {called with error = 0 after successful Clascal initialization}
{--------------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
IF error > 0 THEN
ABCBreak('Some kind of Clascal error', error);
END;
METHODS OF TUTObject;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TObject.}Free;
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
SELF.FreeObject;
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TObject.}FreeObject;
{----------------------------------------------------------------------------------------------------}
VAR heap:
THeap;
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
heap := SELF.Heap;
FreeH(THz(heap), TH(SELF));
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
FUNCTION {TObject.}Heap: THeap;
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
Heap := THeap(HzFromH(TH(SELF)));
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
FUNCTION {TObject.}Class: TClass;
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
Class := ClassPtr(UTppLongint(SELF));
END;
{$IFC WithUObject}
{$S TKUTInit}
{$ELSEC}
{$S UTInit}
{$ENDC}
BEGIN {Class Initialization}
{$IFC fTraceUT}
LogCall;
InitClascal(ClascalError);
InitObject;
END;
{$ENDC}
{Provide an error routine in case of errors in Clascal run-time support}
{Do remaining initialization}
METHODS OF TUTCollection;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
FUNCTION {TCollection.}CREATE(object: TUTObject; heap: THeap; initialSlack: INTEGER): TUTCollection;
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
IF object = NIL THEN
ABCBreak('TUTCollection.CREATE must be passed an already-allocated object by a subclass CREATE', 0);
SELF := TUTCollection(object);
WITH SELF DO
BEGIN
size := 0;
{$H-} dynStart := SizeOfClass(SELF.Class); {$H+}
holeStart := 0;
holeSize := initialSlack;
holeStd := 0;
END;
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
FUNCTION {TCollection.}AddrMember(i: LONGINT): LONGINT;
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
IF i > SELF.holeStart THEN
i := i + SELF.holeSize;
END;
SELF.holeStart := newHoStart;
SELF.holeSize := newHoSize;
END;
END;
WITH SELF DO
BEGIN
size := size + deltaMembers;
holeSize := holeSize - deltaMembers;
holeStart := holeStart + deltaMembers;
IF oldHoSize = 0 THEN
IF holeStd = 0 THEN
IF holeSize > 0 THEN
{$H-}
SELF.StopEdit; {$H+}
END;
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TCollection.}InsManyAt(i: LONGINT; otherCollection: TUTCollection; index, howMany: LONGINT);
{----------------------------------------------------------------------------------------------------}
VAR memberBytes:
INTEGER;
beforeHole:
INTEGER;
srcAddr:
LONGINT;
dstAddr:
LONGINT;
j:
INTEGER;
offset:
INTEGER;
BEGIN
{Stops edit if it wasn't explicitly started}
{$IFC fTraceUT}
LogCall;
{$ENDC}
memberBytes := SELF.memberBytes;
SELF.EditAt(i, howMany);
IF howMany > 0 THEN
IF otherCollection.Class = SELF.Class THEN
{Can do it with at most two Xfers}
BEGIN
beforeHole := Min(howMany, otherCollection.holeStart + 1 - index);
srcAddr := otherCollection.AddrMember(index);
dstAddr := SELF.AddrMember(i);
IF beforeHole > 0 THEN
BEGIN
UTXferLeft(Ptr(srcAddr), Ptr(dstAddr), beforeHole * memberBytes);
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TCollection.}ResizeColl(membersPlusHole: INTEGER);
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
IF membersPlusHole <> (SELF.size + SELF.holeSize) THEN
ResizeDynObject(SELF, SELF.dynStart + (membersPlusHole * SELF.MemberBytes));
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TCollection.}ShiftColl(afterSrcIndex, afterDstIndex, howMany: INTEGER);
{----------------------------------------------------------------------------------------------------}
VAR memberBytes:
INTEGER;
numBytes:
INTEGER;
startAddr:
LONGINT;
srcAddr:
LONGINT;
dstAddr:
LONGINT;
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
IF (howMany > 0) AND (afterSrcIndex <> afterDstIndex) THEN
BEGIN
memberBytes := SELF.MemberBytes;
numBytes := howMany * memberBytes;
startAddr := TpLONGINT(SELF)^ + SELF.dynStart;
srcAddr := startAddr + afterSrcIndex * memberBytes;
dstAddr := startAddr + afterDstIndex * memberBytes;
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TCollection.}StartEdit(withSlack: INTEGER);
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
SELF.holeStd := withSlack;
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TCollection.}StopEdit;
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
FUNCTION {TArray.}At(i: LONGINT): Ptr;
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
{ At := Ptr(SELF.AddrMember(i));
but for speed...}
IF i > SELF.holeStart THEN
i := i + SELF.holeSize;
At := Ptr(TpLONGINT(SELF)^ + SELF.dynStart + (SELF.recordBytes * (i - 1)));
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TArray.}DelAll;
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
SELF.EditAt(1, -SELF.size);
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TArray.}DelAt(i: LONGINT);
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
SELF.EditAt(i, -1);
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TArray.}DelManyAt(i, howMany: LONGINT);
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
SELF.EditAt(i, -howMany);
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TArray.}PutAt(i: LONGINT; pRecord: Ptr);
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
UTXferLeft(pRecord, Ptr(SELF.AddrMember(i)), SELF.recordBytes);
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TArray.}InsAt(i: LONGINT; pRecord: Ptr);
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
SELF.EditAt(i, 1);
SELF.PutAt(i, pRecord);
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TArray.}InsLast(pRecord: Ptr);
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
{$IFC fTrce}BP(3);{$ENDC}
SELF.InsAt(SELF.size + 1, pRecord);
{$IFC fTrce}EP;{$ENDC}
END;
{$IFC WithUObject}
{$S TKUTInit}
{$ELSEC}
{$S UTInit}
{$ENDC}
END;
METHODS OF TUTString;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
FUNCTION {TString.}CREATE(object: TUTObject; heap: THeap; initialSlack: INTEGER): TUTString;
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
IF ODD(initialSlack) THEN
initialSlack := initialSlack + 1;
IF object = NIL THEN
object := NewDynObject(heap, THISCLASS, initialSlack);
SELF := TUTString(TUTCollection.CREATE(object, heap, initialSlack));
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
FUNCTION {TString.}At(i: LONGINT): CHAR;
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
{At := CHAR(TPByte(SELF.AddrMember(i))^); but for speed...}
IF i > SELF.holeStart THEN
i := i + SELF.holeSize;
At := CHAR(TPByte(TpLONGINT(SELF)^ + SELF.dynStart + (i - 1))^);
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TString.}DelAt(i: LONGINT);
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
SELF.EditAt(i, -1);
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TString.}DelAll;
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
SELF.EditAt(1, -SELF.size);
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TString.}DelManyAt(i, howMany: LONGINT);
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
SELF.EditAt(i, -howMany);
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TString.}InsAt(i: LONGINT; character: CHAR);
{----------------------------------------------------------------------------------------------------}
VAR pByte:
TPByte;
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
SELF.EditAt(i, 1);
{TPByte(SELF.AddrMember(i))^ := PByte(character);
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
SELF.EditAt(i + howMany, 0);
UTXferLeft(Ptr(SELF.AddrMember(i)), pPackedArrayOfCharacter, howMany);
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
FUNCTION {TString.}MemberBytes: INTEGER;
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
MemberBytes := 1;
END;
{$IFC WithUObject}
{$S TKUTInit}
{$ELSEC}
{$S UTInit}
{$ENDC}
END;
{$ENDC}
{$IFC fUniversalTextTrace}
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{--------------------------------------------------------------------------------------------------------}
PROCEDURE PrintRun;
{--------------------------------------------------------------------------------------------------------}
VAR i:
INTEGER;
tab:
TTabDescritor;
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
{$IFC fTrce}BP(11);{$ENDC}
{lpd, achad}
WRITELN('the character Descriptor is ');
FOR i := 1 TO activeStream.data.size DO
WRITE(activeStream.data.At(i));
WRITELN;
WRITELN('
maxDataSize ', activeStream.maxDataSize);
{$H-}
WITH activeStream.characterDescriptor DO
BEGIN
WRITELN('
font ', font);
WRITELN('
face ');
WRITELN('
Superscript ', Superscript);
WRITELN('
keepOnSamePage ', keepOnSamePage);
END;
WRITELN('the paragraph Descriptor is ');
WITH activeStream.paragraphDescriptor DO
BEGIN
WRITELN('
paraGraphStart ', paraGraphStart);
WRITELN('
firstLineMargin ', firstLineMargin);
WRITELN('
bodyMargin ', bodyMargin);
WRITELN('
rightMargin ', rightMargin);
WRITELN('
paraLeading ', paraLeading);
WRITELN('
lineSpacing ', lineSpacing);
WRITELN('
', tabTable.size:2,' Tabs ');
FOR i := 1 TO tabTable.size DO
BEGIN
tab := TTabDescritor(tabTable.At(i));
WITH tab DO
BEGIN
WRITELN('
position ', position);
WRITE ('
fillBetweenTabs ');
CASE fillBetweenTabs OF
tNoFill:
WRITELN('No fill');
tDotFill:
WRITELN('Dot fill');
tHyphenFill:
WRITELN('Hyphen fill');
tUnderLineFill: WRITELN('Underline fill');
END;{CASE}
WRITE ('
tabType ');
CASE tabType OF
qLeftTab:
WRITELN('Left tab');
qCenterTab:
WRITELN('Center tab');
qRightTab:
WRITELN('Right tab');
qPeriodTab:
WRITELN('Decimal period tab');
qCommaTab:
WRITELN('Decimal comma tab');
END;{CASE}
END;
END;
WRITE ('
paraType ');
CASE paraType OF
qLeftPara:
WRITELN('Left aligned');
qCenterPara:
WRITELN('Centered');
qRightPara:
WRITELN('Right aligned');
qJustPara:
WRITELN('Justified');
END;{CASE}
WRITELN('
hasPicture ', hasPicture);
END;
{$H+}
{$IFC fTrce}EP;{$ENDC}
END;
{$ENDC}
{$IFC fUniversalTextTrace}
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{--------------------------------------------------------------------------------------------------------}
PROCEDURE PrintLpd(theLpd: TALpd);
{--------------------------------------------------------------------------------------------------------}
PROCEDURE WriteQuad(quad: TQuad);
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
CASE quad OF
quadL: WRITELN('quadL');
quadC: WRITELN('quadC');
quadR: WRITELN('quadR');
quadJ: WRITELN('quadJ');
END;
END;
PROCEDURE WriteTArpe(arpe: TArpe);
VAR i: INTEGER;
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
WITH arpe DO
BEGIN
WRITELN('
cb:
WRITELN('
sy:
WRITELN('
xLftFst:
WRITELN('
xLftBody:
WRITELN('
xRt:
WRITELN('
yLd:
WRITELN('
fill1:
WRITELN('
yLine:
',
',
',
',
',
',
',
',
cb:1);
sy:1);
xLftFst:1);
xLftBody:1);
xRt:1);
yLd:1);
fill1:1);
yLine:1);
WRITE ('
quad:
');
WriteQuad(quad);
WRITELN('
itbLim:
', itbLim:1);
WRITELN('
argtbd:');
FOR i := 0 TO itbLim - 1 DO
{$R-}
WITH argtbd[i] DO
BEGIN
WRITELN('
[',i:0,']:');
WRITELN('
x:
', x:1);
(* WRITELN('
fill4:
', fill4:1); *)
WRITE ('
quad:
');
WriteQuad(argtbd[i].quad);
WRITE ('
tyfill:
');
CASE tyfill OF
tyfillNil: WRITELN('tyfillNil');
tyfillDots: WRITELN('tyfillDots');
tyfillHyph: WRITELN('tyfillHyph');
tyfillUL:
WRITELN('tyfillUL');
END;
END;
WRITELN('
END;
{$R+}
END;
BEGIN
{$IFC fTraceUT}
LogCall;
{$IFC fTrce}BP(11);{$ENDC}
chLdr:
', chLdr:1);
{$ENDC}
ics:1);
ilpd:1);
fParSt);
lp:1);
lplim:1);
lpson:1);
icsson:1);
', tyset.fRce);
', tyset.fParBnds);
WRITELN('
fRpe:
END;
WRITELN('lpFstPar:
WRITELN('lpLimPar:
', tyset.fRpe);
', lpFstPar:1);
', lpLimPar:1);
IF tyset.fRpe THEN
IF rpe = NIL THEN
WRITELN('rpe:
ELSE
WITH rpe^ DO
BEGIN
WRITELN('rpe:');
WriteTArpe(rpe^);
END;
NIL')
IF tyset.fRce THEN
WITH arce DO
BEGIN
WRITELN('arce:');
WRITELN('
cb:
WRITELN('
fVan:
WRITELN('
fBold:
WRITELN('
fItalic:
WRITELN('
fUnderline:
WRITELN('
fill4:
WRITELN('
cbSuperscript:
WRITELN('
ifnt:
WRITELN('
fKeep:
WRITELN('
fOutLine:
WRITELN('
fShadow:
WRITELN('
fFillB:
WRITELN('
fFillC:
WRITELN('
fFillD:
WRITELN('
fFillE:
WRITELN('
fFillF:
END;
',
',
',
',
',
',
',
',
',
',
',
',
',
',
',
',
cb:1);
fVan:1);
fBold:1);
fItalic:1);
fUnderline:1);
fill4:1);
cbSuperscript:1);
ifnt:1);
fKeep:1);
fOutLine:1);
fShadow:1);
fFillB:1);
fFillC:1);
fFillD:1);
fFillE:1);
fFillF:1);
IF tyset.fRpe THEN
BEGIN
WRITELN('arpe:');
WriteTArpe(arpe);
END;
END;
WRITELN('');
WRITELN;
{$IFC fTrce}EP;{$ENDC}
END;
{$ENDC}
{$IFC fUniversalTextTrace}
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{--------------------------------------------------------------------------------------------------------}
PROCEDURE PrintAchad(achad: TAchad);
{--------------------------------------------------------------------------------------------------------}
VAR i:
INTEGER;
size:
INTEGER;
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
{$IFC fTrce}BP(11);{$ENDC}
WITH achad DO
BEGIN
WRITELN(' Achad ');
WRITELN('ichFst:
', ichFst:1);
WRITELN('ichLim:
', ichLim:1);
IF rgch <> NIL THEN
BEGIN
size := ichlim - ichFst - 1;
IF size >= 80 THEN
size := 79;
FOR i := ichFst TO ichFst + size DO
{$R-}
IF rgch^[i] >= 32 THEN
WRITE(CHR(rgch^[i]))
ELSE
WRITE('<', rgch^[i]:0, '>');
{$R+}
WRITELN;
IF ichlim - ichFst >= 79 THEN
WRITELN('etc, etc...');
END;
WRITELN('');
WRITELN;
END;
{$IFC fTrce}EP;{$ENDC}
END;
{$ENDC}
{$IFC fUniversalTextTrace}
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{--------------------------------------------------------------------------------------------------------}
PROCEDURE PrintSecrets(achad: TAchad; theLpd: TALpd);
{--------------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
{$IFC fTrce}BP(11);{$ENDC}
WRITELN('streamArrayIndex is ', secrets.streamArrayIndex);
PrintLpd(theLpd);
PrintAchad(achad);
{$IFC fTrce}EP;{$ENDC}
END;
{$ENDC}
{$IFC WithUObject}
{$S TKUTWrite}
{$ELSEC}
{$S UTWrite}
{$ENDC}
{--------------------------------------------------------------------------------------------------------}
PROCEDURE SeqLpdUTBB(Lpd: TLpd; var achad: Tachad);
{--------------------------------------------------------------------------------------------------------}
VAR howMany:
INTEGER;
done:
BOOLEAN;
index:
INTEGER;
backUp:
INTEGER;
newPara:
BOOLEAN;
{$IFC WithUObject}
newData:
TString;
{$ELSEC}
newData:
TUTString;
{$ENDC}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
{$IFC fTrce}BP(11);{$ENDC}
{LSR: put the next assignment and the WITH before the debugging code because
PrintSecrets depends on it.}
currentLpd := lpd;
WITH lpd^ DO
BEGIN
rpe := @arpe;
rce := @arce;
END;
{$IFC fUniversalTextTrace}
IF fPrintSecrets THEN
BEGIN
WRITELN(' SeqLpdUTBB ');
PrintSecrets(achad, currentLpd^);
WRITELN('dataLp =
', dataLp:0);
WRITELN('dataIndex =
', dataIndex:0);
WRITELN('nOfSavedPara = ', nOfSavedPara:0);
END;
{$ENDC}
newPara := FALSE;
', backUp:0);
done := TRUE;
END
ELSE
index := index + 1;
IF NOT done THEN
{ This is FATAL !!!}
BEGIN
{$IFC fUniversalTextTrace}
WRITELN('Fatal back up attempt in SeqLpdUTBB');
PrintSecrets(achad, lpd^);
{$ENDC}
HALT;
END;
END
ELSE
BEGIN
IF activeStream.data.Size = 0 THEN
{ Test if there is anything left in the buffer, }
BEGIN
newPara := TRUE;
activeStream.ParagraphDescriptor.paraGraphStart := TRUE;
{$IFC WithUObject}
activeStream.ParagraphDescriptor.additionalChrInParagraph := 0;
{$ENDC}
activeStream.FillParagraph;
{ if not then try to get one more paragraph }
activeStream.data.StopEdit;
{ Remove any holes from data }
{$IFC fUniversalTextTrace}
IF fPrintSecrets THEN
BEGIN
WRITELN('FillRun returns:');
PrintRun;
END;
{$ENDC}
dataIndex := 0;
WITH lpd^ DO
{ Pre-fill the lpd with standard data }
BEGIN
{$H-} MoveRgch(@arpe, @arpeStd, arpeStd.cb); {$H+}
{$H-} MoveRgch(@arce, @arceStd, arceStd.cb); {$H+}
dataLp := lpLim;
END;
activeStream.RunToStream;
END
ELSE
BEGIN
{$IFC fUniversalTextTrace}
IF fPrintSecrets THEN
WRITELN('Procede with the rest of the old run:');
{$ENDC}
dataIndex := Lpd^.lpLim - dataLp;
IF dataIndex <> 0 THEN
lpd^.fParSt := FALSE;
END;
theData := activeStream.data;
END;
{ Compute how many bytes to transfer this time }
howMany := MIN(achad.ichLim - achad.ichFst, theData.size - dataIndex);
{$IFC fUniversalTextTrace}
IF fPrintSecrets THEN
BEGIN
WRITELN('theData.size =
WRITELN('dataLp =
WRITELN('dataIndex =
WRITELN('howMany =
WRITELN('newPara =
END;
{$ENDC}
',
',
',
',
',
theData.size:0);
dataLp:0);
dataIndex:0);
howMany:0);
newPara:0);
WITH lpd^ DO
BEGIN
lp := lpLim;
lplim := lp + howMany;
END;
WITH secrets.achad DO
{ Build our own achad just in case... }
BEGIN
rgch := POINTER(ORD4(theData.AddrMember(1)) + dataIndex);
ichfst := 0;
ichLim := howMany;
END;
{ Copy the achad }
{ Check for NIL rgch.}
{ If NIL then pass data else copy the data }
IF achad.rgch = NIL THEN
achad := secrets.achad
ELSE
BEGIN
achad.ichlim := achad.ichFst + howMany;
MoveAchad(achad, secrets.achad);
END;
IF howMany = 0 THEN
{ We are done, kill all saved stuff }
FOR index := 1 TO nOfSavedPara DO
BEGIN
savedPara[index]^^.theText.Free;
FreeH(HzFromH(TH(savedPara[index])), TH(savedPara[index]));
END
ELSE
BEGIN
IF newPara THEN
{ New text in activeStream.data... }
BEGIN
done := FALSE;
index := nOfSavedPara;
WHILE (NOT done) AND (index > 0) DO
{ Get ridd of old stuff }
WITH savedPara[index]^^ DO
IF (lpd^.lpLim - (firstLp + theText.size) ) >= maxBacking THEN {LSR}
BEGIN
theText.Free;
FreeH(HzFromH(TH(savedPara[index])), TH(savedPara[index]));
index := index - 1;
nOfSavedPara := nOfSavedPara - 1;
END
ELSE
done := true;
{LSR: changed direction of following loop}
FOR index := nOfSavedPara DOWNTO 1 DO
{ Shift everything to free the first one }
savedPara[index + 1] := savedPara[index];
nOfSavedPara := nOfSavedPara + 1;
{ Make a new place to save old paragraphs }
savedPara[1] := POINTER(HAllocate(THz(activeStream.Heap), SIZEOF(TSavedPara)));
WITH savedPara[1]^^, lpd^ DO
BEGIN
firstLp := lp;
theArpe := arpe;
theArce := arce;
theText := activeStream.data;
END;
END;
IF (dataIndex + howMany) >= activeStream.data.Size THEN
BEGIN
{ Make a fresh string, the old one is in savedPara[1] }
{$IFC WithUObject}
{$ELSEC}
{$ENDC}
activeStream.data := newData;
activeStream.data.StartEdit(50);
dataLp := lpd^.lpLim;
END;
END;
{Allow holes}
{Make shure backUp will compute to zero}
{$IFC fUniversalTextTrace}
IF fPrintSecrets THEN
BEGIN
PrintSecrets(achad, currentLpd^);
WRITELN('dataLp =
', dataLp:0);
WRITELN('dataIndex =
', dataIndex:0);
WRITELN('nOfSavedPara = ', nOfSavedPara:0);
WRITELN('');
WRITELN;
WRITELN;
END;
{$ENDC}
{$IFC fTrce}EP;{$ENDC}
END;
{$IFC WithUObject}
METHODS OF TTKUnivText
{$ELSEC}
METHODS OF TUnivText
{$ENDC}
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
{$IFC WithUObject}
FUNCTION {TUnivText.}CREATE(object: TObject;
itsHeap: THeap;
itsTString: TString;
itsDataSize: INTEGER)
: TTKUnivText;
{$ELSEC}
FUNCTION {TUnivText.}CREATE(object: TUTObject;
itsHeap: THeap;
itsTString: TUTString;
itsDataSize: INTEGER)
: TUnivText;
{$ENDC}
{----------------------------------------------------------------------------------------------------}
{$IFC WithUObject}
VAR thisTabTable:
{$ELSEC}
VAR thisTabTable:
{$ENDC}
thisString:
TArray;
TUTArray;
^Tsp;
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
{$IFC fTrce}BP(11);{$ENDC}
IF object = NIL THEN
{$IFC WithUObject}
object := NewObject(itsHeap, THISCLASS);
{$ELSEC}
object := NewUTObject(itsHeap, THISCLASS);
{$ENDC}
{$IFC WithUObject}
SELF := TTKUnivText(object);
{$ELSEC}
SELF := TUnivText(object);
{$ENDC}
{ Get the stream }
SELF.itsOurTString := itsTString = NIL;
IF SELF.itsOurTString THEN
{$IFC WithUObject}
itsTString := TString.CREATE(NIL, itsHeap, itsDataSize);
{$ELSEC}
itsTString := TUTString.CREATE(NIL, itsHeap, itsDataSize);
{$ENDC}
itsTString.StartEdit(50);
SELF.data := itsTString;
SELF.maxDataSize := itsDataSize;
{Allow holes}
{$IFC WithUObject}
thisTabTable := TArray.CREATE(NIL, itsHeap, 0, SIZEOF(TTabDescriptor));
{$ELSEC}
thisTabTable := TUTArray.CREATE(NIL, itsHeap, 0, SIZEOF(TTabDescriptor));
{$ENDC}
thisTabTable.StartEdit(5);
SELF.paragraphDescriptor.tabTable := thisTabTable;
{$IFC fTrce}EP;{$ENDC}
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TUnivText.}Free;
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
{$IFC fTrce}BP(11);{$ENDC}
{If the dynamic array was not passed in then free it}
IF SELF.itsOurTString THEN
SELF.data.Free;
SELF.paragraphDescriptor.tabTable.Free;
SUPERSELF.Free;
{$IFC fTrce}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TUnivText.}Fields(PROCEDURE Field(nameAndType: S255));
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
SUPERSELF.Fields(Field);
Field('paraGraphStart: BOOLEAN');
{$IFC WithUObject}
Field('additionalChrInParagraph: INTEGER');
{$ENDC}
Field('firstLineMargin: INTEGER');
Field('bodyMargin: INTEGER');
Field('rightMargin: INTEGER');
Field('paraLeading: INTEGER');
Field('lineSpacing: BYTE');
{$IFC WithUObject}
Field('tabTable: TArray');
{$ELSEC}
Field('tabTable: TUTArray');
{$ENDC}
Field('paraType: BYTE');
Field('hasPicture: BOOLEAN');
Field('font: INTEGER');
Field('face: BYTE');
Field('superscript: BYTE');
Field('keepOnSamePage: BOOLEAN');
Field('maxDataSize: INTEGER');
{$IFC WithUObject}
Field('data: TString');
{$ELSEC}
Field('data: TUTString');
{$ENDC}
Field('itsOurTString: BOOLEAN');
Field('');
END;
{$ENDC}
{$IFC WithUObject}
{$S TKUTWrite}
{$ELSEC}
{$S UTWrite}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TUnivText.}RunToStream;
{----------------------------------------------------------------------------------------------------}
VAR i:
INTEGER;
found:
BOOLEAN;
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
{$IFC fTrce}BP(11);{$ENDC}
IF currentLpd^.tyset.fRce THEN
{ Convert the character descriptor }
WITH SELF.characterDescriptor, currentLpd^.rce^ DO
BEGIN
{ Set the face fields }
fbold
:= bold IN face;
fitalic
:= italic IN face;
funderline := underline IN face;
foutline
:= outline IN face;
fshadow
:= shadow IN face;
fvan := FALSE;
{ Because of the way lotus does fonts we have to convert the a real font to a lotus font }
found := FALSE;
i := 0;
WHILE (i <= ifntlst) AND NOT(found) DO
BEGIN
IF argfam[i] = font THEN
BEGIN
ifnt := i;
found := TRUE;
END;
i := i + 1;
END;
IF NOT found THEN ifnt := 0;
cbSuperscript := superscript;
fKeep := keepOnSamePage;
END; { with }
{ Convert the paragraph descriptor }
WITH SELF.ParagraphDescriptor, currentLpd^, rpe^ DO
BEGIN
fParSt := paraGraphStart;
IF paraGraphStart THEN
BEGIN
{LSR: added lpLim to the right side of each of the following assignments}
lpFstPar := lpLim;
{$IFC WithUObject}
lpLimPar := lpLim + SELF.data.Size + additionalChrInParagraph;
{$ELSEC}
lpLimPar := lpLim + SELF.data.Size;
{$ENDC}
END;
IF tyset.fRpe THEN
BEGIN
xLftFst := firstLineMargin;
xLftBody := bodyMargin;
xRt := rightMargin;
yLd := paraLeading;
yLine := lineSpacing;
CASE paraType OF
qLeftPara:
qCenterPara:
qRightPara:
quad := quadL;
quad := quadC;
quad := quadR;
qJustPara:
OTHERWISE
END;{CASE}
quad := quadJ;
quad := quadL;
itbLim := tabTable.Size - 1;
{$H-} SELF.TabTableToArgTbd; {$H+}
END;
END;
{$IFC fTrce}EP;{$ENDC}
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TUnivText.}StreamToRun;
{----------------------------------------------------------------------------------------------------}
VAR ifnt:
INTEGER;
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
{$IFC fTrce}BP(11);{$ENDC}
{ do the format stuff }
IF secrets.lpd.tyset.frce THEN
WITH SELF.characterDescriptor, secrets.lpd.rce^ DO
BEGIN
font := argfam[ifnt];
face := [];
IF fbold THEN
face := face + [bold];
IF fitalic THEN
face := face + [italic];
IF funderline THEN
face := face + [underline];
IF foutline THEN
face := face + [outline];
IF fshadow THEN
face := face + [shadow];
superscript := cbSuperscript;
keepOnSamePage := fKeep;
END;
IF secrets.lpd.tyset.frpe THEN
BEGIN
WITH SELF.paragraphDescriptor, secrets.lpd.rpe^ DO
BEGIN
paraGraphStart := secrets.lpd.fParSt;
firstLineMargin := xLftFst;
bodyMargin := xLftBody;
rightMargin := xRt;
paraLeading := yLd;
lineSpacing := yLine;
hasPicture := FALSE; {not yet implemented}
CASE quad OF
quadL:
quadC:
quadR:
quadJ:
OTHERWISE
END;{CASE}
paraType
paraType
paraType
paraType
paraType
:=
:=
:=
:=
:=
qLeftPara;
qCenterPara;
qRightPara;
qJustPara;
qLeftPara;
{ Resize the tab table and move the data }
SELF.ArgTbdToTabTable;
END;
{$IFC fTrce}EP;{$ENDC}
END;
{$IFC WithUObject}
{$S TKUTWrite}
{$ELSEC}
{$S UTWrite}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TUnivText.}TabTableToArgTbd;
{----------------------------------------------------------------------------------------------------}
VAR i:
INTEGER;
temp:
INTEGER;
ptrToTab:
Ptr;
tab:
TTabDescriptor;
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
{$IFC fTrce}BP(11);{$ENDC}
temp := MIN(SELF.paragraphDescriptor.tabTable.size, magicTabMax);
FOR i:= 1 to temp DO
BEGIN
tab := TTabDescriptor(SELF.paragraphDescriptor.tabTable.At(i));
{R$-}
tyFill := tyFillNil;
chLdr := ORD(' ');
END;
END;{CASE}
END;
{$R+}
END;
currentLpd^.rpe^.itbLim := temp - 1;
{$IFC fTrce}EP;{$ENDC}
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TUnivText.}ArgTbdToTabTable;
{----------------------------------------------------------------------------------------------------}
VAR i:
INTEGER;
tab:
TTabDescriptor;
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
{$IFC fTrce}BP(11);{$ENDC}
{ Size down the tab array for writing }
SELF.paragraphDescriptor.tabTable.DelAll;
FOR i := 0 to secrets.lpd.rpe^.itbLim - 1 DO
BEGIN
{$R-}
WITH tab, secrets.lpd.rpe^.argTbd[i] DO
BEGIN
position := x;
CASE quad OF
quadL:
quadC:
quadR:
quadJ:
OTHERWISE
END;{CASE}
tabType := qLeftTab;
tabType := qCenterTab;
tabType := qRightTab;
IF fDecimalComma THEN
tabType := qCommaTab
ELSE
tabType := qPeriodTab;
tabType := qLeftTab;
CASE tyFill OF
tyFillNil:
tyFillDots:
tyFillHyph:
tyFillUL:
OTHERWISE
END;{CASE}
fillBetweentabs
fillBetweentabs
fillBetweentabs
fillBetweentabs
fillBetweentabs
:=
:=
:=
:=
:=
tNoFill;
tDotFill;
tHyphenFill;
tUnderLineFill;
tNoFill;
{$IFC fUniversalTextTrace}
IF fPrintSecrets THEN
BEGIN
WRITELN('Tab #', i + 1:0, ', tabType =', ORD(tabType):0, ', quad =', ORD(quad):0);
END;
{$ENDC}
END;
{$R+}
SELF.paragraphDescriptor.tabTable.InsLast(@tab);
END;
{$IFC fTrce}EP;{$ENDC}
END;
{$IFC WithUObject}
{$S TKUTInit}
{$ELSEC}
{$S UTInit}
{$ENDC}
BEGIN
{$IFC fTraceUT}
LogCall;
{$IFC fUniversalTextTrace}
fPrintSecrets := FALSE;
{$ENDC}
END;
{$ENDC}
{$IFC WithUObject}
METHODS OF TTKReadUnivText
{$ELSEC}
METHODS OF TReadUnivText
{$ENDC}
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
{$IFC WithUObject}
FUNCTION {TReadUnivText.}CREATE(object: TObject;
itsHeap: THeap;
{$ELSEC}
FUNCTION
itsTString: TString;
itsDataSize: INTEGER;
LevelOfGranularity: TLevelOfGranularity)
: TTKReadUnivText;
{TReadUnivText.}CREATE(object: TUTObject;
itsHeap: THeap;
itsTString: TUTString;
itsDataSize: INTEGER;
LevelOfGranularity: TLevelOfGranularity)
: TReadUnivText;
{$ENDC}
{----------------------------------------------------------------------------------------------------}
VAR index:
TB;
{$IFC WithUObject}
thisList:
TString;
{$ELSEC}
thisList:
TUTString;
{$ENDC}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
{$IFC fTrce}BP(11);{$ENDC}
{ Establish the level of granularity for reading }
WITH secrets.lpd.tyset DO
BEGIN
frce := UTCharacters IN LevelOfGranularity;
frpe := UTparagraphs IN LevelOfGranularity;
fParBnds := FALSE;
END;
GetCSScrap(index);
IF index = 0 THEN
SELF := NIL
ELSE
BEGIN
secrets.streamArrayIndex := index;
IF object = NIL THEN
{$IFC WithUObject}
object := NewObject(itsHeap, THISCLASS);
{$ELSEC}
object := NewUTObject(itsHeap, THISCLASS);
{$ENDC}
{$IFC WithUObject}
SELF := TTKReadUnivText(TTKUnivText.CREATE(object, itsHeap, itsTString, itsDataSize));
{$ELSEC}
SELF := TReadUnivText(TUnivText.CREATE(object, itsHeap, itsTString, itsDataSize));
{$ENDC}
{$IFC WithUObject}
thisList := TString.CREATE(NIL, itsHeap, itsDataSize);
{$ELSEC}
thisList := TUTString.CREATE(NIL, itsHeap, itsDataSize);
{$ENDC}
thisList.StartEdit(50);
{Allow holes}
SELF.buffer := thisList;
SELF.dataBeforeTab := TRUE;
SELF.Restart;
{ Set up for reading from the beginning}
END;
{$IFC fTrce}EP;{$ENDC}
END;
{$IFC fDebugMethods}
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TReadUnivText.}Fields(PROCEDURE Field(nameAndType: S255));
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
SUPERSELF.Fields(Field);
{$IFC WithUObject}
Field('buffer: TString');
{$ELSEC}
Field('buffer: TUTString');
{$ENDC}
Field('');
END;
{$ENDC}
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TReadUnivText.}Free;
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
{$IFC fTrce}BP(11);{$ENDC}
SELF.buffer.Free;
SUPERSELF.Free;
{$IFC fTrce}EP;{$ENDC}
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TReadUnivText.}Restart;
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
{$IFC fTrce}BP(11);{$ENDC}
{ Set up the Achad for reading from the beginning}
WITH secrets.achad DO
BEGIN
ichFst := 0;
ichLim := SELF.data.size;
END;
secrets.lpd.lpLim := 0;
SELF.columnCount := 0;
{$IFC fTrce}EP;{$ENDC}
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TReadUnivText.}ScanTable(VAR rows, tabColumns, tabStopColumns: INTEGER);
{----------------------------------------------------------------------------------------------------}
VAR
fieldOverflow:
BOOLEAN;
fieldTerminator:
CHAR;
lastTerminator:
CHAR;
tabType:
TTabTypes;
columnsInThisRow:
INTEGER;
dataBeforeTab:
BOOLEAN;
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
rows := 0;
tabColumns := 1;
tabStopColumns := 0;
columnsInThisRow := 1;
{There is at least one column}
SELF.dataBeforeTab := TRUE;
{Make shure ReadField doesn't skip any fields}
dataBeforeTab := FALSE;
SELF.Restart;
WHILE SELF.ReadField(1, fieldOverflow, fieldTerminator, tabType) DO
BEGIN
IF columnsInThisRow = 1 THEN
BEGIN
IF SELF.data.size > 0 THEN
dataBeforeTab := TRUE;
IF tabStopColumns < SELF.paragraphDescriptor.tabTable.size THEN
tabStopColumns := SELF.paragraphDescriptor.tabTable.size;
END;
lastTerminatior := fieldTerminator;
IF fieldTerminator = CHR(chCr) THEN
BEGIN
rows := rows + 1;
columnsInThisRow := 1;
{Check the tab table here}
END
ELSE
IF fieldTerminator = CHR(chTab) THEN
BEGIN
columnsInThisRow := columnsInThisRow + 1;
IF columnsInThisRow > tabColumns THEN
tabColumns := columnsInThisRow;
END;
END;
SELF.Restart;
IF (NOT dataBeforeTab) AND (tabColumn > 0) THEN
tabColumns := tabColumns - 1;
SELF.dataBeforeTab := dataBeforeTab;
IF lastTerminatior <> CHR(chCr) THEN
rows := rows + 1;
{$IFC fUniversalTextTrace}
IF fPrintSecrets THEN
BEGIN
WRITELN('ScanTable:');
WRITELN('
dataBeforeTab:
WRITELN('
tabColumns:
WRITELN('
tabStopColumns:
WRITELN('
rows:
END;
{$ENDC}
',
',
',
',
dataBeforeTab);
tabColumns);
tabStopColumns);
rows);
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
FUNCTION {TReadUnivText.}ReadField(
maxFieldSize: INTEGER;
VAR fieldOverflow: BOOLEAN;
VAR fieldTerminator: CHAR;
VAR tabType: TTabTypes)
: BOOLEAN;
{----------------------------------------------------------------------------------------------------}
{$IFC WithUObject}
VAR data:
TString;
buffer:
TString;
{$ELSEC}
VAR data:
TUTString;
buffer:
TUTString;
{$ENDC}
i:
INTEGER;
terminatorFound:
BOOLEAN;
result:
BOOLEAN;
oldSize:
INTEGER;
newSize:
INTEGER;
columnNr:
INTEGER;
tab:
TTabDescriptor;
ch:
CHAR;
PROCEDURE ReadBuffer;
BEGIN
SELF.data := buffer;
SELF.ReadRun;
SELF.data := data;
END;
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
{$IFC fTrce}BP(11);{$ENDC}
REPEAT
buffer := SELF.buffer;
data := SELF.data;
IF buffer.Size = 0 THEN
ReadBuffer;
fieldTerminator := CHR(0);
fieldOverflow := FALSE;
data.DelAll;
terminatorFound := FALSE;
IF buffer.Size > 0 THEN
BEGIN
tabType := qLeftTab;
{ Default tab type }
IF SELF.columnCount > 0 THEN
IF SELF.paragraphDescriptor.tabTable.size >= SELF.columnCount THEN
tabType := TTabDescriptor(
SELF.paragraphDescriptor.tabTable.At(SELF.columnCount)
).tabType;
SELF.columnCount := SELF.columnCount + 1;
columnNr := SELF.columnCount;
result := TRUE;
REPEAT
i := 0;
WHILE (i < buffer.Size) AND (NOT terminatorFound) DO
BEGIN
i := i + 1;
ch := buffer.At(i);
IF (ch = CHR(chTab)) OR (ch = CHR(chCr)) THEN
BEGIN
terminatorFound := TRUE;
fieldTerminator := ch;
IF fieldTerminator = CHR(chCr) THEN
SELF.columnCount := 0;
END;
END;
oldSize := data.Size;
newSize := oldSize + i;
IF terminatorFound THEN
newSize := newSize - 1;
BEGIN
newSize := maxFieldSize;
fieldOverflow := TRUE;
END;
IF newSize > oldSize THEN
data.InsManyAt(1 + data.size, buffer, 1, newSize - oldSize);
buffer.DelManyAt(1, i);
IF (NOT terminatorFound) AND (buffer.Size = 0) THEN
ReadBuffer;
UNTIL terminatorFound OR (buffer.Size = 0);
{$IFC fUniversalTextTrace}
IF fPrintSecrets THEN
BEGIN
WRITELN('Buffer size is ',buffer.Size:1, ' data size is ',data.size:1);
FOR i := 1 to data.size DO
WRITE(data.At(i));
IF fieldTerminator = CHR(chTab) THEN
WRITE('<Tab>')
ELSE
IF fieldTerminator = CHR(chCr) THEN
WRITE('<Cr>')
ELSE
WRITE('<End of paste>');
WRITELN;
WRITELN('FieldOverflow is ', fieldOverflow);
END;
{$ENDC}
END
ELSE
result := FALSE;
UNTIL (NOT result) OR (columnNr > 1) OR SELF.dataBeforeTab;
ReadField := result;
{$IFC fTrce}EP;{$ENDC}
END;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
FUNCTION {TReadUnivText.}ReadLine(
maxLineSize: INTEGER;
lineTerminator := CHR(0);
lineOverflow := FALSE;
data.DelAll;
terminatorFound := FALSE;
IF buffer.Size > 0 THEN
{ If there is still text to paste }
BEGIN
ReadLine := TRUE;
REPEAT
i := 0;
WHILE (i < buffer.size) AND (NOT terminatorFound) DO
BEGIN
i := i + 1;
ch := buffer.At(i);
IF ch = CHR(chCr) THEN
BEGIN
terminatorFound := TRUE;
lineTerminator := ch;
END;
END;
oldSize := data.Size;
newSize := oldSize + i;
IF terminatorFound THEN
newSize := newSize - 1;
{$IFC WithUObject}
{$S TKUTMain}
{$ELSEC}
{$S UTMain}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TReadUnivText.}ReadRun;
{----------------------------------------------------------------------------------------------------}
VAR error: INTEGER;
size:
LONGINT;
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
{$IFC fTrce}BP(11);{$ENDC}
BindUTDSeg(error);
{ Size up the tab and data arrays to take the next run }
SELF.data.DelAll;
SELF.data.EditAt(1, SELF.maxDataSize);
{ Set the achad to receive the next run }
WITH secrets.achad DO
BEGIN
rgch := POINTER(SELF.data.AddrMember(1));
ichFst := 0;
ichLim := SELF.maxDataSize;
END;
WITH secrets DO
REPEAT
{ Get the next run }
IF lpd.lplim = 0 THEN
SetLpd(@Lpd, streamArrayIndex, 0, lpd.Tyset, achad)
ELSE
Seqlpd(@lpd, achad);
UNTIL (NOT lpd.rce^.fvan) OR (achad.ichFst = achad.ichLim);
{$IFC fUniversalTextTrace}
IF fPrintSecrets THEN
PrintSecrets(secrets.achad, secrets.lpd);
{$ENDC}
{ Convert to Run }
SELF.StreamToRun;
WITH secrets.lpd DO
BEGIN
IF tyset.fRpe THEN
{$ELSEC}
{$S UTWrite}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
{$IFC WithUObject}
FUNCTION {TWriteUnivText.}CREATE(object: TObject;
itsHeap: THeap;
itsTString: TString;
itsDataSize: INTEGER)
: TTKWriteUnivText;
{$ELSEC}
FUNCTION {TWriteUnivText.}CREATE(object: TUTObject;
itsHeap: THeap;
itsTString: TUTString;
itsDataSize: INTEGER)
: TWriteUnivText;
{$ENDC}
{----------------------------------------------------------------------------------------------------}
VAR
ptrToolKitUT:
TPtrToolKitUT;
error:
INTEGER;
index:
TB;
{$IFC PasteTrace}
dbgCh:
CHAR;
{$ENDC}
BEGIN
{$IFC PasteTrace}
WRITE('Do you want to debug (Y/N): ');
READ(dbgCh);
fPrintSecrets := dbgCh IN ['Y', 'y'];
{$ENDC}
{$IFC fTraceUT}
LogCall;
{$ENDC}
{$IFC fTrce}BP(11);{$ENDC}
BindUTDseg(error);
IF error <> 0 THEN
ABCBreak('BindUTDseg Error',error);
index := IcsCreate(tycsFld, SIZEOF(ToolKitUT), POINTER(ORD(itsHeap)));
{$R-}
ptrToolKitUT := POINTER( rghcs^[index]^ );
{$R+}
WITH secrets DO
BEGIN
streamArrayIndex := index;
lpd.tyset.fRpe := TRUE;
lpd.tyset.fRce := TRUE;
END;
WITH ptrToolKitUT^ DO
BEGIN
cspd.argproc[IProcSeqLpd] := @SeqLpdUTBB;
cspd.argproc[IProcFreeIcs] := Pointer(procnil);
cspd.argproc[IProcPxHcs] := Pointer(procnil);
cspd.argproc[IProcFindLpFixed] := @FindLpFstPar;
cspd.argproc[IProcFSelLpBounds] := @TrueStdSelLpBounds;
END;
secrets.streamArrayIndex := index;
nOfSavedPara := 0;
dataLp := 0;
PutCsScrap(index, error);
IF error <> 0 THEN
ABCBreak('PutCsScrap Error',error);
freeics(index);
EndGetScrap(error);
IF error <> 0 THEN
ABCBreak('EndGetScrap Error',error);
UnbindUTDseg(error);
IF error <> 0 THEN
ABCBreak('UnbindUTDseg Error',error);
{$IFC fTrce}EP;{$ENDC}
END;
{$IFC WithUObject}
{$S TKUTWrite}
{$ELSEC}
{$S UTWrite}
{$ENDC}
{----------------------------------------------------------------------------------------------------}
PROCEDURE {TWriteUnivText.}FillParagraph;
{----------------------------------------------------------------------------------------------------}
BEGIN
{$IFC fTraceUT}
LogCall;
{$ENDC}
{$IFC fTrce}BP(11);{$ENDC}
{$IFC WithUObject}
ABCBreak('Failed to reimplement TTKWriteUnivText.FillParagraph',0);
{$ELSEC}
ABCBreak('Failed to reimplement TWriteUnivText.FillParagraph',0);
{$ENDC}
{$IFC fTrce}EP;{$ENDC}
END;
{$IFC WithUObject}
{$S TKUTInit}
{$ELSEC}
{$S UTInit}
{$ENDC}
END;
UNIT UFixUText;
{This unit fixes a bug with UText, where pasting universal text containing a 14 Point or
20 Pitch font would crash with a check range error, accessing the uvFont array. The
only access was made in TInsertionPoint.InsertText. To fix the problem we subclass
TInsertionPoint.InsertText, but install a pointer to the revised method in TInsertionPoint's
method table.}
{$SETC CalcNumbers := FALSE}
{$SETC Debug := FALSE}
INTERFACE
{$E ERRORS}
{$E+}
USES
{$U
{$U
{$U
{$U
{$U
{$U
{$U
LIBPL/UCLASCAL}
UObject}
QuickDraw}
UDraw}
UABC}
UUnivText}
UText}
UClascal,
UObject,
QuickDraw,
UDraw,
UABC,
UTKUniversalText,
UText;
TYPE
TFixInsertionPoint = SUBCLASS OF TInsertionPoint
FUNCTION
{$D-}
{$ENDC}
{$IFC fDbgOK AND Debug}
{$R+}
{$ELSEC}
{$R-}
{$ENDC}
VAR uvFont:
cFixInsertionPoint:
ARRAY[1..19] OF TFontRecord;
TClass;
{$S FixText1}
{Caller and HackMethodTable must be in the same segment}
{$IFC CalcNumbers}
PROCEDURE Caller;
VAR ip:
TInsertionPoint;
t:
TText;
BEGIN
ip.InsertText(t, TRUE, TRUE, TRUE);
END;
{$ENDC}
PROCEDURE HackMethodTables;
{$IFC CalcNumbers AND DEBUG}
LABEL
1,100;
{$ELSEC}
{$IFC CalcNumbers}
LABEL
100;
{$ENDC}
{$IFC Debug}
LABEL
1;
{$ENDC}
{$ENDC}
{$IFC NOT CalcNumbers}
CONST
levNum
=
methNum
=
{$ENDC}
6;
2;
TYPE
TMethodArray = ARRAY [1..256] OF LONGINT;
TPMethodArray = ^TMethodArray;
TSliceTable = ARRAY [0..255] OF TPMethodArray;
TPSliceTable = ^TSliceTable;
VAR myProc:
LONGINT;
{$IFC CalcNumbers}
pc:
TpInteger;
wd:
INTEGER;
levNum:
INTEGER;
methNum:
INTEGER;
{$ENDC}
pSliceTable:
TpSliceTable;
BEGIN
{$IFC Debug}
1: GOTO 1;
{$ENDC}
{$IFC CalcNumbers}
{Find out the method # & level # for TInsertionPoint.InsertText}
pc := TpInteger(@Caller);
WHILE ORD(pc) <= ORD(@HackMethodTables) DO
BEGIN
wd := pc^;
pc := TpInteger(ORD(pc)+2);
IF wd = $4E95 THEN {JSR (A5)}
BEGIN
wd := pc^;
{get level/method # as an integer}
levNum := wd DIV 256;
{these 2 statements only work for <128 levels}
methNum := wd MOD 256;
{$IFC Debug}
WriteLn(levNum, methNum); {***}
{$ENDC}
GOTO 100;
END;
END;
HALT;
{did not find the method call}
100:
{$ENDC}
pSliceTable := TpSliceTable(cFixInsertionPoint);
myProc := pSliceTable^[levNum]^[methNum];
{The superclass pointers have not been installed yet, so need to use the arrays in UClascal.}
pSliceTable := TpSliceTable(pSTables^[pClasses^[numClasses].superIndex]);
pSliceTable^[levNum]^[methNum] := myProc;
END;
METHODS OF TFixInsertionPoint;
{$S FixText2}
univPara.Free;
readUnivText.Free;
{$ENDC}
END;
{$IFC fTrace}EP;{$ENDC}
END;
FUNCTION GetParagraph(VAR paragraph: TEditPara): BOOLEAN;
VAR currPos:
INTEGER;
done:
BOOLEAN;
runSize:
INTEGER;
wasSomeText:
BOOLEAN;
ch:
CHAR;
typeStyle:
TTypeStyle;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
If universalText THEN
BEGIN
{$IFC fUseUnivText}
univPara.ReplPString(0, univPara.Size, NIL);
currPos := 0;
wasSomeText := FALSE;
done := FALSE;
REPEAT
readUnivText.ReadRun;
runSize := readUnivText.data.size;
IF runSize > 0 THEN
BEGIN
IF NOT wasSomeText THEN
BEGIN
WITH univFormat, readUnivText.paragraphDescriptor DO
BEGIN
firstIndent := firstLineMargin;
leftIndent := bodyMargin;
(* Can't use this because it's given as distance from left rather than
indent from right and I don't know what value of right edge of paper is.
rightIndent := rightMargin;
*)
spaceBelowPara := paraLeading;
END;
univPara.format := univFormat;
END;
wasSomeText := TRUE;
ch := readUnivText.data.At(runSize);
IF ORD(ch) = ascReturn THEN
BEGIN
readUnivText.data.DelAt(runSize);
runSize := runSize - 1;
numParas := numParas + 1;
done := TRUE;
END;
univPara.ReplTString(currPos, 0, readUnivText.data, 0, runSize);
typeStyle.onFaces := readUnivText.characterDescriptor.face;
typeStyle.font.fontFamily := uvFont[readUnivText.characterDescriptor.font].fontFamily;
typeStyle.font.fontSize := uvFont[readUnivText.characterDescriptor.font].fontSize;
univPara.NewStyle(currPos, currPos+runSize, typeStyle);
currPos := currPos + runSize;
END
ELSE
BEGIN
IF wasSomeText THEN
numParas := numParas + 1;
done := TRUE;
END;
UNTIL done;
IF wasSomeText THEN
paragraph := univPara
ELSE
paragraph := NIL;
GetParagraph := wasSomeText;
{$ELSEC}
paragraph := NIL;
GetParagraph := FALSE;
{$ENDC}
END
ELSE
GetParagraph := s.Scan(paragraph);
{$IFC fTrace}EP;{$ENDC}
END;
PROCEDURE InsText;
BEGIN
{$IFC fTrace}BP(10);{$ENDC}
delta := 0;
textImage := SELF.textImage;
newLP := SELF.textRange.firstLP;
newPara := SELF.textRange.firstPara;
prevPara := newPara;
insertIt := FALSE;
IF isWordSelection THEN
BEGIN
needSpRight := newPara.Qualifies(newLP);
IF newPara.Qualifies(newLP-1) THEN
BEGIN
newPara.InsertOneChar(' ', newLP);
newLP := newLP + 1;
delta := 1;
END;
END;
(*
*)
{special case: if first paragraph in text is designated a whole paragraph (by isParaSelection) AND
if the insertion point (SELF) is at the end of the paragraph then we want to make a new
paragraph rather than append it to the current paragraph and consequently set the flag that
was supposed to prevent the first paragraph from being inserted}
IF isParaSelection AND (prevPara.size = newLP) THEN
BEGIN
newPara := textImage.NewEditPara(0, prevPara.format);
newLP := 0;
insertIt := TRUE;
END;
done := FALSE;
StartPaste;
IF GetParagraph(aParagraph) THEN
BEGIN
delta := delta + aParagraph.size;
REPEAT
newPara.ReplPara(newLP, 0, aParagraph, 0, aParagraph.size);
newLP := newLP + aParagraph.size;
IF insertIt THEN
textImage.text.InsParaAfter(prevPara, newPara);
insertIt := TRUE;
prevPara := newPara;
IF GetParagraph(aParagraph) THEN
BEGIN
newPara := textImage.NewEditPara(prevPara.size-newLP,
TParaFormat(aParagraph.format.Clone(SELF.Heap)));
{For now, so we don't get garbage (if aParagraph later deleted), put cloned
format on to styleSheet list}
SELF.textImage.text.styleSheet.formats.InsLast(newPara.format);
newPara.StartEdit(newPara.GrowSize);
newPara.ReplPara(0, 0, prevPara, newLp, prevPara.size - newLp);
prevPara.ReplPString(newLp, prevPara.size-newLP, NIL);
prevPara.StopEdit;
newLP := 0;
END
ELSE
done := TRUE;
UNTIL done;
END;
IF isParaSelection THEN
BEGIN
{$IFC fTrace}EP;{$ENDC}
END;
{$S FixText1}
BEGIN
cFixInsertionPoint := THISCLASS;
HackMethodTables;
uvFont[4].fontFamily := famModern;
uvFont[5].fontFamily := famModern;
uvFont[6].fontFamily := famModern;
uvFont[7].fontFamily := famModern;
uvFont[8].fontFamily := famModern;
uvFont[9].fontFamily := famModern;
uvFont[10].fontFamily := famClassic;
uvFont[11].fontFamily := famClassic;
uvFont[12].fontFamily := famClassic;
uvFont[13].fontFamily := famClassic;
uvFont[14].fontFamily := famClassic;
uvFont[15].fontFamily := famModern;
uvFont[16].fontFamily := famClassic;
uvFont[19].fontFamily := famModern;
uvFont[4].fontSize := 5;
uvFont[5].fontSize := 7;
uvFont[6].fontSize := 8;
uvFont[7].fontSize := 2;
uvFont[8].fontSize := 3;
uvFont[9].fontSize := 4;
uvFont[10].fontSize := 5;
uvFont[11].fontSize := 7;
uvFont[12].fontSize := 8;
uvFont[13].fontSize := 3;
uvFont[14].fontSize := 6;
uvFont[15].fontSize := 6;
uvFont[16].fontSize := 6;
uvFont[19].fontSize := 1;
END;
{added}
{added}
{added}
{added}
{added}
{added}
END.