Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Posting-Version: version B 2.10 5/3/83; site k.cs.cmu.edu Path: utzoo!watmath!clyde!burl!ulysses!mhuxr!mhuxn!ihnp4!qantel!lll-crg!seismo!rochester!pt.cs.cmu.edu!k.cs.cmu.edu!tim From: tim@k.cs.cmu.edu (Tim Maroney) Newsgroups: net.sources.mac Subject: Macintosh Internet Protocols (9 of 12) ("Multi-File Get" Dialog) Message-ID: <670@k.cs.cmu.edu> Date: Tue, 26-Nov-85 06:01:35 EST Article-I.D.: k.670 Posted: Tue Nov 26 06:01:35 1985 Date-Received: Fri, 29-Nov-85 09:20:36 EST Organization: Carnegie-Mellon University, Networking Lines: 1775 echo extracting sfmget/make.text... cat >sfmget/make.text <<'!E!O!F!' $EXEC $SUBMIT t-assemble(sfmget-sfmget_asm) $SUBMIT t-depend(sfmget-sfmgetfile,sfmget-sfmget_asm) $SUBMIT t-assemble(sfmget-sfmintf_asm) $SUBMIT t-depend(sfmget-sfmintf) $SUBMIT t-depend(sfmget-sfmtest,sfmget-sfmintf,sfmget-sfmintf_asm) $IF NEWER("sfmget-sfmtestr.text","sfmget-sfmtestr.rsrc") THEN r{un}bin-RMaker sfmget-sfmtestr $ENDIF $IF NEWER("sfmget-sfmgetr.text","sfmget-sfmgetr.rsrc") THEN r{un}bin-RMaker sfmget-sfmgetr $ENDIF $IF NEWER("sfmget-sfmgetfile.obj","sfmget-sfmgetfileL.obj") THEN L{ink}? +X +R sfmhdr {partial link} { no more options} sfmget-sfmget_asm sfmget-sfmgetfile obj-quickdraw obj-tooltraps obj-ostraps obj-prlink obj-packtraps obj-rtlib obj-pasinit obj-paslibasm obj-paslib {no more object files} sfmget-sfmgetfileL.OBJ $ENDIF $IF NEWER("sfmget-sfmtest.obj","sfmget-sfmtestL.obj") THEN L{ink}? +X { no more options} sfmget-sfmtest obj-quickdraw obj-tooltraps obj-ostraps obj-prlink obj-packtraps obj-rtlib obj-pasinit obj-paslibasm obj-paslib obj-writelnwindow sfmget-sfmintf sfmget-sfmintf_asm {no more object files} {list on console} sfmget-sfmtestL.OBJ { output file is progL.OBJ } $ENDIF R{un}bin-rmaker { convert linked file to CODE resource file } sfmget-sfmtesto $ R{un}RFB { Resource file builder } sfmget-sfmtest.rsrc { output file } sfmget-sfmtestr.rsrc { compiled resource file } * sfmget-sfmgetr.rsrc * sfmget-sfmtesto.rsrc { CODE resource file } * { no more input files } { quit } R{un}bin-MacCom { write the disk } RYFYLsfmget-sfmtest.RSRC sfmtest APPL { set type to APPL } { set creator to ???? } Y{es, bundle bit}E{ject}Q{uit} $DOIT $ENDEXEC !E!O!F! # # echo extracting sfmget/sfmget_asm.tex... cat >sfmget/sfmget_asm.tex <<'!E!O!F!' ; header for Multiple File Get SOFT resource .PROC sfmhdr .REF GetFList,DelFList,SFMGetFile,CompFList,SortFList jmp GetFList ; 0 jmp DelFList ; 4 jmp SFMGetFile ; 8 jmp CompFList ; 12 jmp SortFList ; 16 .PROC CallBool MOVE.L 4(SP),A0 ; Copy the procedure pointer MOVE.L (SP)+,(SP) ; Move the return address down JMP (A0) ; Jump to the real routine .END !E!O!F! # # echo extracting sfmget/sfmgetfile.tex... cat >sfmget/sfmgetfile.tex <<'!E!O!F!' {$X-} {$U-} {$R-} {$D-} Unit SFMGet; INTERFACE {$L-} USES {$U Obj-Memtypes } MemTypes, {$U Obj-QuickDraw } QuickDraw, {$U Obj-OSIntf } OSIntf, {$U Obj-ToolIntf } ToolIntf, {$U Obj-PackIntf } PackIntf; {$L+} Type StrCell = Record str: StringHandle; selected: Boolean; end; StrList = Record howmany: Integer; volume: Integer; vname: String[27]; { change vn_offset if this changes place } table: Array [0..0] of StrCell; end; StrLPtr = ^StrList; StrLHandle = ^StrLPtr; FUNCTION GetFList(vref:Integer; numTypes:Integer; typeList:SFTypeList; fileFilter: ProcPtr):StrLHandle; PROCEDURE DelFList(h:StrLHandle); FUNCTION SFMGetFile(where: Point; fileFilter: ProcPtr; numTypes:Integer; typeList:SFTypeList; dlgHook:ProcPtr; flags:Integer): StrLHandle; PROCEDURE CompFList(h:StrLHandle); PROCEDURE SortFList(h:StrLHandle); CONST { constants to be OR'ed into flags word } SFMmulti = 1; SFMenable = 2; SFMstart = 4; IMPLEMENTATION CONST GrayLine = 9; VolName = 4; getHScroll = 11; getMChk = 12; shiftList = 255; IncHoriz = 8; DlogResID = -4001; {resource for the dialog} DefVCBPtr = $352; {address of default volume control block pointer} SFSaveDisk = $214; {SF package global: last colume seen} vn_offset = 4; Type DrvElPtr = ^DrvQEl; VCBPtr = ^VCB; VCBHdl = ^VCBPtr; IntPtr = ^Integer; DlogRef = RECORD VBar: ControlHandle; HBar: ControlHandle; List: StrLHandle; DrvPtr: DrvElPtr; filter: ProcPtr; oldVert:Integer; oldHoriz:Integer; Rows: Integer; tnum: Integer; tlist: SFTypeList; tlist2: SFTypeList; tlist3: SFTypeList; tlist4: SFTypeList; { if ya want more'n 16 types, yer nuts } end; DlogRPtr = ^DlogRef; PROCEDURE DrawBoxInerds(DlogPtr:DialogPtr); VAR fi: FontInfo; i,v: Integer; invert: Rect; VBar,HBar: ControlHandle; h: StrLHandle; val: Integer; ItemType: INTEGER; ItemHdl: Handle; BoxRect: Rect; Clear: Rect; Begin VBar := DlogRPtr(GetWRefCon(DlogPtr))^.VBar; HBar := DlogRPtr(GetWRefCon(DlogPtr))^.HBar; GetDItem(DlogPtr, getNmList, ItemType, ItemHdl, BoxRect); Clear := BoxRect; InsetRect(Clear,1,1); EraseRect(Clear); h := DlogRPtr(GetWRefCon(DlogPtr))^.List; if h = NIL then exit(DrawBoxInerds); GetFontInfo(fi); v := fi.ascent + boxRect.top + 1; val := GetCtlValue(VBar); for i := 0 to DlogRPtr(GetWRefCon(DlogPtr))^.rows do begin if i+val >= h^^.howmany then leave; MoveTo(boxRect.left+2 - (GetCtlValue(HBar)*IncHoriz),v); DrawString(h^^.table[i+val].str^^); if h^^.table[i+val].selected then begin SetRect(invert, boxRect.left+1, v - fi.ascent, boxRect.right - 1, v + fi.descent + fi.leading); InvertRect(invert); end; v := v + fi.ascent + fi.descent + fi.leading; end; End; PROCEDURE DrawGrayLine(theDialog: DialogPtr; ItemNo: integer); {this is the UserItem procedure that draws the gray divider line} VAR ItemType: integer; theItem: Handle; itsRect: Rect; penLoc: Point; Begin GetDItem(theDialog, ItemNo, ItemType, theItem, itsRect); penLoc.v := itsRect.top; penLoc.h := itsRect.left; PenNormal; moveto(penLoc.h, penLoc.v); while (penLoc.v < itsRect.bottom) do begin move(0,2); penLoc.v := penLoc.v + 2; Line(0,0); end; End; PROCEDURE PrVName(theDialog: DialogPtr; ItemNo: integer); {this is the UserItem procedure that draws the volume name} VAR ItemType: integer; theItem: Handle; itsRect: Rect; TempClip: RgnHandle; fi: FontInfo; width: Integer; lastSpace: Integer; i,line2: Integer; h: StrLHandle; BEGIN GetDItem(theDialog, ItemNo, ItemType, theItem, itsRect); EraseRect(itsRect); h := DlogRPtr(GetWRefCon(theDialog))^.list; if h = NIL then exit(PrVName); GetFontInfo(fi); TempClip := NewRgn; GetClip(TempClip); ClipRect(itsRect); width := StringWidth(h^^.vname); if width < itsRect.right-itsRect.left then begin MoveTo(itsRect.left+(((itsRect.right-itsRect.left)-width) div 2), itsRect.top + 3 + ((itsRect.bottom - itsRect.top) div 2)); DrawString(h^^.vname); end else begin { have to justify the sucker within the box } TextBox(Ptr(ORD4(h^)+vn_offset+1),length(h^^.vname),itsRect,teJustCenter); end; SetClip(TempClip); DisposeRgn(tempClip); END; PROCEDURE ScrollVert(DlogPtr: DialogPtr); Var OldOrig: integer; NewOrig: integer; delta: integer; theBox: Rect; UpDateRgn: RgnHandle; TempClip: RgnHandle; fi: FontInfo; SBar: ControlHandle; ItemType: INTEGER; ItemHdl: Handle; BoxRect: Rect; dp: DlogRPtr; Begin {get some new region space} UpDateRgn := NewRgn; {Rgn for use in updateing} TempClip := NewRgn; {Rgn for use in restoring the clip} dp := DlogRPtr(GetWRefCon(DlogPtr)); SBar := dp^.VBar; GetDItem(DlogPtr, getNmList, ItemType, ItemHdl, BoxRect); {calculate the amount scrolled} OldOrig := dp^.oldVert; NewOrig := GetCtlValue(SBar); GetFontInfo(fi); {get V diff. between old & new origin} delta := (OldOrig - NewOrig) * (fi.ascent+fi.descent+fi.leading); {get the area to scroll} SetRect(theBox, boxRect.left, boxRect.top, boxRect.right, boxRect.bottom); InSetRect(theBox, 1,1); {make scroll box smaller by one pixel} {do the scrolling} ScrollRect(theBox, 0, delta, UpDateRgn); {move pixels up by Vert. diff.} {clip to the update region} GetClip(TempClip); ClipRect(UpDateRgn^^.rgnBBox); {draw whatever is in the box} DrawBoxInerds(DlogPtr); {restore the clip & remember the new origin for next scroll} SetClip(TempClip); dp^.oldVert := NewOrig; {throw away unneeded things} DisposeRgn(tempClip); DisposeRgn(UpDateRgn); End; PROCEDURE ItemScroll(ScrollBarHdl:ControlHandle; CntlLoc: integer); Begin If (CntlLoc = inDownButton) & (GetCtlValue(ScrollBarHdl) < GetCtlMax(ScrollBarHdl)) then SetCtlValue(ScrollBarHdl, GetCtlValue(ScrollBarHdl) + 1) else If (CntlLoc = inUpButton) & (GetCtlValue(ScrollBarHdl) > GetCtlMin(ScrollBarHdl)) then SetCtlValue(ScrollBarHdl, GetCtlValue(ScrollBarHdl) - 1); ScrollVert(ScrollBarHdl^^.contrlOwner); End; PROCEDURE PageVert(ScrollBarHdl:ControlHandle; CntlLoc: integer); Begin If CntlLoc = inPageUp then SetCtlValue(ScrollBarHdl, GetCtlValue(ScrollBarHdl) - DlogRPtr(GetWRefCon(ScrollBarHdl^^.contrlOwner))^.rows) Else If CntlLoc = inPageDown then SetCtlValue(ScrollBarHdl, GetCtlValue(ScrollBarHdl) + DlogRPtr(GetWRefCon(ScrollBarHdl^^.contrlOwner))^.rows); If GetCtlValue(ScrollBarHdl) > GetCtlMax(ScrollBarHdl) then SetCtlValue(ScrollBarHdl,GetCtlMax(ScrollBarHdl)) Else If GetCtlValue(ScrollBarHdl) < GetCtlMin(ScrollBarHdl) then SetCtlValue(ScrollBarHdl,GetCtlMin(ScrollBarHdl)); ScrollVert(ScrollBarHdl^^.contrlOwner); End; { Procedure to handle mouse-downs in the vertical scroll bar } PROCEDURE VScroller(theDialog: DialogPtr); Var BoxScrollBar: ControlHandle; mouseLoc: Point; ControlLoc: integer; dummy: integer; Begin {get the mouse location- its local to the current Grafport} GetMouse(mouseLoc); {find the control part} ControlLoc := FindControl(mouseLoc, theDialog, BoxScrollBar); If ControlLoc <> 0 then begin Case ControlLoc of inUpButtom: dummy:=TrackControl(BoxScrollBar, mouseLoc, @ItemScroll); inDownButton: dummy:=TrackControl(BoxScrollBar, mouseLoc, @ItemScroll); inPageUp: PageVert(BoxScrollBar, ControlLoc); inPageDown: PageVert(BoxScrollBar, ControlLoc); inThumb: If TrackControl(BoxScrollBar, mouseLoc, Nil) <> 0 then ScrollVert(theDialog); End; End else sysbeep(3); End; PROCEDURE ScrollHoriz(DlogPtr: DialogPtr); Var OldOrig: integer; NewOrig: integer; delta: integer; theBox: Rect; UpDateRgn: RgnHandle; TempClip: RgnHandle; SBar: ControlHandle; ItemType: INTEGER; ItemHdl: Handle; BoxRect: Rect; dp: DlogRPtr; Begin {get some new region space} UpDateRgn := NewRgn; {Rgn for use in updateing} TempClip := NewRgn; {Rgn for use in restoring the clip} dp := DlogRPtr(GetWRefCon(DlogPtr)); SBar := dp^.HBar; GetDItem(DlogPtr, getNmList, ItemType, ItemHdl, BoxRect); {calculate the amount scrolled} OldOrig := dp^.oldHoriz; NewOrig := GetCtlValue(SBar); {get H diff. between old & new origin} delta := (OldOrig - NewOrig) * IncHoriz; {get the area and scroll} SetRect(theBox, boxRect.left, boxRect.top, boxRect.right, boxRect.bottom); InSetRect(theBox, 1,1); {make scroll box smaller by one pixel} ScrollRect(theBox, delta, 0, UpDateRgn); {clip to the update region} GetClip(TempClip); ClipRect(UpDateRgn^^.rgnBBox); {draw whatever is in the box} DrawBoxInerds(DlogPtr); {restore the clip & remember the new origin for next scroll} SetClip(TempClip); dp^.oldHoriz := NewOrig; {throw away unneeded things} DisposeRgn(tempClip); DisposeRgn(UpDateRgn); END; {tracking routine for horizontal scoll bar} PROCEDURE NameScroll(ScrollBarHdl:ControlHandle; CntlLoc: integer); Begin If (CntlLoc = inDownButton) & (GetCtlValue(ScrollBarHdl) < GetCtlMax(ScrollBarHdl)) then SetCtlValue(ScrollBarHdl, GetCtlValue(ScrollBarHdl) + 1) else If (CntlLoc = inUpButton) & (GetCtlValue(ScrollBarHdl) > GetCtlMin(ScrollBarHdl)) then SetCtlValue(ScrollBarHdl, GetCtlValue(ScrollBarHdl) - 1); ScrollHoriz(ScrollBarHdl^^.contrlOwner); End; PROCEDURE PageHoriz(ScrollBarHdl:ControlHandle; CntlLoc: integer); Begin If CntlLoc = inPageUp then SetCtlValue(ScrollBarHdl, GetCtlValue(ScrollBarHdl) - 5) Else If CntlLoc = inPageDown then SetCtlValue(ScrollBarHdl, GetCtlValue(ScrollBarHdl) + 5); If GetCtlValue(ScrollBarHdl) > GetCtlMax(ScrollBarHdl) then SetCtlValue(ScrollBarHdl,GetCtlMax(ScrollBarHdl)) Else If GetCtlValue(ScrollBarHdl) < GetCtlMin(ScrollBarHdl) then SetCtlValue(ScrollBarHdl,GetCtlMin(ScrollBarHdl)); ScrollHoriz(ScrollBarHdl^^.contrlOwner); End; { Procedure to handle mouse down events in the horizontal scroll bar } PROCEDURE HScroller(theDialog: DialogPtr); Var HScrollBar: ControlHandle; mouseLoc: Point; ControlLoc: integer; dummy: integer; Begin {get the mouse location- its local to the current Grafport} GetMouse(mouseLoc); {find the control part} ControlLoc := FindControl(mouseLoc, theDialog, HScrollBar); If ControlLoc <> 0 then begin Case ControlLoc of inUpButtom,inDownButton: dummy := TrackControl(HScrollBar, mouseLoc, @NameScroll); inPageUp,inPageDown: PageHoriz(HScrollBar, ControlLoc); inThumb: If TrackControl(HScrollBar, mouseLoc, Nil) <> 0 then ScrollHoriz(theDialog); End; End else sysbeep(3); End; PROCEDURE BoxContents(theDialog: DialogPtr; ItemNo: integer); Var ItemType: integer; ItemHdl: Handle; ItemRect: Rect; LongHdl: LongInt; TempClip: RgnHandle; Begin {first get the Box size} GetDItem(theDialog, ItemNo, ItemType, ItemHdl, ItemRect); {set the clip for drawing} TempClip := NewRgn; GetClip(TempClip); ClipRect(ItemRect); {do the drawing} FrameRect(ItemRect); DrawBoxInerds(theDialog); {restore the clip & clean up} SetClip(TempClip); DisposeRgn(tempClip); End; PROCEDURE ListAdjust(dlog: DialogPtr); VAR i: Integer; anySelected: Boolean; h:StrLHandle; itemType: Integer; itemHandle: Handle; itemBox: Rect; BEGIN h := DlogRPtr(GetWRefCon(dlog))^.List; anySelected := false; for i := 0 to h^^.howmany-1 do if h^^.table[i].selected then anySelected := true; GetDItem(dlog,getOpen,itemType,itemHandle,itemBox); if anySelected then HiLiteControl(ControlHandle(itemHandle), 0) else HiLiteControl(ControlHandle(itemHandle), 255); END; PROCEDURE MultClick(dlog: DialogPtr; bar: ControlHandle; rows: Integer); { this procedure handles mouse-down events in the name box (with multi-selection)} CONST pauseTime = 4; { 4 60th's of a second := 1/15 second } VAR mouseLoc: Point; fontHeight: Integer; fi: FontInfo; invert: Rect; name_no: Integer; h: StrLHandle; ItemType: Integer; ItemHdl: Handle; BoxRect: Rect; time: LongInt; selecting: (yep, nope, dunno); val,max: Integer; lastDone: Integer; BEGIN h := DlogRPtr(GetWRefCon(dlog))^.List; if h = NIL then begin sysbeep(3); exit(MultClick); end; GetFontInfo(fi); fontHeight := fi.ascent + fi.descent + fi.leading; GetDItem(Dlog, getNmList, ItemType, ItemHdl, BoxRect); selecting := dunno; max := GetCtlMax(bar); val := GetCtlValue(bar); while StillDown do begin { loop tracks mouse } SystemTask; GetMouse(mouseLoc); if mouseLoc.v < boxRect.top+1 then begin { past the top of the first row, scroll down } If val > 0 then SetCtlValue(bar, val - 1) else cycle; val := val - 1; case selecting of dunno: begin if h^^.table[val].selected then selecting := nope else selecting := yep; h^^.table[val].selected := NOT h^^.table[val].selected; end; yep: h^^.table[val].selected := true; nope: h^^.table[val].selected := false; end; lastDone := val; ScrollVert(dlog); Delay(pauseTime,time); cycle; end else name_no := (mouseLoc.v - (boxRect.top + 1)) div fontHeight; if name_no > (rows - 1) then begin { past the bottom of the last row, scroll upwards } If val < max then SetCtlValue(bar, val + 1) else cycle; val := val + 1; case selecting of dunno: begin if h^^.table[val+(rows-1)].selected then selecting := nope else selecting := yep; h^^.table[val+(rows-1)].selected := NOT h^^.table[val+(rows-1)].selected; end; yep: h^^.table[val+(rows-1)].selected := true; nope: h^^.table[val+(rows-1)].selected := false; end; lastDone := val+(rows-1); ScrollVert(dlog); Delay(pauseTime,time); cycle; end; if name_no + val >= h^^.howmany then cycle; case selecting of dunno: begin if h^^.table[name_no + val].selected then selecting := nope else selecting := yep; h^^.table[name_no + val].selected := NOT h^^.table[name_no + val].selected; invert.left := boxRect.left + 1; invert.top := boxRect.top + 1 + (name_no * fontHeight); invert.right := boxRect.right - 1; invert.bottom := boxRect.top+1+((name_no+1)*fontHeight); InvertRect(invert); end; yep: begin if NOT h^^.table[name_no + val].selected then begin h^^.table[name_no + val].selected := true; invert.left := boxRect.left + 1; invert.top := boxRect.top+1+(name_no * fontHeight); invert.right := boxRect.right - 1; invert.bottom := boxRect.top+1+ ((name_no+1)*fontHeight); InvertRect(invert); end; end; nope: begin if h^^.table[name_no + val].selected then begin h^^.table[name_no + val].selected := false; invert.left := boxRect.left + 1; invert.top := boxRect.top+1+(name_no*fontHeight); invert.right := boxRect.right - 1; invert.bottom := boxRect.top + 1 + ((name_no+1)*fontHeight); InvertRect(invert); end; end; end; { case } lastDone := name_no + val; end; { loop } ListAdjust(dlog); END; PROCEDURE UnSelect(h:StrLHandle; val, rows, fontHeight:Integer; boxRect: Rect); VAR i:INTEGER; invert:Rect; BEGIN for i := 0 to h^^.howmany - 1 do begin if h^^.table[i].selected then begin h^^.table[i].selected := false; if (i >= val) & (i-val < rows) then begin SetRect(invert, boxRect.left + 1, boxRect.top + 1 + ((i - val) * fontHeight), boxRect.right - 1, boxRect.top+1+ (((i-val)+1)*fontHeight)); InvertRect(invert); end; end; end; END; {UnSelect} PROCEDURE SingClick(dlog: DialogPtr; bar: ControlHandle; rows: Integer); { this procedure handles mouse-down events in the name box (no multi-selection)} CONST pauseTime = 4; { 4 60th's of a second := 1/15 second } VAR mouseLoc: Point; fontHeight: Integer; fi: FontInfo; invert: Rect; name_no: Integer; h: StrLHandle; ItemType: Integer; ItemHdl: Handle; BoxRect: Rect; time: LongInt; val,max: Integer; j: Integer; BEGIN h := DlogRPtr(GetWRefCon(dlog))^.List; if h = NIL then begin sysbeep(3); exit(SingClick); end; GetFontInfo(fi); fontHeight := fi.ascent + fi.descent + fi.leading; GetDItem(Dlog, getNmList, ItemType, ItemHdl, BoxRect); max := GetCtlMax(bar); val := GetCtlValue(bar); { single click unselects any existing selections } Unselect(h,val,rows,fontHeight,boxRect); while StillDown do begin { loop tracks mouse } SystemTask; GetMouse(mouseLoc); if mouseLoc.v < boxRect.top+1 then begin { past the top of the first row, scroll down } val := GetCtlValue(bar); If val > 0 then begin if not h^^.table[val - 1].selected then Unselect(h,val,rows,fontHeight,boxRect); SetCtlValue(bar, val - 1); end else cycle; h^^.table[val - 1].selected := true; ScrollVert(dlog); Delay(pauseTime,time); cycle; end else name_no := (mouseLoc.v - (boxRect.top + 1)) div fontHeight; if name_no > (rows - 1) then begin { past the bottom of the last row, scroll upwards } val := GetCtlValue(bar); If val < max then begin if not h^^.table[val + 1 + (rows-1)].selected then Unselect(h,val,rows,fontHeight,boxRect); SetCtlValue(bar, val + 1); end else cycle; h^^.table[val + 1 + (rows-1)].selected := true; ScrollVert(dlog); Delay(pauseTime,time); cycle; end; val := GetCtlValue(bar); if name_no + val >= h^^.howmany then cycle; if NOT h^^.table[name_no + val].selected then begin Unselect(h,val,rows,fontHeight,boxRect); h^^.table[name_no + val].selected := true; SetRect(invert, boxRect.left + 1, boxRect.top + 1 + (name_no * fontHeight), boxRect.right - 1, boxRect.top+1+((name_no+1)*fontHeight)); InvertRect(invert); end; end; { loop } { disable or enable Open button as needed } GetDItem(dlog,getOpen,ItemType,ItemHdl,BoxRect); for j := 0 to h^^.howmany-1 do if h^^.table[j].selected then begin HiLiteControl(ControlHandle(ItemHdl),0); exit(SingClick); end; HiLiteControl(ControlHandle(ItemHdl),255); END; FUNCTION CallBool(PB:ParmBlkPtr; func:ProcPtr):Boolean; external; FUNCTION GetFList(vref:Integer; numTypes:Integer; typeList:SFTypeList; fileFilter: ProcPtr):StrLHandle; VAR i, j: Integer; h: StrLHandle; PB: ParamBlockRec; s: STR255; sh: StringHandle; err: OSErr; OK: Boolean; numFiles, badfiles, t: Integer; v: VCBPtr; BEGIN if vref = 0 then begin { default volume, find its real reference number } v := VCBHdl(DefVCBPtr)^; vref := v^.vcbVRefNum; end else if vref > 0 then begin { drive number, find volume ref } v := VCBPtr(GetVCBQHdr^.qHead); while (v <> NIL) & (v^.vcbDrvNum <> vref) do v := VCBPtr(v^.qLink); if v = NIL then SysError(-56); { no such drive } vref := v^.vcbVRefNum; end else begin { volume reference number } v := VCBPtr(GetVCBQHdr^.qHead); while (v <> NIL) & (v^.vcbVRefNum <> vref) do v := VCBPtr(v^.qLink); if v = NIL then SysError(-35); {no such volume} end; numFiles := v^.vcbNmFls; h := StrLHandle(NewHandle(sizeof(StrList) + (numFiles*sizeof(StrCell)))); if (memError <> noErr) | (h = NIL) then SysError(25); h^^.volume := vref; h^^.vname := v^.vcbVN; badfiles := 0; t := 0; for i := 1 to numFiles do begin PB.ioVersNum := 0; PB.ioVRefNum := vref; s := ''; PB.ioNamePtr := @s; PB.ioFDirIndex := i; err := PBGetFInfo(@PB, FALSE); if err <> noErr then SysError(err); if numTypes <> -1 then begin OK := false; for j := 0 to numTypes-1 do if typeList[j] = PB.ioFlFndrInfo.fdType then begin OK := true; leave; end; end else OK := true; if OK & (fileFilter <> NIL) then OK := NOT CallBool(@PB,fileFilter); if OK then begin sh := POINTER(ORD4(NewHandle(length(s)+1))); if (memError <> noErr) | (sh = NIL) then SysError(25); BlockMove(@s, Ptr(sh^), length(s) + 1); h^^.table[t].str := sh; h^^.table[t].selected := FALSE; t := t + 1; end else badfiles := badfiles + 1; end; h^^.howmany := numFiles - badfiles; SetHandleSize(Handle(h),sizeof(StrList) + (h^^.howmany*sizeof(StrCell))); err := MemError; if err <> noErr then SysError(err); GetFList := h; END; PROCEDURE DelFList(h:StrLHandle); VAR i:INTEGER; err:OSErr; BEGIN if h = NIL then exit(DelFList); for i := 0 to h^^.howmany-1 do begin if h^^.table[i].str <> NIL then begin DisposHandle(Handle(h^^.table[i].str)); err := memError; if err <> noErr then SysError(err); end; end; DisposHandle(Handle(h)); err := memError; if err <> noErr then SysError(err); END; PROCEDURE CompFList(h:StrLHandle); VAR i,j:INTEGER; err:OSErr; selNum:Integer; BEGIN if h = NIL then exit(CompFList); selNum := 0; for i := 0 to h^^.howmany-1 do begin if not h^^.table[i].selected then begin DisposHandle(Handle(h^^.table[i].str)); err := memError; if err <> noErr then SysError(err); h^^.table[i].str := NIL; end else begin selNum := selNum + 1; { move it back to fill up any holes } if (i > 0) & (h^^.table[i-1].str = NIL) then begin for j := i - 1 downto 0 do if h^^.table[j].str <> NIL then leave; if (j = 0) & (h^^.table[0].str = NIL) then j := -1; h^^.table[j+1].str := h^^.table[i].str; h^^.table[j+1].selected := true; h^^.table[i].str := NIL; h^^.table[i].selected := false; end; end; end; h^^.howmany := selNum; SetHandleSize(Handle(h),sizeof(StrList) + (h^^.howmany*sizeof(StrCell))); END; {simple selection sort is fast enough} PROCEDURE SortFList(h:StrLHandle); VAR i:Integer; flag,tmp:Boolean; s:StringHandle; BEGIN flag := true; while flag do begin flag := false; for i := 0 to h^^.howmany - 2 do begin if IUMagString(POINTER(ORD4(h^^.table[i].str^)+1), POINTER(ORD4(h^^.table[i+1].str^)+1), length(h^^.table[i].str^^), length(h^^.table[i+1].str^^)) = 1 then begin flag := true; s := h^^.table[i].str; tmp := h^^.table[i].selected; h^^.table[i].str := h^^.table[i+1].str; h^^.table[i].selected := h^^.table[i+1].selected; h^^.table[i+1].str := s; h^^.table[i+1].selected := tmp; end; end; end; END; FUNCTION DrvHasDisk(Drive: DrvElPtr): Boolean; VAR RawPtr:PTR; BEGIN RawPtr := POINTER(ORD4(Drive)-3); if RawPtr^ in [1,2,8] then DrvHasDisk := true else DrvHasDisk := false; END; PROCEDURE DlogSetup(SFFileDlg:DialogPtr); VAR ItemType: integer; ItemHdl: Handle; ItemRect: Rect; VScrollBar: ControlHandle; HScrollBar: ControlHandle; List: StrLHandle; rows: INTEGER; dp: DlogRPtr; max,i,w: Integer; BEGIN dp := DlogRPtr(GetWRefCon(SFFileDlg)); VScrollBar := dp^.VBar; HScrollBar := dp^.HBar; List := dp^.List; rows := dp^.Rows; {set scroll bar values} if List = NIL then SetCtlMax(VScrollBar, 0) else begin if List^^.howmany >= rows then SetCtlMax(VScrollBar,List^^.howmany-rows) else SetCtlMax(VScrollBar,0); end; SetCtlValue(VScrollBar, 0); if GetCtlMax(VScrollBar) < 1 then HiLiteControl(VScrollBar,255) else HiLiteControl(VScrollBar,0); { the maximum value of the horizontal scroll bar is the maximum width of the strings in the file list minus the width of the name list box } SetCtlValue(HScrollBar,0); if List = NIL then HiLiteControl(HScrollBar,255) else begin max := 0; for i := 0 to List^^.howmany - 1 do begin w := StringWidth(List^^.table[i].str^^); if w > max then max := w; end; GetDItem(SFFileDlg,getNmList,itemType,itemHdl,itemRect); w := (itemRect.right - itemRect.left) + 4; { 4 for frame + offset } if max <= w then HiLiteControl(HScrollBar,255) else begin SetCtlMax(HScrollBar,((max - w) div IncHoriz) + 2); HiLiteControl(HScrollBar,0); end; end; {make open button inactive initially} GetDItem(SFFileDlg,getOpen,itemType,itemHdl,itemRect); HiLiteControl(ControlHandle(itemHdl), 255); {Set scrollbar old settings = to zero initially} dp^.oldVert := 0; dp^.oldHoriz := 0; END; FUNCTION SFFilter(theDialog: DialogPtr; VAR theEvent: EventRecord; VAR theItem: INTEGER): Boolean; VAR DIEvent: EventRecord; DIpt: Point; DIOK: Boolean; ItemType: integer; ItemHdl: Handle; ItemRect: Rect; ItemPt: Point; dp: DlogRPtr; tmpDrvPtr:DrvElPtr; i: Integer; BEGIN if GetNextEvent(diskMask,DIEvent) then begin dp := DlogRPtr(GetWRefCon(theDialog)); if HiWord(DIEvent.message) <> noErr then begin DIPt.v := 120; DIPt.h := 150; if DIBadMount(DIpt, DIEvent.message) = noErr then DIOK := true else DIOK := false; end else DIOK := true; if DIOK then begin { set up from new drive } DelFList(dp^.list); dp^.list := GetFList(LoWord(DIEvent.message),dp^.tnum, dp^.tlist,dp^.filter); SortFList(dp^.list); DlogSetUp(theDialog); { if 2 or more disks in, activate Drive button } i := 0; tmpDrvPtr := DrvElPtr(GetDrvQHdr^.qHead); while tmpDrvPtr <> NIL do begin if DrvHasDisk(tmpDrvPtr) then i := i + 1; tmpDrvPtr := DrvElPtr(tmpDrvPtr^.qLink); end; if i > 1 then begin GetDItem(theDialog,getDrive,ItemType,ItemHdl, ItemRect); HiliteControl(ControlHandle(ItemHdl),0); end; { activate Eject button } GetDItem(theDialog,getEject,ItemType,ItemHdl,ItemRect); HiliteControl(ControlHandle(ItemHdl),0); { set drive pointer for later use } dp^.DrvPtr := DrvElPtr(GetDrvQHdr^.qHead); while dp^.DrvPtr^.dQDrive <> LoWord(DIEvent.message) do dp^.DrvPtr := DrvElPtr(dp^.DrvPtr^.qLink); { cause the dialog to be redrawn } InvalRect(theDialog^.portRect); end; end; if (theEvent.what = mouseDown) then begin GetDItem(theDialog,getNmList,ItemType,ItemHdl,ItemRect); ItemPt := theEvent.where; GlobalToLocal(ItemPt); if PtInRect(ItemPt,ItemRect) then begin if BitAnd(theEvent.modifiers,shiftKey) <> 0 then theItem := shiftList else theItem := getNmList; SFFilter := true; exit(SFFilter); end; end; if (theEvent.what in [keyDown,autoKey]) & (BitAnd(theEvent.modifiers,BitOr(optionKey,cmdKey)) = 0) & (chr(BitAnd(theEvent.message,$ff)) = chr($0d) { cr }) then begin GetDItem(theDialog,getOpen,ItemType,ItemHdl,ItemRect); ItemPt.h := (ItemRect.left + ItemRect.right) div 2; ItemPt.v := (ItemRect.top + ItemRect.bottom) div 2; if TestControl(ControlHandle(ItemHdl),ItemPt) in [254,0] then SFFilter := false else begin theItem := 1; SFFilter := true; end; end else SFFilter := false; END; FUNCTION SFMGetFile(where: Point; fileFilter: ProcPtr; numTypes:Integer; typeList:SFTypeList; dlgHook:ProcPtr; flags:Integer): StrLHandle; Var SFFileDlg: DialogPtr; ItemHit: integer; ItemType: integer; ItemHdl: Handle; ItemRect: Rect; tmpRect: Rect; DRec: DlogRef; tmpDrvPtr: DrvElPtr; tmp: Integer; fi: FontInfo; PB: ParamBlockRec; err: OSErr; savePort: GrafPtr; v: VCBPtr; multichecked:Boolean; lastclick: LongInt; lastpoint: Point; tmppoint: Point; ip: IntPtr; Begin DRec.filter := fileFilter; DRec.tnum := numTypes; if numTypes > -1 then begin for tmp := 0 to numTypes - 1 do DRec.tlist[tmp] := typeList[tmp]; end; lastclick := 0; {create the dialog} GetPort(savePort); SFFileDlg := GetNewDialog(DlogResID, Nil, Pointer(-1)); MoveWindow(SFFileDlg, where.h, where.v, FALSE); SetPort(SFFileDlg); SetWRefCon(SFFileDlg,ORD4(@DRec)); GetDItem(SFFileDlg,getScroll,ItemType,ItemHdl,ItemRect); DRec.VBar := NewControl(SFFileDlg, ItemRect, '', TRUE, 0, 0, 0, scrollBarProc,0); GetDItem(SFFileDlg,getHScroll,ItemType,ItemHdl,ItemRect); GetDItem(SFFileDlg,getNmList,ItemType,ItemHdl,tmpRect); DRec.HBar := NewControl(SFFileDlg, ItemRect, '', TRUE, 0, 0, tmpRect.right div IncHoriz, scrollBarProc,0); {set up the multiple file check box using flags} GetDItem(SFFileDlg,getMChk,ItemType,ItemHdl,ItemRect); if BitAnd(flags,SFMmulti) = 0 then HideControl(ControlHandle(ItemHdl)) else if BitAnd(flags,SFMenable) = 0 then HiLiteControl(ControlHandle(ItemHdl),255); if BitAnd(flags,SFMstart) = 0 then multichecked := false else multichecked := true; SetCtlValue(ControlHandle(ItemHdl),ord(multichecked)); {set the font information} TextFont(0); TextFace([]); TextMode(srcOr); TextSize(12); GetFontInfo(fi); GetDItem(SFFileDlg, getNmList, ItemType, ItemHdl, ItemRect); Drec.rows := 1 + ((ItemRect.bottom-ItemRect.top) - 3) div (fi.ascent+fi.descent+fi.leading); {set up the drive button (oh, God, this is complicated...)} DRec.DrvPtr := DrvElPtr(GetDrvQHdr^.qHead); if DRec.DrvPtr^.qLink = NIL then begin { only one drive attached } GetDItem(SFFileDlg,getDrive,itemType,itemHdl,itemRect); HideControl(ControlHandle(itemHdl)); { hide Drive button } if DrvHasDisk(DRec.DrvPtr) then { if it has a disk, set up from that } DRec.List := GetFList(DRec.DrvPtr^.dQDrive,numTypes,typeList, fileFilter) else begin { drive has no disk, disable Eject and set list to NIL } DRec.List := NIL; GetDItem(SFFileDlg,getEject,itemType,itemHdl,itemRect); HiLiteControl(ControlHandle(itemHdl), 255); end; end else begin {multiple drives in queue} tmp := 0; tmpDrvPtr := DrvElPtr(GetDrvQHdr^.qHead); while tmpDrvPtr <> NIL do begin { count number of drives with disks } if DrvHasDisk(tmpDrvPtr) then tmp := tmp + 1; tmpDrvPtr := DrvElPtr(tmpDrvPtr^.qLink); end; if tmp = 0 then begin { no drives have disks, disable Eject and Drive } DRec.List := NIL; GetDItem(SFFileDlg,getEject,itemType,itemHdl,itemRect); HiLiteControl(ControlHandle(itemHdl), 255); GetDItem(SFFileDlg,getDrive,itemType,itemHdl,itemRect); HiLiteControl(ControlHandle(itemHdl), 255); end else if tmp = 1 then begin { only one drive has a disk, disable Drive } { find which drive it is that has a disk, set up from it } DRec.DrvPtr := DrvElPtr(GetDrvQHdr^.qHead); while NOT DrvHasDisk(DRec.DrvPtr) do DRec.DrvPtr := DrvElPtr(DRec.DrvPtr^.qLink); Drec.List := GetFList(DRec.DrvPtr^.dQDrive,numTypes,typeList, fileFilter); GetDItem(SFFileDlg,getDrive,itemType,itemHdl,itemRect); HiLiteControl(ControlHandle(itemHdl), 255); end else begin { multiple drives have disks } { try to use last volume seen by SFGetFile } v := VCBPtr(GetVCBQHdr^.qHead); tmp := IntPtr(SFSaveDisk)^; tmp := -tmp; while (v <> NIL) & (v^.vcbVRefNum <> tmp) do v := VCBPtr(v^.qLink); if v <> NIL then begin DRec.DrvPtr := DrvElPtr(GetDrvQHdr^.qHead); while (DRec.DrvPtr <> NIL) & (DRec.DrvPtr^.dQDrive <> v^.vcbDrvNum) do DRec.DrvPtr := DrvElPtr(DRec.DrvPtr^.qLink); end else begin { try to use default volume } v := VCBHdl(DefVCBPtr)^; DRec.DrvPtr := DrvElPtr(GetDrvQHdr^.qHead); while (DRec.DrvPtr <> NIL) & (DRec.DrvPtr^.dQDrive <> v^.vcbDrvNum) do DRec.DrvPtr := DrvElPtr(DRec.DrvPtr^.qLink); end; { if those volumes don't have disks, then use the first drive that does have a disk } if (DRec.DrvPtr = NIL) | NOT DrvHasDisk(DRec.DrvPtr) then begin DRec.DrvPtr := DrvElPtr(GetDrvQHdr^.qHead); while NOT DrvHasDisk(DRec.DrvPtr) do DRec.DrvPtr := DrvElPtr(DRec.DrvPtr^.qLink); end; { set up from whatever disk was chosen } Drec.List := GetFList(DRec.DrvPtr^.dQDrive, numTypes, typeList, fileFilter); end; end; if Drec.List <> NIL then SortFList(Drec.List); {set the gray line userItem} GetDItem(SFFileDlg, GrayLine, ItemType, ItemHdl, ItemRect); ItemHdl := Handle(ORD(@DrawGrayLine)); SetDItem(SFFileDlg, GrayLine, ItemType, ItemHdl, ItemRect); {set the Box UserItem} GetDItem(SFFileDlg, getNmList, ItemType, ItemHdl, ItemRect); ItemHdl := Handle(ORD(@BoxContents)); SetDItem(SFFileDlg, getNmList, ItemType, ItemHdl, ItemRect); {set the volume name UserItem} GetDItem(SFFileDlg, VolName, ItemType, ItemHdl, ItemRect); ItemHdl := Handle(ORD(@PrVName)); SetDItem(SFFileDlg, VolName, ItemType, ItemHdl, ItemRect); {set up control values and such} DlogSetUp(SFFileDlg); {everything has been setup, show the dialog window} ShowWindow(SFFileDlg); {draw the fake grow box} GetDItem(SFFileDlg, getScroll, ItemType, ItemHdl, ItemRect); tmpRect.top := ItemRect.bottom - 1; tmpRect.right := ItemRect.right; GetDItem(SFFileDlg, getHScroll, ItemType, ItemHdl, ItemRect); tmpRect.left := ItemRect.right - 1; tmpRect.bottom := ItemRect.bottom; FrameRect(tmpRect); InsetRect(tmpRect,2,2); while (tmpRect.right-tmpRect.left) >= 2 do begin FrameRect(tmpRect); InsetRect(tmpRect,2,2); end; {now start processing some user inputs} Repeat ModalDialog(@SFFilter, ItemHit); Case ItemHit of getEject: begin PB.ioNamePtr := NIL; PB.ioVRefNum := DRec.List^^.volume; err := PBEject(@PB); if err = noErr then begin DelFList(DRec.List); { try to move on to next drive. However, all the drives may be empty. } DRec.DrvPtr := DrvElPtr(DRec.DrvPtr^.qLink); while (DRec.DrvPtr <> NIL) & NOT DrvHasDisk(DRec.DrvPtr) do DRec.DrvPtr := DrvElPtr(DRec.DrvPtr^.qLink); if DRec.DrvPtr = NIL then begin DRec.DrvPtr := DrvElPtr(GetDrvQHdr^.qHead); while (DRec.DrvPtr <> NIL) & NOT DrvHasDisk(DRec.DrvPtr) do DRec.DrvPtr := DrvElPtr(DRec.DrvPtr^.qLink); end; if DRec.DrvPtr = NIL then begin {all empty} DRec.List := NIL; GetDItem(SFFileDlg,getEject,itemType, itemHdl,itemRect); HiLiteControl(ControlHandle(itemHdl),255); GetDItem(SFFileDlg,getDrive,itemType, itemHdl,itemRect); HiLiteControl(ControlHandle(itemHdl),255); end else begin Drec.List := GetFList(DRec.DrvPtr^.dQDrive, numTypes,typeList,fileFilter); SortFList(Drec.List); { if fewer than two drives have disks, then deactivate the Drive button } tmp := 1; tmpDrvPtr := DrvElPtr(DRec.DrvPtr^.qLink); while tmpDrvPtr <> NIL do begin if DrvHasDisk(tmpDrvPtr) then tmp := tmp + 1; tmpDrvPtr := DrvElPtr(tmpDrvPtr^.qLink); end; if tmp < 2 then begin GetDItem(SFFileDlg,getDrive, itemType,itemHdl, itemRect); HiLiteControl(ControlHandle( itemHdl),255); end; end; DlogSetUp(SFFileDlg); InvalRect(SFFileDlg^.portRect); end; end; getDrive: begin DelFList(DRec.List); DRec.DrvPtr := DrvElPtr(DRec.DrvPtr^.qLink); while (DRec.DrvPtr <> NIL) & NOT DrvHasDisk(DRec.DrvPtr) do DRec.DrvPtr := DrvElPtr(DRec.DrvPtr^.qLink); if DRec.DrvPtr = NIL then begin DRec.DrvPtr := DrvElPtr(GetDrvQHdr^.qHead); while NOT DrvHasDisk(DRec.DrvPtr) do DRec.DrvPtr := DrvElPtr(DRec.DrvPtr^.qLink); end; Drec.List := GetFList(DRec.DrvPtr^.dQDrive,numTypes, typeList,fileFilter); SortFList(Drec.list); DlogSetUp(SFFileDlg); InvalRect(SFFileDlg^.portRect); end; shiftList: begin if multichecked then MultClick(SFFileDlg, DRec.VBar, Drec.rows) else begin GetDItem(SFFileDlg,getMChk,ItemType,ItemHdl, ItemRect); SetCtlValue(ControlHandle(ItemHdl),1); MultClick(SFFileDlg, DRec.VBar, Drec.rows); SetCtlValue(ControlHandle(ItemHdl),0); end; end; getNmList: begin if multichecked then MultClick(SFFileDlg, DRec.VBar, Drec.rows) else begin { is this a double click? Note that I do not quite do this by the book; there are extra delays in the times involved, since I don't use the times stored in event records. It should all average out, though. } if TickCount - lastClick < GetDblTime then begin { time OK for double click, check motion } GetMouse(tmpPoint); if (abs(tmpPoint.h - lastPoint.h) < 3) & (abs(tmpPoint.v - lastPoint.v) < 3) then itemHit := getOpen else begin lastpoint := tmppoint; SingClick(SFFileDlg, DRec.VBar, Drec.rows); lastclick := TickCount; end end else begin GetMouse(lastPoint); SingClick(SFFileDlg, DRec.VBar, Drec.rows); lastclick := TickCount; end; end; end; getScroll: VScroller(SFFileDlg); getHScroll: HScroller(SFFileDlg); getMChk: begin GetDItem(SFFileDlg,getMChk,ItemType,ItemHdl,ItemRect); if multichecked then SetCtlValue(ControlHandle(ItemHdl),0) else SetCtlValue(ControlHandle(ItemHdl),1); multichecked := NOT multichecked; end; End; Until ItemHit in [getOpen,getCancel]; { set last volume seen by standard file package } if DRec.DrvPtr <> NIL then begin v := VCBPtr(GetVCBQHdr^.qHead); while (v <> NIL) & (v^.vcbDrvNum <> DRec.DrvPtr^.dQDrive) do v := VCBPtr(v^.qLink); if v <> NIL then begin ip := IntPtr(SFSaveDisk); ip^ := -v^.vcbVRefNum; end; end; if DRec.List <> NIL then begin CompFList(DRec.List); if itemHit <> getOpen then begin DelFList(DRec.List); DRec.List := NIL; end; end; DisposeControl(DRec.VBar); DisposeControl(DRec.HBar); DisposDialog(SFFileDlg); SetPort(savePort); SFMGetFile := DRec.List; End; END. !E!O!F! # # echo extracting sfmget/sfmgetr.text... cat >sfmget/sfmgetr.text <<'!E!O!F!' * resource compiler input file for SFMGetFile resources * sfmget-sfmgetr.rsrc * this is the dialog referenced as SFDialog in program Type DLOG ,-4001 0 0 152 358 InVisible 1 NoGoAway 0 -4001 * Item list for the SFdialog Type DITL ,-4001 12 BtnItem Enabled 28 162 46 242 Open BtnItem Disabled 59 1552 77 1232 Invisible BtnItem Enabled 90 162 108 242 Cancel *the volume name UserItem Disabled 22 258 54 354 BtnItem Enabled 59 266 77 346 Eject BtnItem Enabled 90 266 108 346 Drive *the window in the dialog UserItem Enabled 11 12 125 135 *the scroll bar for the window UserItem Enabled 11 134 125 150 *the gray line UserItem Disabled 20 254 116 255 StatText Disabled 20 1044 116 1145 Invisible Text *the horizontal scroll bar UserItem Enabled 124 12 140 135 ChkItem Enabled 125 172 140 346 Multiple File Selection !E!O!F! # # echo extracting sfmget/sfmtest.text... cat >sfmget/sfmtest.text <<'!E!O!F!' {$X-} {$U-} {$R-} Program SFMTest; USES {$U Obj-Memtypes } MemTypes, {$U Obj-QuickDraw } QuickDraw, {$U Obj-OSIntf } OSIntf, {$U Obj-ToolIntf } ToolIntf, {$U Obj-PackIntf } PackIntf, {$U Obj-WritelnWindow } WritelnWindow, {$U sfmget-SFMIntf } SFMIntf; CONST AppleMenu = 256; FileMenu = 257; FilterDlog = 256; TypeDlog = 257; TYPE myTypeList = ARRAY [0..7] OF OSType; VAR Finished: Boolean; {used to terminate the program} myFilter: ProcPtr; bounds: Rect; numTypes: INTEGER; typeList: myTypeList; FUNCTION theFilter(PB:ParmBlkPtr):Boolean; VAR theDialog: DialogPtr; itemHit: INTEGER; BEGIN ParamText(PB^.ioNamePtr^,'','',''); theDialog := GetNewDialog(FilterDlog,NIL,POINTER(-1)); ModalDialog(NIL,itemHit); DisposDialog(theDialog); if itemHit = 1 then theFilter := FALSE else theFilter := TRUE; END; PROCEDURE SetTypes; VAR theDialog: DialogPtr; itemHit: INTEGER; ItemType: INTEGER; ItemHdl: Handle; ItemBox: Rect; s: STR255; i: INTEGER; tmp: LongInt; tp: OSType; BEGIN theDialog := GetNewDialog(TypeDlog,NIL,POINTER(-1)); ModalDialog(NIL,ItemHit); if ItemHit = 2 then begin DisposDialog(theDialog); exit(SetTypes); end; GetDItem(theDialog,3,ItemType,ItemHdl,ItemBox); GetIText(ItemHdl,s); StringToNum(s,tmp); numTypes := tmp; for i := 0 to 7 do begin GetDItem(theDialog,4+i,ItemType,ItemHdl,ItemBox); GetIText(ItemHdl,s); BlockMove(POINTER(ORD4(@s)+1),@tp,4); typeList[i] := tp; end; DisposDialog(theDialog); END; PROCEDURE Break; inline $FACE; PROCEDURE ProcessMenu_in(CodeWord:longint); Var Menu_No: integer; {menu number that was selected} Item_No: integer; {item in menu that was selected} NameHolder: Str255; {name holder for desk accessory or font} DNA: integer; {OpenDA will never return 0, so don't care} pt: Point; h: StrLHandle; err: OSErr; i: Integer; reply: SFReply; Begin If CodeWord <> 0 then begin Menu_No := HiWord(CodeWord); {get the Hi word of...} Item_no := LoWord(CodeWord); {get the Lo word of...} Case Menu_No of AppleMenu:Begin GetItem(GetMHandle(AppleMenu), Item_No, NameHolder); DNA := OpenDeskAcc(NameHolder); End; FileMenu: case Item_No of 1: begin pt.v := 100; pt.h := 100; h := XMGetFile(pt,myFilter,numTypes,@typeList,NIL, BitOr(SFMmulti,SFMenable)); if h <> NIL then begin WriteLn('Volume ',h^^.volume:1,': ',h^^.vname, ' (',h^^.howmany:1,' files selected)'); for i := 0 to h^^.howmany-1 do WriteLn(' ',h^^.table[i].str^^); DelFList(h); end; SFMEnd; end; 2: err := Eject(NIL,1); 3: err := Eject(NIL,2); 4: if myFilter = NIL then begin CheckItem(GetMenu(Menu_No), Item_No, TRUE); myFilter := @theFilter; end else begin CheckItem(GetMenu(Menu_No), Item_No, FALSE); myFilter := NIL; end; 5: SetTypes; 6: begin pt.v := 100; pt.h := 100; SFPutFile(pt,'Having fun with your','Luau Frog Giblets?', NIL,reply); end; 7: Finished := True; end; End;{case of Menu_No} end; {the If codeword <> 0} HiliteMenu(0); {unhilite after processing menu} End; {of ProcessMenu_in procedure} PROCEDURE DealwthMouseDowns(Event:EventRecord); Var WindowPointedTo: WindowPtr; MouseLoc:Point; WindoLoc:integer; Begin MouseLoc := Event.Where; WindoLoc := FindWindow(MouseLoc, WindowPointedTo); Case WindoLoc of inMenuBar: ProcessMenu_in(MenuSelect(MouseLoc)); inSysWindow: SystemClick(Event,WindowPointedTo); inContent,inGrow: WWMouseDown(WindoLoc, Event.where, Event.modifiers); End{ of case}; End; PROCEDURE DealwthKeyDowns(Event:EventRecord); Var CharCode:char; Begin CharCode:= chr(Event.message MOD 128); If BitAnd(Event.modifier,CmdKey) = CmdKey then ProcessMenu_in(MenuKey(CharCode)); End; PROCEDURE MainEventLoop; Var Event:EventRecord; ProcessIt: Boolean; DIPt: Point; Fake: OSErr; Begin Repeat SystemTask; {so you can support Desk Accessories} ProcessIt := GetNextEvent(EveryEvent,Event); If ProcessIt{is true} then {we'll ProcessIt} Case Event.what of activateEvt: WWActivateEvent(Event.modifiers); updateEvt : WWUpdateEvent; mouseDown : DealwthMouseDowns(Event); KeyDown : DealwthKeyDowns (Event); diskEvt : if HiWord(Event.message) <> noErr then begin DIPt.v := 120; DIPt.h := 150; Fake := DIBadMount(DIpt, Event.message); end; End;{of Case} Until Finished; {terminate the program} End; BEGIN InitGraf(@thePort); MaxApplZone; MoreMasters; MoreMasters; MoreMasters; MoreMasters; {init everything in case the app is the Startup App} InitFonts; InitWindows; InitMenus; TEInit; InitDialogs(Nil); InitCursor; WWInit(200,80); bounds.top := 40; bounds.left := 10; bounds.bottom := 340; bounds.right := 500; WWNew(bounds,'Test Window',FALSE,TRUE,1,9); Finished := False; myFilter := NIL; numTypes := -1; FlushEvents(everyEvent,0); AddResMenu(GetMenu(AppleMenu),'DRVR'); InsertMenu(GetMenu(AppleMenu),0); InsertMenu(GetMenu(FileMenu),0); DrawMenuBar; {all done so show the menu bar} MainEventLoop; END. !E!O!F! # # echo extracting sfmget/sfmtesto.text... cat >sfmget/sfmtesto.text <<'!E!O!F!' sfmget-sfmtesto.rsrc Type CODE sfmget-sfmtestL,0 Type SOFT = DRVR sfmget-sfmgetfileL!SFMGetFile,1 (16) !E!O!F! # # echo extracting sfmget/sfmtestr.text... cat >sfmget/sfmtestr.text <<'!E!O!F!' * Input Resource File for Standard File example * sfmget-sfmtestr.Rsrc * apple menu, 14 is apple symbol in HEX Type MENU ,256 \14 * file menu ,257 File Open /O Eject Internal /I Eject External /E Filter Files /F Set Types /S Put File Test /P Quit /Q Type DLOG ,256 80 80 170 380 Visible 2 NoGoAway 0 256 Type DITL ,256 3 BtnItem Enabled 55 20 80 130 YES BtnItem Enabled 55 170 80 280 NO StatText Disabled 15 20 45 280 Should I allow the file "^0" to be used? Type DLOG ,257 178 163 328 463 Visible 3 NoGoAway 0 257 Type DITL ,257 12 BtnItem Enabled 105 40 137 120 OK BtnItem Enabled 105 185 137 265 CANCEL EditText Disabled 15 205 32 245 -1 EditText Disabled 40 25 56 75 TEXT EditText Disabled 40 95 56 145 MACA EditText Disabled 40 160 56 210 APPL EditText Disabled 40 225 56 275 MACS EditText Disabled 65 25 81 75 ZSYS EditText Disabled 65 95 81 145 PFIL EditText Disabled 65 160 81 210 FNDR EditText Disabled 65 225 81 275 DAMN StatText Disabled 15 25 31 185 Number of File Types: !E!O!F! exit -=- Tim Maroney, Professional Heretic, CMU Center for Art and Technology tim@k.cs.cmu.edu | uucp: {seismo,decwrl,ucbvax,etc.}!k.cs.cmu.edu!tim CompuServe: 74176,1360 | God is not dead; he just smells funny.