<> <> <> <> <<>> <> <<>> DIRECTORY BiScrollers USING [BiScroller, ClientDataOf, QuaBiScroller, QuaViewer], Commander USING [CommandProc, Register], CommandTool USING [ArgumentVector, Failed, Parse, StarExpansion], Cursors USING [CursorArray, CursorType, NewCursor], FileNames USING [CurrentWorkingDirectory, ResolveRelativePath, Directory], Geom2D USING [Rect, Vec, ExtremaOfRect, Transform, id], ImagerTransformation USING [PostTranslate], Process USING [Detach, MsecToTicks, SetTimeout], Real USING [FixI], Rope USING [Concat, Length, ROPE], ViewerOps USING [PaintViewer], TIPUser USING [InstantiateNewTIPTable, TIPTable], ViewerClasses USING [DestroyProc, Viewer], SilBiScrollers, SilFile, SilDisplay, SilDisplayUtils, SilKernel, SilUserInput ; SilKernelImpl: CEDAR MONITOR IMPORTS BiScrollers, Cursors, Commander, CommandTool, FileNames, Geom2D, ImagerTransformation, Process, SilFile, ViewerOps, Real, Rope, SilBiScrollers, SilDisplay, SilKernel, SilUserInput, SilDisplayUtils, TIPUser EXPORTS SilKernel = BEGIN SilData: TYPE = SilKernel.SilData; maxInstances: NAT _ 0; --keep non-decreasing count for viewer naming numberOfSilInstances: NAT _ 0; <> caretTimeout: CONDITION; <> SilDataList: TYPE = LIST OF SilData; silDatas: SilDataList _ NIL; --list of all sil's in the world SilError: PUBLIC ERROR [explain: SilKernel.SilErrorType] = CODE; InitSil: PROC [] = { <> <> MakeSilClass[]; <> SilFile.InitSil[]; SilDisplay.InitSil[]; }; StartSilInstance: PUBLIC ENTRY PROC [fileName: Rope.ROPE] = { <> <<>> data: SilData _ NEW[SilKernel.SilDataObject]; viewer: ViewerClasses.Viewer _ SilDisplay.InitSilDisplayInstance[data, fileName, maxInstances ! SilKernel.SilError => GOTO NotFound]; <> silDatas _ CONS[data, silDatas]; -- save models for repainting if fonts change TRUSTED {Process.Detach [FORK SilMain[data, viewer] ]}; IF numberOfSilInstances = 0 THEN TRUSTED {Process.Detach [FORK Carets[] ]}; numberOfSilInstances _ numberOfSilInstances + 1; maxInstances _ maxInstances + 1; EXITS NotFound => NULL; }; RepaintSilViewers: PUBLIC ENTRY PROC = { <> <<>> fudge: REAL = 10.0; -- fudge factor for EraseArea needed to catch all descenders in fonts xMin, yMin, xMax, yMax: INTEGER _ 0; rect: Geom2D.Rect _ [0.0, 0.0, 0.0, 0.0]; FOR d: SilDataList _ silDatas, d.rest UNTIL d=NIL DO IF d.first.mainProcessShouldStop THEN LOOP; -- already deleted Sil viewer rect _ SilDisplayUtils.BoundingBoxOfModel[dData: d.first.displayData, model: d.first.model, mapArea: FALSE]; -- Returns RECORD [x, y, w, h: REAL] <> FOR s: SilFile.SilObject _ SilFile.GetObjectList[d.first.model, fgnd], s.rest UNTIL s=NIL DO IF s.first.font IN SilFile.InternalPresetFonts THEN { [xMin: , yMin: , xMax: xMax, yMax: yMax] _ SilDisplayUtils.BoundingBoxOfObject[d.first.model, s.first]; s.first.xMax _ s.first.xMin+xMax; s.first.yMax _ s.first.yMin+yMax; }; ENDLOOP; IF NOT SilUserInput.GetBiScroller[d.first.uiData].QuaViewer[].parent.iconic THEN { SilUserInput.Enque[[EraseArea[Real.FixI[rect.x-fudge], Real.FixI[rect.y-fudge], Real.FixI[rect.x+rect.w+fudge], Real.FixI[rect.y+rect.h+fudge]]], d.first.uiData]; rect _ SilDisplayUtils.BoundingBoxOfModel[dData: d.first.displayData, model: d.first.model, mapArea: FALSE]; --get NEW bounding box, which has changed due to new fonts SilUserInput.Enque[[MergeArea[Real.FixI[rect.x-fudge], Real.FixI[rect.y-fudge], Real.FixI[rect.x+rect.w+fudge], Real.FixI[rect.y+rect.h+fudge]]], d.first.uiData]; }; ENDLOOP; <> SilFile.EvaluateSelection[]; }; SilMain: PROC [data: SilData, viewer: ViewerClasses.Viewer] = { <> WHILE NOT data.mainProcessShouldStop DO IF SilUserInput.InputAvailable[data.uiData] THEN IF NOT viewer.parent.iconic THEN ViewerOps.PaintViewer[viewer: viewer, hint: client, clearClient: FALSE, whatChanged: $UserInput] ELSE NULL ELSE IF SilUserInput.ShouldChangeCaret[data.uiData] THEN { IF NOT viewer.parent.iconic THEN ViewerOps.PaintViewer[viewer: viewer, hint: client, clearClient: FALSE, whatChanged: $Carets]; SilUserInput.CaretHasChanged[data.uiData]; } ELSE IF SilDisplay.NeedRebuild[data.displayData] THEN IF NOT viewer.parent.iconic THEN ViewerOps.PaintViewer[viewer: viewer, hint: client, clearClient: FALSE, whatChanged: $Rebuild] ELSE SilDisplay.CancelRebuild[data.displayData] ELSE SilUserInput.AwaitUserInput[data.uiData]; ENDLOOP; }; Carets: PROC [] = { --Carets is forked so is not an ENTRY Proc <> <<>> quarterSec: INTEGER = 250; --(msecs) SetCaretBlinkInterval[quarterSec]; WHILE numberOfSilInstances > 0 DO RestCaret[]; SilDisplay.CaretBlink[]; ENDLOOP; }; SetCaretBlinkInterval: ENTRY PROC [msecs: INTEGER] = { <> <<>> ENABLE UNWIND => NULL; TRUSTED {Process.SetTimeout[@caretTimeout, Process.MsecToTicks[msecs]];}; }; RestCaret: ENTRY PROC [] = { <> ENABLE UNWIND => NULL; WAIT caretTimeout; }; SilDestroy: ViewerClasses.DestroyProc = { <<[self: Viewer]>> SilEntryDestroy[self: self]; }; <<>> SilEntryDestroy: ENTRY PROC [self: ViewerClasses.Viewer] = { <> <> <<>> data: SilData _ NARROW[BiScrollers.QuaBiScroller[self].ClientDataOf[]]; data.mainProcessShouldStop _ TRUE; SilUserInput.DestroyUserInput[data.uiData]; numberOfSilInstances _ numberOfSilInstances - 1; }; SilExtremaProc: PROC [clientData: REF ANY, direction: Geom2D.Vec] RETURNS [min, max: Geom2D.Vec] --BiScrollers.ExtremaProc-- = { <> data: SilData _ NARROW[clientData]; area: Geom2D.Rect; area _ SilDisplayUtils.BoundingBoxOfModel[dData: data.displayData, model: data.model, mapArea: TRUE]; [min, max] _ Geom2D.ExtremaOfRect[r: area, n: direction]; }; SilBasicTransformProc: PROC [bs: BiScrollers.BiScroller] RETURNS [t: Geom2D.Transform] --BiScrollers.TransformGenerator-- = { iv: ViewerClasses.Viewer _ bs.style.QuaViewer[bs: bs, inner: TRUE]; t _ Geom2D.id.PostTranslate[[0, iv.ch]]; < appear at the upper left corner of viewer.>> }; MakeSilClass: PROC [] = { <> <<>> myCursorBits: Cursors.CursorArray = [177700B, 177600B, 177400B, 177000B, 177400B, 177600B, 177700B, 167740B, 143760B, 101770B, 774B, 376B, 177B, 76B, 34B, 10B]; myCursor: Cursors.CursorType _ Cursors.NewCursor[myCursorBits]; tipTable: TIPUser.TIPTable _ TIPUser.InstantiateNewTIPTable["Sil.tip"]; SilUserInput.InitTipTable[tipTable]; SilBiScrollers.silClass _ SilBiScrollers.bsStyle.NewBiScrollerClass [[flavor: $Sil, extrema: SilExtremaProc, notify: SilUserInput.SilNotify, paint: SilDisplay.SilPaintProc, --call SilPaint when viewer needs to be repainted modify: SilUserInput.SilModifyInputFocus, --Call when input focus is taken destroy: SilDestroy, finish: LIST[$Exit], save: SilDisplay.SilSaveProc, tipTable: tipTable, cursor: myCursor, mayStretch: FALSE, offsetsMustBeIntegers: TRUE, preferIntegerCoefficients: TRUE, -- integer coefficients in transform vanilla: SilBasicTransformProc, --proc which provides the basic transform for BiScrollers preserve: [X: 0, Y: 1] --this specifies point that stays fixed when viewer size changes ]]; }; StartSilCommand: Commander.CommandProc = { <<[cmd: Handle]>> <<>> argv: CommandTool.ArgumentVector; name, dir: Rope.ROPE; CommandTool.StarExpansion[cmd]; argv _ CommandTool.Parse[cmd ! CommandTool.Failed => CONTINUE; ]; IF argv = NIL THEN RETURN[$Failure, "Sil initialization procedure is confused"]; IF argv.argc < 2 THEN { --Sil called with no file name given. StartSilInstance[fileName: ""]; RETURN; }; FOR i: NAT IN [1..argv.argc) DO --open a sil window on each file given name _ FileNames.ResolveRelativePath[argv[i]]; dir _ FileNames.Directory[name]; IF Rope.Length[dir] = 0 THEN name _ Rope.Concat[FileNames.CurrentWorkingDirectory[], name]; StartSilInstance[fileName: name]; ENDLOOP; }; <<>> <> <<>> InitSil[]; Commander.Register[key: "Sil", proc: StartSilCommand, doc: "Create a Window Sil Instance" ]; END.