DIRECTORY CIFS USING [Error], EditSpan USING [Delete, InsertOtherNode], Directory USING [Error, LookupUnlimited, RemoveFile, Rename], File USING [Capability, Delete, nullCapability], GEditClasses, GEditIO USING [MyParent], GEditMotion USING [Move], GEditPaint USING [GEditPainter], GEditSelect, GEditViewer, Graphics USING [Context, PaintMode, SetCP, SetPaintMode], GraphicsOps USING [BitmapRef, BitmapRep, DrawBitmap], InputFocus USING [GetInputFocus, SetInputFocus], Menus USING [AppendMenuEntry, CreateEntry, CreateMenu, Menu, MenuProc, MouseButton], MessageWindow USING [Append, Blink], OtherNode USING [CopyInfo, Register], Process USING [Detach], PutGet USING [FromFile, ToFile], RefTab USING [Create, Fetch, Ref, Store], Rope USING [Cat, ROPE, ToRefText], SafeStorage USING [NewZone], TextEdit USING [DocFromNode], TextNode USING [FirstChild, LastChild, MakeNodeSpan, NarrowToOtherNode, NewOtherNode, Next, Previous, Ref, Root], TIPUser USING [InstantiateNewTIPTable, TIPScreenCoords], ViewerClasses USING [InitProc, ModifyProc, NotifyProc, SaveProc, Viewer, ViewerClass, ViewerClassRec], ViewerMenus USING [Save], ViewerOps USING [PaintViewer, RegisterViewerClass, SetMenu, SetNewVersion]; GEditViewerImpl: PROGRAM IMPORTS CIFS, Directory, EditSpan, File, GEditIO, GEditMotion, GEditPaint, Graphics, GraphicsOps, InputFocus, Menus, MessageWindow, OtherNode, Process, PutGet, RefTab, Rope, SafeStorage, TextEdit, TextNode, TIPUser, ViewerMenus, ViewerOps EXPORTS GEditSelect, GEditViewer = BEGIN OPEN GEditViewer, GEditClasses; gZ: ZONE _ SafeStorage.NewZone[quantized]; selection: PUBLIC Selection _ NEW[SelectionRec]; classes: LIST OF Class _ NIL; RegisterClass: PUBLIC PROC [flavor: ClassID, classInfo: ClassRec] RETURNS [class: Class] = BEGIN class _ gZ.NEW[ClassRec _ classInfo]; class.flavor _ flavor; [] _ RefTab.Store[classTable, flavor, class]; OtherNode.Register[flavor, class.readProc, class.writeProc, class.copyProc]; classes _ CONS[class, classes]; END; FetchClass: PUBLIC PROC [flavor: ClassID] RETURNS [class: Class] = {RETURN[NARROW[RefTab.Fetch[classTable, flavor].val]]}; GEditInit: ViewerClasses.InitProc = BEGIN gvd: GEditViewerData; gvd _ self.data _ gZ.NEW[GEditViewerDataRec]; IF self.file#NIL THEN gvd.root _ PutGet.FromFile[self.file ! CIFS.Error => CHECKED {self.newFile _ TRUE; CONTINUE}; GEditIO.MyParent => RESUME[self]; ]; IF gvd.root=NIL THEN gvd.root _ TextEdit.DocFromNode[Nil[]]; ViewerOps.SetMenu[self, gEditMenu, FALSE]; END; Nil: PROC RETURNS [object: Object] = BEGIN object _ TextNode.NewOtherNode[]; object.body _ other [$Nil, NIL]; END; SetSelection: PROC [self: ViewerClasses.Viewer, gvd: GEditViewerData _ NIL, grain: SelectionGrain _ point, objects: SelectedObject _ NIL, x, y: INTEGER _ 0, paint: BOOL _ TRUE] = BEGIN IF selection.displayed AND paint THEN PaintSelection[]; selection^ _ [self, IF self=NIL THEN NIL ELSE gvd, objects, grain, self#NIL, x, y]; IF selection.displayed THEN -- put up new {IF InputFocus.GetInputFocus[].owner#self THEN InputFocus.SetInputFocus[self] ELSE IF paint THEN PaintSelection[]}; END; KillSelection: PROC [paint: BOOL _ TRUE] = BEGIN IF selection.displayed AND paint THEN PaintSelection[]; selection^ _ [NIL, NIL, NIL, point, FALSE]; END; PaintSelection: PROC = BEGIN IF selection.viewer#NIL THEN ViewerOps.PaintViewer[selection.viewer, client, FALSE, $Selection]; END; DrawControlPoint: PUBLIC PROC [context: Graphics.Context, x, y: INTEGER, marking: SelectionGrain] = BEGIN Graphics.SetCP[context, x-SIZE[PtArray]/2, y+SIZE[PtArray]/2]; GraphicsOps.DrawBitmap[context, IF marking=point THEN pointMap ELSE objectMap, 16, SIZE[PtArray]]; END; MarkSelection: PUBLIC PROC [context: Graphics.Context] = BEGIN HighlightObject: PROC [sel: SelectedObject] = BEGIN class: Class ~ NARROW[sel.object.class]; IF class#NIL AND class.selectProc#NIL THEN class.selectProc[sel.object, context, sel.controlPoint, selection.grain]; END; oldPaintMode: Graphics.PaintMode _ Graphics.SetPaintMode[context, invert]; FOR obj: SelectedObject _ selection.objects, obj.nextObject UNTIL obj=NIL DO HighlightObject[obj]; ENDLOOP; [] _ Graphics.SetPaintMode[context, oldPaintMode]; END; GEditModify: ViewerClasses.ModifyProc = BEGIN SELECT change FROM set => PaintSelection[]; kill => KillSelection[]; ENDCASE; END; SelectListFromObject: PROC [object: Object, controlPoint: INTEGER _ 0] RETURNS [sel: SelectedObject] = INLINE BEGIN sel _ NEW [SelectedObjectRec _ [controlPoint, object, NIL]]; END; GEditNotify: ViewerClasses.NotifyProc = BEGIN gvd: GEditViewerData _ NARROW[self.data]; button: Menus.MouseButton _ red; shift, control: BOOL _ FALSE; mouse: TIPUser.TIPScreenCoords; FOR list: LIST OF REF ANY _ input, list.rest UNTIL list = NIL DO WITH list.first SELECT FROM x: ATOM => SELECT x FROM $Blue => button _ blue; $Control => control _ TRUE; $Copy => BEGIN newObject: Object; IF selection.objects=NIL OR selection.objects.nextObject#NIL THEN BEGIN MessageWindow.Append["Please make a single object selection to copy...", TRUE]; MessageWindow.Blink[]; RETURN; END; newObject _ CopyObject[gvd, selection.objects.object]; SetSelection[self, gvd, selection.grain, SelectListFromObject[newObject, selection.objects.controlPoint], selection.caretX, selection.caretY, TRUE]; ViewerOps.PaintViewer[selection.viewer, client, FALSE, $XORSelection]; -- since overlaps old object GEditMotion.Move[mouse.mouseX, mouse.mouseY]; IF ~self.newVersion THEN ViewerOps.SetNewVersion[self]; END; $Delete => DeleteSelection[]; $Move => GEditMotion.Move[mouse.mouseX, mouse.mouseY]; $Next => Next[shift]; $Red => button _ red; $Sampler => BEGIN x: INTEGER _ 10; y: INTEGER ~ 20; FOR c: LIST OF Class _ classes, c.rest UNTIL c=NIL DO IF c.first.newProc#NIL THEN BEGIN object: Object _ EditSpan.InsertOtherNode[gvd.root, TextNode.LastChild[gvd.root]]; object.body _ other [c.first.flavor, NIL]; object.class _ c.first; c.first.newProc[object, x, y, self]; ViewerOps.PaintViewer[self, client, FALSE, object]; x _ x+100; END; ENDLOOP; END; $Shift => shift _ TRUE; $Select => Select[self, gvd, mouse.mouseX, mouse.mouseY, selection.grain]; $SelectExtend => BEGIN object: Object; x, y, controlPoint: INTEGER; [object, controlPoint, x, y] _ Resolve[gvd, mouse.mouseX, mouse.mouseY]; MessageWindow.Append[IF object=NIL THEN "NIL" ELSE SELECT controlPoint FROM 0 => "0", 1 => "1", 2 => "2", ENDCASE => "3", TRUE]; END; $SelectObject => Select[self, gvd, mouse.mouseX, mouse.mouseY, object]; $SelectPoint => Select[self, gvd, mouse.mouseX, mouse.mouseY, point]; $Yellow => button _ yellow; ENDCASE => IF selection.objects#NIL THEN BEGIN paintAll: BOOL _ FALSE; FOR sel: SelectedObject _ selection.objects, sel.nextObject UNTIL sel=NIL DO class: Class ~ NARROW[sel.object.class]; all, me: BOOL _ FALSE; IF class.inputProc#NIL THEN [all, me] _ class.inputProc[sel.object, x]; IF all THEN paintAll _ TRUE ELSE ViewerOps.PaintViewer[self, client, FALSE, sel.object]; ENDLOOP; IF paintAll THEN ViewerOps.PaintViewer[self, client]; END; z: TIPUser.TIPScreenCoords => mouse _ z; ENDCASE => ERROR; ENDLOOP; END; Select: PROC [self: ViewerClasses.Viewer, gvd: GEditViewerData, mx, my: INTEGER, grain: SelectionGrain] = BEGIN object: Object; x, y, controlPoint: INTEGER; [object, controlPoint, x, y] _ Resolve[gvd, mx, my]; IF object#NIL THEN BEGIN IF selection.objects#NIL AND selection.objects.object=object AND selection.objects.nextObject=NIL AND selection.grain=grain AND selection.objects.controlPoint = controlPoint THEN RETURN; -- already selected SetSelection[self, gvd, grain, SelectListFromObject[object, controlPoint], x, y, TRUE]; END ELSE IF selection.viewer#self THEN SetSelection[self, gvd, grain]; END; DeleteSelection: PROC = BEGIN savedSel: SelectedObject ~ selection.objects; savedViewer: ViewerClasses.Viewer ~ selection.viewer; KillSelection[]; FOR obj: SelectedObject _ savedSel, obj.nextObject UNTIL obj=NIL DO Delete[obj.object]; ENDLOOP; ViewerOps.PaintViewer[savedViewer, client]; IF ~savedViewer.newVersion THEN ViewerOps.SetNewVersion[savedViewer]; END; Resolve: PROC [gvd: GEditViewerData, x, y: INTEGER] RETURNS [object: Object, controlPoint, trueX, trueY: INTEGER _ 0] = BEGIN bestAffinitySoFar: INTEGER _ LAST[INTEGER]; tempControlPoint, tempAffinity, tempX, tempY: INTEGER; Affinity: PROC [object: Object] RETURNS [affinity, controlPoint, tx, ty: INTEGER] = BEGIN class: Class ~ NARROW[object.class]; IF class=NIL THEN affinity _ LAST[INTEGER] ELSE [affinity, controlPoint, tx, ty] _ class.resolveProc[object, x, y]; END; trueX _ x; trueY _ y; FOR ref: Object _ TextNode.NarrowToOtherNode[TextNode.FirstChild[gvd.root]], TextNode.NarrowToOtherNode[TextNode.Next[ref]] UNTIL ref=NIL DO [tempAffinity, tempControlPoint, tempX, tempY] _ Affinity[ref]; IF tempAffinity <= bestAffinitySoFar THEN BEGIN -- <= favors top most when equal bestAffinitySoFar _ tempAffinity; object _ ref; controlPoint _ tempControlPoint; trueX _ tempX; trueY _ tempY; END; ENDLOOP; END; Next: PROC [backwards: BOOL] = BEGIN IF selection.objects=NIL THEN BEGIN MessageWindow.Append["Please make a selection first", TRUE]; MessageWindow.Blink[]; RETURN; END; IF selection.objects.nextObject#NIL THEN BEGIN MessageWindow.Append["Sorry, NEXT only works for single selected objects", TRUE]; MessageWindow.Blink[]; RETURN; END; IF selection.grain = point THEN BEGIN class: Class ~ NARROW[selection.objects.object.class]; ViewerOps.PaintViewer[selection.viewer, client, FALSE, $Selection]; selection.objects.controlPoint _ class.nextProc[selection.objects.object, selection.objects.controlPoint, backwards]; ViewerOps.PaintViewer[selection.viewer, client, FALSE, $Selection]; END ELSE BEGIN -- object nextObject: TextNode.Ref _ IF backwards THEN TextNode.Previous[selection.objects.object] ELSE TextNode.Next[selection.objects.object]; IF nextObject=NIL THEN BEGIN MessageWindow.Append[IF backwards THEN "Start of object tree" ELSE "End of object tree", TRUE]; MessageWindow.Blink[]; RETURN; END; SetSelection[selection.viewer, selection.data, selection.grain, SelectListFromObject[TextNode.NarrowToOtherNode[nextObject]], selection.caretX, selection.caretY, TRUE]; -- cx, cy are wrong; these should be computed for new control point!!! END; END; EnumProc: TYPE = PROC [self: Object] ; EnumerateObjects: PROC [gvd: GEditViewerData, enum: EnumProc] = BEGIN FOR ref: Object _ TextNode.NarrowToOtherNode[TextNode.FirstChild[gvd.root]], TextNode.NarrowToOtherNode[TextNode.Next[ref]] UNTIL ref=NIL DO enum[ref]; ENDLOOP; END; gEditClass: ViewerClasses.ViewerClass _ NEW[ViewerClasses.ViewerClassRec _ [ paint: GEditPaint.GEditPainter, init: GEditInit, save: GEditSave, notify: GEditNotify, modify: GEditModify, tipTable: TIPUser.InstantiateNewTIPTable["GEdit.tip"], cursor: crossHairsCircle ]]; Delete: EnumProc = BEGIN class: Class ~ NARROW[self.class]; IF class#NIL AND class.deleteProc#NIL THEN class.deleteProc[self]; EditSpan.Delete[TextNode.Root[self], TextNode.MakeNodeSpan[self, self]]; END; Clear: Menus.MenuProc = BEGIN self: ViewerClasses.Viewer ~ NARROW[parent]; gvd: GEditViewerData ~ NARROW[self.data]; IF selection.viewer=self THEN KillSelection[]; EnumerateObjects[gvd, Delete]; gvd.root _ TextEdit.DocFromNode[Nil[]]; ViewerOps.PaintViewer[self, all]; IF ~self.newVersion THEN ViewerOps.SetNewVersion[self]; END; Reset: Menus.MenuProc = BEGIN self: ViewerClasses.Viewer ~ NARROW[parent]; gvd: GEditViewerData ~ NARROW[self.data]; IF selection.viewer=self THEN KillSelection[]; EnumerateObjects[gvd, Delete]; GEditInit[NARROW[parent]]; IF self.newVersion THEN self.newVersion _ FALSE; ViewerOps.PaintViewer[self, all] END; Store: Menus.MenuProc = BEGIN MessageWindow.Append["Sorry, that's not yet implemented...", TRUE]; END; Load: Menus.MenuProc = BEGIN MessageWindow.Append["Sorry, that's not yet implemented...", TRUE]; END; GEditSave: ViewerClasses.SaveProc = BEGIN gvd: GEditViewerData ~ NARROW[self.data]; dollarFile: REF READONLY TEXT; dollarCap: File.Capability _ File.nullCapability; root: TextNode.Ref ~ gvd.root; file: Rope.ROPE ~ self.file; IF file=NIL THEN BEGIN MessageWindow.Append["Can't SAVE -- no file name!", TRUE]; MessageWindow.Blink[]; ViewerOps.SetNewVersion[self]; -- turn the bit back on RETURN; END; dollarFile _ Rope.ToRefText[Rope.Cat[file, "$"]]; dollarCap _ Directory.LookupUnlimited[fileName: LOOPHOLE[dollarFile] ! Directory.Error => CONTINUE]; IF dollarCap#File.nullCapability THEN Directory.RemoveFile[LOOPHOLE[dollarFile], dollarCap]; Directory.Rename[LOOPHOLE[Rope.ToRefText[file]], LOOPHOLE[dollarFile] ! Directory.Error => CONTINUE]; [] _ PutGet.ToFile[file, root]; IF dollarCap#File.nullCapability THEN Process.Detach[FORK ReclaimDollarFile[dollarCap]]; END; ReclaimDollarFile: PROC [file: File.Capability] = {File.Delete[file ! ABORTED => CONTINUE]}; CopyObject: PROC [gvd: GEditViewerData, object: Object] RETURNS [newObject: Object] = BEGIN newObject _ EditSpan.InsertOtherNode[gvd.root, TextNode.LastChild[gvd.root]]; newObject.class _ object.class; newObject.body _ other [object.variety, OtherNode.CopyInfo[object]]; END; PtArray: TYPE = ARRAY [0..6) OF UNSPECIFIED; objectMap: GraphicsOps.BitmapRef _ NEW[GraphicsOps.BitmapRep _ [base: NEW[PtArray _ [176000B, 102000B, 102000B, 102000B, 102000B, 176000B]], raster: (SIZE[PtArray]+15)/16, width: SIZE[PtArray], height: SIZE[PtArray] ]]; pointMap: GraphicsOps.BitmapRef _ NEW[GraphicsOps.BitmapRep _ [base: NEW[PtArray _ [176000B, 176000B, 176000B, 176000B, 176000B, 176000B]], raster: (SIZE[PtArray]+15)/16, width: SIZE[PtArray], height: SIZE[PtArray] ]]; classTable: RefTab.Ref _ RefTab.Create[mod:32]; -- hold GEdit classes gEditMenu: Menus.Menu _ Menus.CreateMenu[]; Menus.AppendMenuEntry[gEditMenu, Menus.CreateEntry[name: "Clear", proc: Clear, documentation: "Destroy contents...", guarded: FALSE]]; Menus.AppendMenuEntry[gEditMenu, Menus.CreateEntry[name: "Reset", proc: Reset, documentation: "Read from file...", guarded: FALSE]]; Menus.AppendMenuEntry[gEditMenu, Menus.CreateEntry[name: "Store", proc: Store, documentation: "Store contents to file...", guarded: FALSE]]; Menus.AppendMenuEntry[gEditMenu, Menus.CreateEntry[name: "Load", proc: Load, documentation: "Read contents from a file...", guarded: FALSE]]; Menus.AppendMenuEntry[gEditMenu, Menus.CreateEntry[name: "Save", proc: ViewerMenus.Save, documentation: "Save contents to file...", guarded: FALSE]]; ViewerOps.RegisterViewerClass[$Graphics, gEditClass]; -- plug in to Viewers END. tGEditViewerImpl.mesa; Edited by McGregor on December 15, 1982 1:04 pm move selection through data structure ΚΦ– "Mesa" style˜JšΟc,œ™EJ™šΟk ˜ Jšžœžœ ˜Jšœ žœ˜)Jšœ žœ.˜=Jšœžœ&˜0Jšœ ˜ Jšœžœ ˜Jšœ žœ˜Jšœ žœ˜ Jšœ ˜ Jšœ ˜ Jšœ žœ+˜9Jšœ žœ$˜5Jšœ žœ ˜0JšœžœI˜TJšœžœ˜$Jšœ žœ˜%Jšœžœ ˜Jšœžœ˜ Jšœžœ˜)Jšœžœžœ ˜"Jšœ žœ ˜Jšœ žœ˜Jšœ žœc˜qJšœžœ+˜8JšœžœS˜fJšœ žœ˜Jšœ žœ<˜KJ˜—Jšœž˜J˜Jšžœžœβ˜ξJšžœ˜"J˜Jšžœžœ˜%J˜Jšœžœ"˜*J˜Jšœ žœ žœ˜0J˜Jšœ žœžœ žœ˜J˜š Οn œžœžœ(žœž˜`Jšœ žœ˜%Jšœ˜J˜-JšœL˜LJšœ žœ˜Jšžœ˜—J˜šŸ œžœžœžœ˜BJšœžœžœ)˜7—J˜šœ$ž˜)Jšœ˜Jšœžœ˜-šžœ žœžœ%˜:š œžœ žœžœžœ˜8Jšœžœ˜!Jšœ˜——Jšžœ žœžœ(˜Jš œ žœžœ žœžœ ˜bJšžœ˜J˜—šŸ œžœžœž˜>šŸœžœž˜3Jšœžœ˜(š žœžœžœžœž˜*JšœI˜I—Jšžœ˜—JšœJ˜Jšžœ9žœžœž˜LJšœ˜Jšžœ˜—Jšœ2˜2Jšžœ˜—J˜šœ(ž˜-šžœž˜Jšœ˜Jšœ˜Jšžœ˜—Jšžœ˜—š œŸœžœ žœžœžœž˜tJšœžœ-žœ˜