boot3/Toolbox/CommToolbox/CommToolboxUtilities/DITL.p
Elliot Nunn 5b0f0cc134 Bring in CubeE sources
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included.

The Tools directory, containing mostly junk, is also excluded.
2017-12-26 10:02:57 +08:00

634 lines
20 KiB
OpenEdge ABL

{
File: DITL.p
Contains: DITL Management unit
Written by: Byron Han
Copyright: © 1987-1990 by Apple Computer, Inc., all rights reserved.
This file is used in these builds: BigBang
Change History (most recent first):
<7> 12/13/90 kaz Stuff the new rect before appending resCtrls. <jng>
<6> 5/9/90 kaz Adjusted the rects of resCtrl items on Append
<5> 3/29/90 BBH fix handling of resControl's (was using uninitialized control ID
variable)
<4> 3/22/90 BBH Implement (latest) Help interface stuff thrashed out with Randy
(new constant HMScanAppendhdlg with the hdlg ID and the dialog
item list offset stored in the ditl itself)
<3> 3/21/90 BBH Take out SetClip's
Use WITH where possible
Use ShowDItem/HideDItem to handle text edit item
appending/removal
<2> 3/15/90 BBH renamed some routines
<1> 3/14/90 BBH first checked in
To Do:
Pre-BBS History
1/30/90 BBH Changed handling of helpitems to reflect reality.
8/22/89 BBH In the Save/Restore of the control template rectangle, we assumed
that GetNewControl does not release the CNTL resource.
This is, unfortunately, only true on the Mac II. On SE and Plus
the CNTL resource is released by the control manager.
8/21/89 BBH Eliminate call to ReleaseResource when handling resControl's
8/19/89 BBH In fixing things, forgot to lock down theNewDITL when appending
to end of old one....
Revised handling of resource controls to truly allow use of cctb's
in resource controls.
Also there was a screw up in the handling of the rectangles for
resource controls which is now fixed. The strategy is the
load the CNTL template and offset the template rectangle
appropriately. Then after control creation via GetNewControl
(which automagically handles cctb's), the control is moved
to the topLeft of the itemRect (as per dmgr.a)
8/18/89 BBH Changed BitOr to BOR's
Use WITH's statements
In processing helpItem, we now stuff helpInvalidID into the
ID field of the dialog item list if we are unable to load the
hdlg resource.
Added error recovery from failing to append the new item list
to the old item list.
Moved calls to InvalRect in Append outside of CASE structure
to cut down on codesize.
Changed constants 5, 3, 8192 to named constants
8/7/89 BBH Added balloon help support per conversations with Randy Carr
'hdlg' resource has first two bytes version, second two being
the item number (0 based) of the first dialog item managed by the
'hdlg' resource.
Renamed some data structure elements to be clearer and renamed
some local variables to be clearer.
8/4/89 BBH Removed "fix" to resControl handling. Now explicitly read in the
CNTL template and handle it manually.
8/2/89 BBH Added support for HelpItems ?
Handle resControl items with call to GetNewControl instead of
manually ditling with the CNTL template (no pun intended)
7/28/89 MPR Added support for color icons
4/25/89 BBH Changed BitAnd to BANDs
Added some memory error checking
4/9/89 BBH Added sanity check to AppendDITL to see if theDITL is NIL.
Added sanity check to ShortenDITL to see if numberItems is <= 0
}
UNIT DITL;
INTERFACE
USES
MemTypes,
QuickDraw,
OSIntf,
ToolIntf,
PackIntf,
AppleTalk,
CTBUtilities,
CommToolboxPriv;
FUNCTION DITLEntry(theDialog: DialogPtr; theDITL: Handle; method: INTEGER;
numberItems: INTEGER; msg: INTEGER): LONGINT;
IMPLEMENTATION
CONST
{ INTERNAL CONSTANTS }
dialogSlop = 5; { after growing dialog, this is whitespace at bottom/right }
teSlop = 3; { slop around text edit boxes }
hiddenThreshold = 8192;
low7Bits = $0000007F;
buttonMask = $03; { to get var code for buttons }
growNothing = 0;
growRight = 1; { internal msgs for dialgo growing }
growBottom = 2; { to the right or to the bottom }
{ new item types to be included someday with Dialogs.p }
helpItem = 1;
reservedItem = 2;
{ more help stuff }
helpResource = 'hdlg';
helpInvalidID = -1;
HMScanAppendhdlg = 8;
TYPE
{ DITL data structures }
IntPtr = ^INTEGER;
IntHandle = ^IntPtr;
hHelpItem = ^pHelpItem; { per discussions with Randy Carr }
pHelpItem = ^rHelpItem;
rHelpItem = RECORD
hVersion : INTEGER;
hFirstItem : INTEGER;
hItemData : ARRAY[0..0] OF SignedByte;
END;
hDITLItem = ^pDITLItem;
pDITLItem = ^DITLItem;
DITLItem = RECORD
dItemHandle : Handle;
dItemRect : Rect;
dItemType : SignedByte;
dItemData : Array[0..0] OF SignedByte;
END;
hItemList = ^pItemList;
pItemList = ^ItemList;
ItemList = RECORD
iNumberItems: INTEGER;
iDITLItems : ARRAY[0..0] OF DITLItem;
END;
{ forward declaration of routines }
{ These routines are the externally visible routines which are accessed via the
single entry point and selector }
PROCEDURE DoAppendDITL( theDialog:DialogPtr; theDITL:Handle; method:INTEGER); FORWARD;
FUNCTION DoCountDITL( theDialog:DialogPtr ) : INTEGER; FORWARD;
PROCEDURE DoShortenDITL( theDialog:DialogPtr; numberItems:INTEGER); FORWARD;
{ utility routines }
FUNCTION IsCGrafPort(theCPort: CGrafPtr): BOOLEAN; FORWARD;
FUNCTION GetFirstTEItem(theDialog: DialogPtr) : INTEGER; FORWARD;
FUNCTION GetUSB(a : SignedByte) : INTEGER; FORWARD;
FUNCTION EvenInt(a : INTEGER) : INTEGER; FORWARD;
{ Main Entry Point }
{------------------------------------------------------------------------------------------}
FUNCTION DITLEntry(theDialog: DialogPtr; theDITL: Handle; method: INTEGER;
numberItems: INTEGER; msg: INTEGER): LONGINT;
BEGIN
DITLEntry := 0;
CASE msg OF
AppendMSG:
DoAppendDITL(theDialog, theDITL, method);
CountMSG:
DITLEntry := DoCountDITL(theDialog);
ShortenMSG:
DoShortenDITL(theDialog, numberItems);
OTHERWISE
DITLEntry := -1; { out of range }
END; {case}
END;
PROCEDURE DoAppendDITL( theDialog:DialogPtr; theDITL:Handle; method:INTEGER);
VAR
offset : Point; { offset each appended item from this }
theDialogRect : Rect; { dialog original portRect }
theNewDITL : hItemList; { to append (should be detached from rsrc map) }
theOldDITL : hItemList; { the current DITL }
theType : INTEGER; { type of item being worked on }
firstItem : INTEGER; { item number of first appended item (1 based) }
newItems : INTEGER; { number of new items to append }
dataSize : LONGINT; { size of data associated with item }
theCurrentItem : pDITLItem; { current item in appended list being processed }
i : INTEGER; { a counter }
err : OSErr; { fuckup notifier }
firstTEItem : INTEGER; { first TE item. need to special case adding }
{ a TE item where none were before }
theID : INTEGER; { ID for creating control }
theIDPtr : IntPtr;
theHelpHandle : hHelpItem; { for 'hdlg' resource }
myItemKind : INTEGER; { itemKind }
myItemHandle : Handle; { itemBox }
myItemBox : Rect; { itemBox }
expanded : INTEGER; { expanded right or bottom? }
tempRect : Rect; { place holder }
savedPort : GrafPtr; { saved port }
BEGIN
IF theDITL = NIL THEN
Exit(DoAppendDITL); { abort abort abort }
GetPort(savedPort); { sanity }
SetPort(theDialog);
HidePen;
theDialogRect := theDialog^.portRect; { current dialog portRect }
expanded := growNothing; { did not grow rectangle }
IF method < 0 THEN { relative to topLeft of item |method| }
BEGIN
GetDItem(theDialog, -method, myItemKind, myItemHandle, myItemBox);
offset := myItemBox.topLeft;
END
ELSE
BEGIN
offset := theDialog^.portRect.topLeft; { append rel to topLeft }
CASE method OF
appendDITLRight:
offset.h := theDialogRect.right; { relative to topRight of portRect }
appendDITLBottom:
offset.v := theDialogRect.bottom; { relative to botLeft of portRect }
END; {case}
END;
theOldDITL := hItemList( DialogPeek(theDialog)^.items ); { current item list }
theNewDITL := hItemList(theDITL); { list to be appended }
firstItem := theOldDITL^^.iNumberItems + 2; { item # of first appended item }
newItems := theNewDITL^^.iNumberItems + 1; { # items to append }
{ this are 1 based }
firstTEItem := GetFirstTEItem(theDialog); { first TE item in old list }
{ this is 1 based }
HLock(Handle(theNewDITL)); { lock new list }
theCurrentItem := @theNewDITL^^.iDITLItems; { go through items in new list }
FOR i := 1 TO newItems DO
BEGIN { loop de loop }
WITH theCurrentItem^ DO
BEGIN
myItemBox := dItemRect; { get item rectangle }
OffsetRect(myItemBox, offset.h, offset.v); { move it }
InvalRect(myItemBox); { Invalidate the rectangle }
theType := BAND(dItemType, low7Bits); { what kind of item is it }
dataSize := GetUSB(dItemData[0]); { and how big is the data }
dItemHandle := NIL; { pessimism }
CASE theType OF
helpItem:
BEGIN
theID := IntPtr(@dItemData[1])^; { get the help item type }
IF theID = HMScanAppendhdlg THEN
BEGIN
theIDPtr := IntPtr(@dItemData[5]); { stuff offset into ditl }
theIDPtr^ := firstItem - 1; { stuff invalid ID marker }
END;
END;
ctrlItem + btnCtrl,
ctrlItem + chkCtrl,
ctrlItem + radCtrl:
BEGIN
dItemHandle :=
Handle(NewControl(theDialog,
myItemBox,
StringPtr(@dItemData[0])^,
TRUE, { visible, val, min, max }
0, 0, 1, { procID, refCon }
BAND(theType, buttonMask), 0));
{ We get the new contrlRect 'cuz NewControl may have changed the contrlRect }
IF dItemHandle <> NIL THEN
BEGIN
myItemBox := ControlHandle(dItemHandle)^^.contrlRect;
InvalRect(myItemBox); { invalidate it since we are not }
END;
END;
ctrlItem + resCtrl:
BEGIN
{ We stuff the new rect in the CNTL resource before NewControl }
{ so that the control won't get confused about drawing/erasing }
{ in the old location }
dItemHandle := GetResource('CNTL', IntPtr(@dItemData[1])^);
IF (dItemHandle <> NIL) THEN
BlockMove(@myItemBox,Ptr(dItemHandle^),SIZEOF(Rect));
dItemHandle := Handle(GetNewControl(IntPtr(@dItemData[1])^, theDialog));
IF dItemHandle <> NIL THEN
BEGIN
myItemBox := ControlHandle(dItemHandle)^^.contrlRect;
InvalRect(myItemBox); { didn't really draw it so... }
END;
END;
statText: { static text item }
err := PtrToHand(@dItemData[1], dItemHandle, dataSize); { copy data }
editText: { yummy. a text edit item }
BEGIN
err := PtrToHand(@dItemData[1], dItemHandle, dataSize); { copy data }
InsetRect(myItemBox, -teSlop, -teSlop);
{ expand to take care of outline }
InvalRect(myItemBox); { box. so inval it }
InsetRect(myItemBox, teSlop, teSlop);
END;
iconItem: { an icon! }
BEGIN
IF IsCGrafPort(CGrafPtr(theDialog)) THEN{ check for a color dialog }
dItemHandle := Handle(GetCIcon(IntPtr(@dItemData[1])^));
{ try for a cicn }
IF dItemHandle = NIL THEN { nope, get BW }
dItemHandle := GetIcon(IntPtr(@dItemData[1])^); { load the icon }
END;
picItem: { a picture (of vanna white) }
dItemHandle := Handle(GetPicture((IntPtr(@dItemData[1])^)));
END; {case}
dItemRect := myItemBox; { in case itemBox changed }
END; {with theCurrentItem}
UnionRect(myItemBox, theDialogRect, tempRect); { do we need to grow dlog rect? }
IF tempRect.right > theDialogRect.right THEN { grown to the right }
expanded := BOR(expanded, growRight); { set right grow bit }
IF tempRect.bottom > theDialogRect.bottom THEN { grown to the bottom }
expanded := BOR(expanded, growBottom); { set bottom grow bit }
theDialogRect := tempRect; { set dlog rect to grown rect }
dataSize := EvenInt(dataSize); { item data is padded to even len }
theCurrentItem := pDITLItem(Ptr(ORD4(@theCurrentItem^) + dataSize + sizeof(DITLItem)));
{ move to next item }
END; {for i}
HUnlock(Handle(theNewDITL));
{ append new list to old }
HLock(Handle(theNewDITL));
theCurrentItem := @theNewDITL^^.iDITLItems;
err := PtrAndHand(Ptr(theCurrentItem), { -2 is to skip numItems field }
Handle(theOldDITL),
GetHandleSize(Handle(theNewDITL)) -2);
HUnlock(Handle(theNewDITL));
IF err <> noErr THEN { cannot add items to DITL }
BEGIN
{ cleanup handles and/or resources allocated }
HLock(Handle(theNewDITL)); { lock new list }
theCurrentItem := @theNewDITL^^.iDITLItems; { go thru items in new list }
FOR i := 1 TO newItems DO
BEGIN { loop de loop }
WITH theCurrentItem^ DO
BEGIN
theType := BAND(dItemType, low7Bits); { what kind of item is it }
dataSize := EvenInt(GetUSB(dItemData[0]));
{ and how big is the data }
IF dItemHandle <> NIL THEN
BEGIN
CASE theType OF
ctrlItem + btnCtrl, { dispose of it }
ctrlItem + chkCtrl,
ctrlItem + radCtrl,
ctrlItem + resCtrl :
DisposeControl( ControlHandle(dItemHandle) );
statText, { static text item }
editText:
DisposHandle(dItemHandle);
iconItem, { an icon! }
picItem: { a picture (of vanna white) }
ReleaseResource(dItemHandle);
END; {case}
END;
dItemHandle := NIL;
END; {with theCurrentItem}
theCurrentItem := pDITLItem(Ptr(ORD4(@theCurrentItem^) + dataSize + sizeof(DITLItem)));
END; {for}
HUnlock(Handle(theNewDITL));
{ now cleanup local variables that indicate state of appending operation }
newItems := 0; { no new items }
expanded := growNothing; { no growing of the dialog }
theDialogRect := theDialog^.portRect; { mark no size change of dialog }
END; {if err <> noErr}
WITH theOldDITL^^ DO
iNumberItems := iNumberItems + newItems; { add itemCount }
IF BAND(expanded, growBottom) = growBottom THEN { add an extra 5 if growing }
theDialogRect.bottom := theDialogRect.bottom + dialogSlop;
IF BAND(expanded, growRight) = growRight THEN { add an extra 5 if growing }
theDialogRect.right := theDialogRect.right + dialogSlop;
{ only redraw the rectangle if size has changed }
IF NOT EqualPt(theDialogRect.botRight, theDialog^.portRect.botRight) THEN
SizeWindow(theDialog, theDialogRect.right, theDialogRect.bottom, FALSE);
{ resize the window if needed }
IF firstTEItem = 0 THEN { no TE items beforeÉ }
BEGIN
firstTEItem := GetFirstTEItem(theDialog); { got one now? }
IF firstTEItem > 0 THEN
BEGIN
HideDItem(theDialog, firstTEItem); { select it please }
ShowDItem(theDialog, firstTEItem);
SelIText(theDialog, firstTEItem, 0, 32767);
END;
END;
ShowPen;
SetPort(savedPort);
END;
{ returns the number of dialog items in the dialog item list }
{ this is 1 based }
FUNCTION DoCountDITL( theDialog:DialogPtr) : INTEGER;
BEGIN
DoCountDITL := 0;
IF theDialog <> NIL THEN
DoCountDITL := IntHandle(DialogPeek(theDialog)^.items)^^ + 1;
END;
PROCEDURE DoShortenDITL( theDialog:DialogPtr; numberItems:INTEGER);
{
removes "number of items" from end of DITL.
need to remember that if we have a editText item in the area being deleted,
we must be sure that we are not in it. if we are, we need to make sure
we move the current text edit item to one that is available. it there are
none, we need to set editField to -1
}
VAR
theOldDITL : hItemList;
lastItem : INTEGER;
lastSavedItem : INTEGER;
dataSize : LONGINT;
theCurrentItem : pDITLItem;
i : INTEGER;
newDITLSize : LONGINT;
tempKind : INTEGER;
tempRect : Rect;
tempHandle : Handle;
theState1 :INTEGER;
savedPort : GrafPtr;
killCurrent : BOOLEAN; { are we disposing of the current TE item }
itemKind: INTEGER;
itemHandle: Handle;
itemRect: Rect;
changeIt: BOOLEAN;
BEGIN
IF numberItems <= 0 THEN
Exit(DoShortenDITL); { abort abort abort }
GetPort(savedPort); { sanity }
SetPort(theDialog);
theOldDITL := hItemList( DialogPeek(theDialog)^.items ); { the current item list }
newDITLSize := 2; { how many bytes to keep in item list }
lastItem := theOldDITL^^.iNumberItems + 1; { last item in DITL (1 based) }
lastSavedItem := lastItem - numberItems; { itemNumber of last to save (1 base) }
killCurrent := (DialogPeek(theDialog)^.editField+1 > lastSavedItem);
FOR i := lastSavedItem + 1 TO lastItem DO
BEGIN
GetDItem(theDialog, i, itemKind, itemHandle, itemRect);
itemKind := BAND(BNOT(itemDisable), itemKind); { clear disable bit }
IF itemKind = editText THEN
InsetRect(itemRect, -teSlop, -teSlop);
EraseRect(itemRect);
InvalRect(itemRect);
IF itemKind = editText THEN
HideDItem(theDialog, i);
IF itemHandle <> NIL THEN
BEGIN
changeIt := TRUE;
CASE itemKind OF
statText,
editText:
DisposHandle( itemHandle );
ctrlItem + btnCtrl, { a control, eh? }
ctrlItem + chkCtrl,
ctrlItem + radCtrl,
ctrlItem + resCtrl : { a resource control, eh? }
DisposeControl( ControlHandle(itemHandle) );
iconItem,
picItem:
ReleaseResource(itemHandle);
OTHERWISE
changeIt := FALSE;
END; {case}
IF changeIt THEN
SetDItem(theDialog, i, userItem, NIL, itemRect);
END; {if itemHandle <> NIL }
END;
theState1 := HGetState(Handle(theOldDITL)); { get state of DITL }
HLock(Handle(theOldDITL)); { lock it down }
theCurrentItem := @theOldDITL^^.iDITLItems; { the current item to look at }
FOR i := 1 TO lastSavedItem DO { and a 1, and a 2, and a 3, 4, 5, 6 }
BEGIN
dataSize := EvenInt(GetUSB(theCurrentItem^.dItemData[0]));
newDITLSize := newDITLSize + dataSize + sizeof(DITLItem); { yup }
theCurrentItem := pDITLItem(Ptr(ORD4(@theCurrentItem^) + dataSize + sizeof(DITLItem)));
END; {for }
SetHandleSize(Handle(theOldDITL), newDITLSize); { reduce datasize of DITL }
WITH theOldDITL^^ DO
iNumberItems := iNumberItems - numberItems; { reduce # items in DITL }
HSetState(Handle(theOldDITL), theState1); { restore state of DITL }
IF killCurrent THEN
BEGIN
i := DialogPeek(theDialog)^.editField+1;
IF i > 0 THEN
SelIText(theDialog, i, 0, 32767);
END;
SetPort(savedPort); { go on home }
END;
{ This function takes a grafPtr and returns TRUE if it is a color grafPort }
FUNCTION IsCGrafPort(theCPort: CGrafPtr): BOOLEAN;
BEGIN
IsCGrafPort := (BAND(theCPort^.portVersion, $0000C000) = $0000C000);
END;
{
This is a utility routine which returns the item number (1 based) of the
first text edit item in the dialog item list, 0 if none is found
}
FUNCTION GetFirstTEItem(theDialog: DialogPtr) : INTEGER;
VAR
theOldDITL : hItemList;
lastItem : INTEGER;
dataSize : LONGINT;
theCurrentItem : pDITLItem;
i : INTEGER;
theType : INTEGER;
firstTEItem : INTEGER;
BEGIN
theOldDITL := hItemList( DialogPeek(theDialog)^.items );
WITH theOldDITL^^ DO
BEGIN
lastItem := iNumberItems;
theCurrentItem := @iDITLItems;
END;
GetFirstTEItem := 0;
FOR i := 0 TO lastItem DO
BEGIN
WITH theCurrentItem^ DO
BEGIN
theType := BAND(dItemType, low7Bits);
dataSize := EvenInt(GetUSB(dItemData[0]));
IF theType = editText THEN
IF dItemRect.left < hiddenThreshold THEN { hidden? }
BEGIN
GetFirstTEItem := i+1; { return 1 based value }
Exit(GetFirstTEItem); { exit please }
END;
END;
theCurrentItem := pDITLItem(Ptr(ORD4(@theCurrentItem^) + dataSize + sizeof(DITLItem)));
END; {for }
END; {function}
{ this function casts a Signed Byte into an integer }
FUNCTION GetUSB(a : SignedByte) : INTEGER; { cast signed byte into unsigned byte }
BEGIN
GetUSB := BAND($000000FF, a);
END;
{ this function evens out an integer (rounding up) }
FUNCTION EvenInt(a : INTEGER) : INTEGER;
BEGIN
EvenInt := BAND(a+1, $FFFFFFFE);
END;
END.