DIRECTORY <>AtomButtons, BiScrollers, BufferedRefresh, <> CedarProcess, ChoiceButtons, Commander, CommanderOps, Cursors, FileNames, FS, FunctionCache, Geom2D, Icons, Imager, ImagerBackdoor, ImagerBox, <> ImagerFont, ImagerMaskCapture, ImagerMemory, ImagerTransformation, InterpressInterpreter, IO, IPMaster, MessageWindow, MJSContainers, <> <> Real, RefText, Rope, RuntimeError, SF, SlackProcess, Sliders, TiogaAccess, TiogaAccessViewers, TiogaMenuOps, TIPUser, Vectors2d, ViewerClasses, ViewerOps, ViewerSpecs, ViewerTools; SlideShowImpl: CEDAR MONITOR IMPORTS <> AtomButtons, BiScrollers, BufferedRefresh, CedarProcess, ChoiceButtons, Commander, CommanderOps, FileNames, FS, FunctionCache, Geom2D, Icons, Imager, ImagerBox, ImagerBackdoor, <> ImagerFont, ImagerMaskCapture, ImagerMemory, ImagerTransformation, InterpressInterpreter, IO, IPMaster, MessageWindow, MJSContainers, <> <> Real, RefText, Rope, RuntimeError, SlackProcess, Sliders, TIPUser, TiogaAccess, TiogaAccessViewers, TiogaMenuOps, Vectors2d, ViewerOps, ViewerSpecs, ViewerTools = BEGIN release: BOOL ฌ TRUE; ButtonLineEntry: TYPE = AtomButtons.ButtonLineEntry; PopUpChoices: TYPE = AtomButtons.PopUpChoices; CacheKey: TYPE ~ REF CacheKeyRep; CacheKeyRep: TYPE ~ RECORD [ fileName: Rope.ROPE, pageNumber: INTEGER ]; CacheVal: TYPE ~ REF CacheValRep; CacheValRep: TYPE ~ RECORD [ iMemContext: ImagerMemory.Context, boundRect: Imager.Rectangle, cToV: Imager.Transformation ]; globalCache: FunctionCache.Cache = FunctionCache.Create[maxEntries: 20]; buttonFont: Rope.ROPE = "xerox/tiogafonts/helvetica18b"; popupFont: Rope.ROPE = "xerox/tiogafonts/helvetica18bi"; cribFont: Rope.ROPE = "xerox/tiogafonts/helvetica8b"; fontScale: REAL = 1.0; buttonLines: INTEGER = 2; buttonLineHeight: INTEGER = 22; cribLineHeight: INTEGER = 12; bsY: INTEGER = (buttonLines*buttonLineHeight)+cribLineHeight+9; indent: INTEGER = 2; -- indents buttons from left edge for cleaner look pointsPerMeter: REAL = 72.0/.0254; SSButtonFont: Imager.Font = Imager.FindFontScaled[buttonFont, fontScale]; SSPopupFont: Imager.Font = Imager.FindFontScaled[popupFont, fontScale]; SSCribFont: Imager.Font = Imager.FindFontScaled[cribFont, fontScale]; visibleGrey: Imager.Color = ImagerBackdoor.MakeStipple[122645B]; invisibleGrey: Imager.Color = ImagerBackdoor.MakeStipple[100040B]; nullBox: Imager.Box = [-Real.LargestNumber, -Real.LargestNumber, Real.LargestNumber, Real.LargestNumber]; nullRect: Imager.Rectangle = [-Real.LargestNumber, -Real.LargestNumber, Real.LargestNumber, Real.LargestNumber]; Data: TYPE = REF Rep; Rep: TYPE = RECORD [ wDir: Rope.ROPE, slackHandle: SlackProcess.SlackHandle, sandwich: BufferedRefresh.Sandwich, useBR: BOOL ฌ TRUE, aborted: BOOL ฌ FALSE, fileName: Rope.ROPE, container: ViewerClasses.Viewer, pageNumberViewer: ViewerClasses.Viewer, pageNumberSlider: ViewerClasses.Viewer, fileNameViewer: ViewerClasses.Viewer, biScroller: BiScrollers.BiScroller, view: ViewerClasses.Viewer, -- the BiScroller inner viewer startScroll: Imager.VEC ฌ [0.0, 0.0], startPage: Imager.VEC ฌ [0.0, 0.0], op: ATOM ฌ $Idle, where: Imager.VEC ฌ [0.0, 0.0], pageNumber: INTEGER ฌ 1, lastPageNumber: INTEGER ฌ 0, master: InterpressInterpreter.Master, pageInMem: INTEGER ฌ 0,-- which page is in iMemContext. iMemContext: Imager.Context, -- an ImagerMemory context boundRect: Imager.Rectangle ฌ nullRect, oldClip: Imager.Box ฌ nullBox, <> stream: IO.STREAM ]; Message: PROC [r: Rope.ROPE, clearFirst, blink: BOOL ฌ TRUE] ~ { MessageWindow.Append[r, clearFirst]; IF blink THEN MessageWindow.Blink[]; }; SSButtonHandleProc: AtomButtons.HandleButtonProc ~ { atom: ATOM ฌ NARROW[event.first]; [] ฌ CedarProcess.Fork[action: SELECT atom FROM $SSBigger => Bigger, $SSSmaller => Smaller, $SSReset => Vanilla, $SSToAll => ToAll, $SSFillAll => FillAll, $SSResetAll => ResetAll, $SSFill => Fill, $SSGet => Get, $SSHelp => Help, $SSResize => Resize, ENDCASE => Unknown, data: clientData]; }; Lookup: PROC [d: Data, forPage: INTEGER ฌ 0] RETURNS [val: CacheVal] ~ { PageCompareProc: FunctionCache.CompareProc ~ TRUSTED { IF argument=NIL THEN RETURN[FALSE] ELSE { key: CacheKey ฌ NARROW[argument]; RETURN[key.fileName=d.fileName AND key.pageNumber= (IF forPage=0 THEN d.pageNumber ELSE forPage)]; }; }; val ฌ NARROW[FunctionCache.Lookup[x: globalCache, compare: PageCompareProc, clientID: $SSPage].value]; }; GetCachedTransform: PROC [d: Data] RETURNS [cToV: Imager.Transformation] ~ { val: CacheVal ฌ Lookup[d]; IF val#NIL THEN cToV ฌ val.cToV; }; CacheViewingTransform: PROC [d: Data] ~ { val: CacheVal ฌ Lookup[d]; IF val#NIL THEN val.cToV ฌ bsStyle.GetTransforms[bs: d.biScroller].clientToViewer; -- get the new viewing transforms }; Bigger: CedarProcess.ForkableProc ~ { d: Data ฌ NARROW[data]; IF d.fileName=NIL THEN {Message["No slides loaded. Can't make Bigger."]; RETURN;}; BiScrollers.Scale[d.biScroller, [byArg[1.2]] ]; -- bigger by 20% }; Smaller: CedarProcess.ForkableProc ~ { d: Data ฌ NARROW[data]; IF d.fileName=NIL THEN {Message["No slides loaded. Can't make Smaller."]; RETURN;}; BiScrollers.Scale[d.biScroller, [byArg[1.0/1.2]] ]; -- smaller by 20% }; Fill: CedarProcess.ForkableProc ~ { rx, ry: REAL; -- ratios in X and Y w, cw, h, ch: REAL; -- conversions from integer fudge: REAL = 0.96; -- fudge factor d: Data ฌ NARROW[data]; cacheVal: CacheVal ฌ Lookup[d]; IF d.fileName=NIL OR cacheVal=NIL THEN { Message["No slides loaded. Can't Fill."]; RETURN; }; Message[IO.PutFR1["Filling page %g . . . please wait.", IO.int[d.pageNumber]], TRUE, FALSE]; IF cacheVal.boundRect.x#nullRect.x THEN d.boundRect ฌ cacheVal.boundRect -- yes ELSE { -- no. Calculate it. PlayFake: PROC [cc: Imager.Context] = { ImagerMemory.Replay[cacheVal.iMemContext, cc]; }; sfBox: SF.Box ฌ SF.maxBox; -- [min: minVec, max: maxVec] sfBox ฌ ImagerMaskCapture.CaptureBounds[PlayFake, ImagerTransformation.Scale[2.0] ! ImagerMaskCapture.Cant => RESUME]; d.boundRect ฌ cacheVal.boundRect ฌ IF sfBox.min=SF.minVec THEN nullRect ELSE ImagerTransformation.InverseTransformRectangle[ImagerTransformation.Scale[2.0], ImagerBox.RectangleFromBox[[sfBox.min.s, sfBox.min.f, sfBox.max.s, sfBox.max.f]]]; -- Michael Plass magic }; w ฌ d.boundRect.w; cw ฌ d.sandwich.cw; h ฌ d.boundRect.h; ch ฌ d.sandwich.ch; rx ฌ cw/w; -- possible scaling ratio ry ฌ ch/h; -- another possible scaling ratio BiScrollers.DoBSUserAction[d.biScroller, LIST[$First, $Vanilla] ]; -- standard transformation. Don't paint BiScrollers.Align[bs: d.biScroller, client: [coord[x: d.boundRect.x+(w/2.0), y: d.boundRect.y+h]], viewer: [fraction[fx: 0.50, fy: 1.00]], paint: FALSE ]; BiScrollers.Scale[bs: d.biScroller, op: [byArg[arg: fudge*MIN[rx, ry]]], paint: FALSE ]; BiScrollers.Shift[bs: d.biScroller, dx: 0.0, dy: -4, paint: TRUE ]; Message[IO.PutFR1[" Page %g fill completed.", IO.int[d.pageNumber]], FALSE, FALSE]; }; Vanilla: CedarProcess.ForkableProc ~ { d: Data ฌ NARROW[data]; BiScrollers.DoBSUserAction[d.biScroller, LIST[$Vanilla] ]; -- standard transformation }; ToAll: CedarProcess.ForkableProc ~ { d: Data ฌ NARROW[data]; IF d.fileName=NIL THEN Message["No slides loaded. Can't do ToAll."] ELSE { -- set all page view transforms to the current transform cToV: Imager.Transformation ฌ bsStyle.GetTransforms[bs: d.biScroller].clientToViewer; thisPage: INTEGER ฌ d.pageNumber; FOR nextPage: INTEGER ฌ thisPage+1, nextPage+1 UNTIL nextPage>d.lastPageNumber DO bsStyle.ChangeTransform[bs: d.biScroller, new: cToV, ageOp: remember, paint: FALSE]; PaintView[d: d, op: $View]; DeltaPage[d: d, newPage: nextPage, paint: TRUE]; -- forces current page to cache transform ENDLOOP; FOR nextPage: INTEGER ฌ 1, nextPage+1 UNTIL nextPage>thisPage DO bsStyle.ChangeTransform[bs: d.biScroller, new: cToV, ageOp: remember, paint: FALSE]; PaintView[d: d, op: $View]; DeltaPage[d: d, newPage: nextPage, paint: TRUE]; -- forces current page to cache transform ENDLOOP; Message["ToAll completed.", TRUE, FALSE]; }; }; ResetAll: CedarProcess.ForkableProc ~ { d: Data ฌ NARROW[data]; IF d.fileName=NIL THEN Message["No slides loaded. Can't do ResetAll."] ELSE { -- set all page view transforms to the vanilla transform thisPage: INTEGER ฌ d.pageNumber; FOR nextPage: INTEGER ฌ thisPage+1, nextPage+1 UNTIL nextPage>d.lastPageNumber DO BiScrollers.DoBSUserAction[d.biScroller, LIST[$First, $Vanilla] ]; -- standard transformation PaintView[d: d, op: $View]; DeltaPage[d: d, newPage: nextPage, paint: TRUE]; -- forces current page to cache transform ENDLOOP; FOR nextPage: INTEGER ฌ 1, nextPage+1 UNTIL nextPage>thisPage DO BiScrollers.DoBSUserAction[d.biScroller, LIST[$First, $Vanilla] ]; -- standard transformation PaintView[d: d, op: $View]; DeltaPage[d: d, newPage: nextPage, paint: TRUE]; -- forces current page to cache transform ENDLOOP; Message["ResetAll completed.", TRUE, FALSE]; }; }; FillAll: CedarProcess.ForkableProc ~ { d: Data ฌ NARROW[data]; IF d.fileName=NIL THEN Message["No slides loaded. Can't do FillAll."] ELSE { -- fill and display each page thisPage: INTEGER ฌ d.pageNumber; FOR nextPage: INTEGER ฌ thisPage+1, nextPage+1 UNTIL nextPage>d.lastPageNumber DO [] ฌ Fill[data]; PaintView[d: d, op: $View]; DeltaPage[d: d, newPage: nextPage, paint: TRUE]; -- forces current page to cache transform ENDLOOP; FOR nextPage: INTEGER ฌ 1, nextPage+1 UNTIL nextPage>thisPage DO [] ฌ Fill[data]; PaintView[d: d, op: $View]; DeltaPage[d: d, newPage: nextPage, paint: TRUE]; -- forces current page to cache transform ENDLOOP; Message["FillAll completed.", TRUE, FALSE]; }; }; Match: ENTRY PROC [s: IO.STREAM, r: Rope.ROPE] RETURNS [BOOL] = { IO.SetIndex[s, 0]; buffer.length ฌ IO.GetBlock[s, buffer, 0, 10]; RETURN[Rope.Match[Rope.Concat[r, "*"], RefText.TrustTextAsRope[buffer], FALSE]]; }; Get: CedarProcess.ForkableProc ~ { Reset: PROC [restoreCursor: BOOL ฌ TRUE] = { defaultGet ฌ NIL; -- only one shot at default per invocation d.fileName ฌ NIL; d.pageNumber ฌ 1; d.lastPageNumber ฌ 0; d.container.name ฌ "SlideShow"; d.container.label ฌ "SlideShow"; d.container.file ฌ NIL; d.boundRect ฌ nullRect; d.oldClip ฌ nullBox; IF d.master#NIL THEN {InterpressInterpreter.Close[d.master]; d.master ฌ NIL;}; d.pageInMem ฌ 0; d.iMemContext ฌ NIL; <> IF d.stream#NIL THEN {d.stream.Close[]; d.stream ฌ NIL;}; SetBigAndBold[d.pageNumberViewer, "0 of 0"]; Sliders.SetContents[d.pageNumberSlider, 0]; ViewerOps.PaintViewer[viewer: d.container, hint: all, clearClient: TRUE]; IF restoreCursor THEN ChangeCursor[d.view, crossHairsCircle]; }; fullName: Rope.ROPE; bytes: INT ฌ -1; d: Data ฌ NARROW[data]; fileName: Rope.ROPE ฌ IF defaultGet#NIL THEN defaultGet ELSE ViewerTools.GetContents[d.fileNameViewer]; ViewerTools.SetContents[d.fileNameViewer, fileName, FALSE]; BEGIN -- so the EXITS can use the above variables dot: INT ฌ 0; IF Rope.Equal[fileName, NIL] THEN GOTO NoFileName; ChangeCursor[d.view, hourGlass]; [fullFName: fullName, bytes: bytes] ฌ FS.FileInfo[name: fileName, wDir: d.wDir ! FS.Error => CONTINUE]; IF bytes=-1 THEN GOTO NotFound; Message[IO.PutFR1["Trying %g . . . ", IO.rope[fullName]], TRUE, FALSE]; Reset[FALSE]; -- immediately clear the viewer for user feedback. Don't change the cursor. d.stream ฌ FS.StreamOpen[fileName: fullName, wDir: d.wDir ! FS.Error => GOTO StreamOpenFail]; SELECT TRUE FROM Match[d.stream, "Interpress"] => { -- IP file d.master ฌ InterpressInterpreter.FromStream[stream: d.stream, log: IPLogError ! FS.Error => { Message[Rope.Cat[error.explanation, " for ", fullName]]; GOTO Quit; }; IPMaster.Error => { --ErrorDesc: TYPE = RECORD[code: ATOM, explanation: ROPE, index: INT ฌ 0] Message[Rope.Cat[error.explanation, " for ", fullName]]; GOTO Quit; }; Imager.Error => { --ErrorDesc: TYPE = RECORD [code: ATOM, explanation: ROPE] Message[Rope.Cat[error.explanation, " for ", fullName]]; GOTO Quit; }; IO.Error, IO.EndOfStream => { Message[Rope.Concat["IO Stream Error for ", fullName]]; GOTO Quit; }; RuntimeError.UnnamedError => { Message[Rope.Concat["Unnamed Error for IP master ", fullName]]; GOTO Quit; }; ]; IF d.master.pages=0 THEN { Message[Rope.Concat["Zero pages in ", fullName]]; GOTO Quit; }; d.lastPageNumber ฌ d.master.pages; d.pageInMem ฌ 0; d.iMemContext ฌ NIL; [] ฌ FunctionCache.Obtain[globalCache, FunctionCache.Any, 9999, $SSPage]; }; NOT release <> => { -- PS file <> IO.SetIndex[d.stream, 0]; d.lastPageNumber ฌ 1; }; ENDCASE => GOTO NotPDL; d.pageNumber ฌ 1; d.fileName ฌ fullName; d.container.name ฌ fullName; d.container.file ฌ fullName; d.container.label ฌ FileNames.GetShortName[fullName]; IF (dot ฌ Rope.Find[d.container.label, "."])#-1 THEN d.container.label ฌ Rope.Substr[d.container.label, 0, dot]; BiScrollers.DoBSUserAction[d.biScroller, LIST[$Vanilla] ]; ViewerOps.PaintViewer[viewer: d.container, hint: caption, clearClient: FALSE]; DeltaPage[d, 1, FALSE]; Message[IO.PutFR["success. %g slide%g.", IO.int[d.lastPageNumber], IF d.lastPageNumber=1 THEN IO.rope[""] ELSE IO.rope["s"] ], FALSE, FALSE ]; ChangeCursor[d.view, crossHairsCircle]; EXITS NoFileName => { Message["No file name. Fill in FILE field and retry."]; Reset[]; }; NotFound => { Message[Rope.Concat["Could not find ", fileName]]; Reset[]; }; StreamOpenFail => { Message[Rope.Concat["Could not open ", fullName]]; Reset[]; }; NotPDL => { Message[Rope.Cat[fullName, " is not an ", pdls, " file"]]; Reset[]; }; Quit => Reset[]; END; }; <> Help: CedarProcess.ForkableProc ~ { goodHeight: INTEGER = ViewerSpecs.openTopY-ViewerSpecs.openBottomY-bsY; help: ViewerClasses.Viewer; helpName: Rope.ROPE = FileNames.ConvertToSlashFormat[FS.ExpandName[helpFile, helpWDir ].fullFName]; IF (help ฌ ViewerOps.FindViewer[helpName])=NIL THEN { -- create new help file viewer and load help file help ฌ ViewerOps.CreateViewer[flavor: $Text, info: [iconic: TRUE, column: left, openHeight: goodHeight], paint: FALSE]; TiogaMenuOps.Load[viewer: help, fileName: helpName]; } ELSE IF help.column#left THEN ViewerOps.ChangeColumn[help, left]; -- viewer already exists IF help.file#NIL THEN { IF help.iconic THEN ViewerOps.OpenIcon[icon: help, closeOthers: FALSE, paint: FALSE]; ViewerOps.SetOpenHeight[help, goodHeight]; ViewerOps.ComputeColumn[left]; ViewerTools.InhibitUserEdits[help]; ViewerOps.PaintViewer[viewer: help, hint: all]; -- make viewer appear } ELSE { Message["Could not find or open Slideshow HELP"]; ViewerOps.DestroyViewer[help, FALSE]; }; }; Resize: CedarProcess.ForkableProc ~ { d: Data ฌ NARROW[data]; wide: BOOL ฌ d.container.cw > ViewerSpecs.bwScreenWidth - leaveRight; ViewerOps.MoveBoundary[newLeftWidth: ViewerSpecs.bwScreenWidth - (IF wide THEN leaveRight ELSE 4), newBottomY: IF wide THEN ViewerSpecs.iconRowHeight ELSE 4]; }; Unknown: CedarProcess.ForkableProc ~ { Message["Slideshow saw unknown button ATOM"]; }; FilePressed: ChoiceButtons.SelectionNotifierProc = { d: Data ฌ NARROW[clientdata]; ViewerTools.SetSelection[d.fileNameViewer]; }; OptimizeQueue: SlackProcess.OptimizeProc = { atom, nextAtom: ATOM; action: LIST OF REF ANY; IF actionsOnQueue < 2 THEN RETURN [0]; skipActions ฌ 0; FOR i: NAT IN [0..actionsOnQueue-2] DO action ฌ NARROW[SlackProcess.GetQueueEntry[qeGen, i].inputAction]; atom ฌ NARROW[action.first]; action ฌ NARROW[SlackProcess.GetQueueEntry[qeGen, i+1].inputAction]; nextAtom ฌ NARROW[action.first]; IF atom = nextAtom THEN { skipActions ฌ skipActions + 1; } ELSE RETURN; ENDLOOP; }; SSFlush: Commander.CommandProc = { FunctionCache.Flush[globalCache]; }; CreateSlideShow: Commander.CommandProc = { args: LIST OF Rope.ROPE; argLength: NAT ฌ 0; filePrompt: ChoiceButtons.PromptDataRef; nextX: INTEGER ฌ 0; d: Data ฌ NEW[Rep]; getButton: ButtonLineEntry ฌ [button[name: "Get", events: LIST[LIST[$SSGet]], border: TRUE, font: SSButtonFont]]; biggerButton: ButtonLineEntry ฌ [button[name: "Bigger", events: LIST[LIST[$SSBigger]], border: TRUE, font: SSButtonFont]]; smallerButton: ButtonLineEntry ฌ [button[name: "Smaller", events: LIST[LIST[$SSSmaller]], border: TRUE, font: SSButtonFont]]; fillButton: ButtonLineEntry ฌ [button[name: "Fill", events: LIST[LIST[$SSFill]], border: TRUE, font: SSButtonFont]]; resetButton: ButtonLineEntry ฌ [button[name: "Reset", events: LIST[LIST[$SSReset]], border: TRUE, font: SSButtonFont]]; xformChoices: PopUpChoices ฌ LIST[ [LIST[$SSToAll], "ToAll", "Copy current view transformation to each page"], [LIST[$SSFillAll], "FillAll", "Fill each page individually"], [LIST[$SSResetAll], "ResetAll", "Reset view transformation for each page"] ]; xformButton: ButtonLineEntry ฌ [popUpButton[name: "Views", choices: xformChoices, border: TRUE, font: SSPopupFont, disableDecoding: TRUE]]; atButton: ButtonLineEntry ฌ [label[name: "At slide: ", font: SSButtonFont]]; helpButton: ButtonLineEntry ฌ [button[name: "HELP", events: LIST[LIST[$SSHelp]], border: TRUE, font: SSButtonFont]]; resizeButton: ButtonLineEntry ฌ [button[name: "Resize", events: LIST[LIST[$SSResize]], border: TRUE, font: SSButtonFont]]; redButton: ButtonLineEntry ฌ [label[name: "LEFT aborts change or scroll", border: FALSE, font: SSCribFont]]; yellowButton: ButtonLineEntry ฌ [label[name: "MIDDLE changes slides <==>", border: FALSE, font: SSCribFont]]; blueButton: ButtonLineEntry ฌ [label[name: "RIGHT scrolls", border: FALSE, font: SSCribFont]]; bkgnd: BufferedRefresh.Layer ฌ [name: $SSBkgnd, backingMap: TRUE, refreshProc: RefreshBkgnd]; frgnd: BufferedRefresh.Layer ฌ [name: $SSFrgnd, backingMap: FALSE, refreshProc: RefreshFrgnd]; <> d.useBR ฌ TRUE; [list: args, length: argLength] ฌ CommanderOps.ParseToList[cmd: cmd ! CommanderOps.Failed => CONTINUE; ]; SELECT argLength FROM 1 => { IF Rope.Equal[args.first, "-r"] THEN d.useBR ฌ FALSE ELSE defaultGet ฌ args.first; }; 2 => { IF Rope.Equal[args.first, "-r"] THEN d.useBR ฌ FALSE; defaultGet ฌ IF args.rest#NIL THEN args.rest.first ELSE NIL; }; ENDCASE => defaultGet ฌ NIL; d.wDir ฌ FileNames.CurrentWorkingDirectory[]; d.slackHandle ฌ SlackProcess.Create[optimizeProc: OptimizeQueue]; d.sandwich ฌ BufferedRefresh.CreateSandwich[LIST[bkgnd, frgnd] ]; d.container ฌ MJSContainers.Create[ viewerFlavor: $VanillaMJSContainer, info: [ name: "SlideShow", label: "SlideShow", file: NIL, iconic: TRUE, menu: NIL, data: d, icon: ssIcon, scrollable: FALSE], paint: FALSE ]; ViewerOps.SetOpenHeight[d.container, bsY]; nextX ฌ AtomButtons.BuildButtonLine[container: d.container, x: indent, y: 0, clientData: d, handleProc: SSButtonHandleProc, entries: LIST[biggerButton, smallerButton, fillButton, resetButton, xformButton, atButton], lineHeight: buttonLineHeight]; d.pageNumberViewer ฌ ViewerTools.MakeNewTextViewer[ info: [wx: nextX, wy: buttonLineHeight-15, ww: 80, wh: buttonLineHeight, parent: d.container, border: FALSE, scrollable: FALSE], paint: FALSE]; nextX ฌ nextX+d.pageNumberViewer.ww; d.pageNumberSlider ฌ Sliders.Create[ info: [ wx: nextX, wy: 0, ww: d.container.ww-nextX, wh: buttonLineHeight, border: TRUE, parent: d.container, data: d, scrollable: FALSE], filterProc: NormalizePageNumber, sliderProc: PageNumberSlider, orientation: horizontal, foreground: visibleGrey, background: invisibleGrey, clientData: d, paint: FALSE]; MJSContainers.ChildXBound[d.container, d.pageNumberSlider]; nextX ฌ AtomButtons.BuildButtonLine[container: d.container, x: indent, y: buttonLineHeight+3, clientData: d, handleProc: SSButtonHandleProc, entries: LIST[getButton, helpButton, resizeButton], lineHeight: buttonLineHeight]; nextX ฌ nextX+2; -- seems to be needed to make layout work filePrompt ฌ ChoiceButtons.BuildTextPrompt[viewer: d.container, x: nextX, y: buttonLineHeight+5, title: "FILE", default: Rope.Cat["Your ", pdls, " file name here"], font: SSButtonFont, textViewerWidth: d.pageNumberSlider.wx - nextX - 40, clientdata: d, notify: FilePressed]; d.fileNameViewer ฌ filePrompt.textViewer; nextX ฌ AtomButtons.BuildButtonLine[container: d.container, x: filePrompt.newx, y: buttonLineHeight+7, clientData: d, handleProc: NIL, entries: LIST[redButton], lineHeight: cribLineHeight]; nextX ฌ AtomButtons.BuildButtonLine[container: d.container, x: filePrompt.newx, y: buttonLineHeight+cribLineHeight+7, clientData: d, handleProc: NIL, entries: LIST[yellowButton], lineHeight: cribLineHeight]; nextX ฌ AtomButtons.BuildButtonLine[container: d.container, x: filePrompt.newx, y: buttonLineHeight+2*cribLineHeight+7, clientData: d, handleProc: NIL, entries: LIST[blueButton], lineHeight: cribLineHeight]; d.biScroller ฌ bsStyle.CreateBiScroller[ class: bsClass, info: [ parent: d.container, wx: 0, wy: bsY, border: TRUE, scrollable: FALSE, data: d], paint: FALSE ]; d.view ฌ d.biScroller.QuaViewer[inner: FALSE]; -- use d.view as temporary for outer viewer MJSContainers.ChildXBound[d.container, d.view]; MJSContainers.ChildYBound[d.container, d.view]; d.view ฌ d.biScroller.QuaViewer[inner: TRUE]; -- put inner viewer in d.view ViewerOps.MoveBoundary[newLeftWidth: ViewerSpecs.bwScreenWidth-leaveRight, newBottomY: ViewerSpecs.iconRowHeight]; ViewerOps.OpenIcon[icon: d.container, closeOthers: TRUE, paint: TRUE]; IF defaultGet=NIL THEN defaultGet ฌ defaultWant; -- use defaultWant unless command line specified filename IF defaultGet#NIL THEN [] ฌ CedarProcess.Fork[action: Get, data: d]; }; NormalizePageNumber: Sliders.FilterProc = { d: Data ฌ NARROW[clientData]; lastPageNumber: REAL ฌ d.lastPageNumber; RETURN [ SELECT TRUE FROM d.lastPageNumber = 0 => 0.0, -- means no slides loaded; return 0. ENDCASE => Real.Round[value*lastPageNumber]/lastPageNumber -- normalized page number. ]; }; PageNumberSlider: Sliders.SliderProc = { d: Data ฌ NARROW[clientData]; lastPageNumber: REAL ฌ d.lastPageNumber; SELECT reason FROM abort => { SetBigAndBold[d.pageNumberViewer, IO.PutFR["%-g of %g", IO.int[d.pageNumber], IO.int[d.lastPageNumber] ]]; }; move => { newPageInt: INT ฌ MIN[MAX[Real.Round[value*lastPageNumber], 1], d.lastPageNumber]; newContents: Rope.ROPE ฌ IO.PutFR["%-g of %g", IO.int[newPageInt], IO.int[d.lastPageNumber] ]; oldContents: Rope.ROPE ฌ ViewerTools.GetContents[d.pageNumberViewer]; IF Rope.Equal[newContents, oldContents] THEN RETURN; SetBigAndBold[d.pageNumberViewer, newContents]; }; set => { DeltaPage[d, MIN[MAX[Real.Round[value*lastPageNumber], 1], d.lastPageNumber]]; }; ENDCASE; }; DeltaPage: PROC [d: Data, newPage: INT, paint: BOOL ฌ TRUE] = { IF newPage IN [1..d.lastPageNumber] THEN { cToV: Imager.Transformation; newPageReal: REAL ฌ newPage; -- need real value below lastPageReal: REAL ฌ d.lastPageNumber; -- need real value below SetBigAndBold[d.pageNumberViewer, IO.PutFR["%-g of %g", IO.int[newPage], IO.int[d.lastPageNumber] ]]; Sliders.SetContents[d.pageNumberSlider, newPageReal/lastPageReal]; CacheViewingTransform[d]; -- remember the current transforms for the old page d.pageNumber ฌ newPage; cToV ฌ GetCachedTransform[d]; -- fetch the view transforms for the new page IF cToV=NIL THEN BiScrollers.DoBSUserAction[d.biScroller, LIST[$First, $Vanilla] ] ELSE bsStyle.ChangeTransform[bs: d.biScroller, new: cToV, ageOp: remember, paint: FALSE]; }; IF paint THEN PaintView[d: d, op: $View]; }; SetBigAndBold: PROC [v: ViewerClasses.Viewer, r: Rope.ROPE] = { Action: Rope.ActionType = { notSpace: BOOL ฌ c # ' ; tiogaChar.char ฌ c; tiogaChar.looks['x] ฌ notSpace; tiogaChar.looks['b] ฌ notSpace; TiogaAccess.Put[writer, tiogaChar]; }; newline: Rope.ROPE ~ "\n"; writer: TiogaAccess.Writer ฌ TiogaAccess.Create[]; tiogaChar: TiogaAccess.TiogaChar ฌ [charSet: 0, char: ' , looks: ALL[FALSE], format: NIL, comment: FALSE, endOfNode: FALSE, deltaLevel: 0]; TiogaAccess.Put[writer, [charSet: 0, char: '\n, looks: ALL[FALSE], format: NIL, comment: TRUE, endOfNode: TRUE, deltaLevel: 1, propList: LIST[[$NewlineDelimiter, newline]]]]; [] ฌ Rope.Map[base: r, action: Action]; TiogaAccessViewers.WriteViewer[writer, v]; ViewerTools.InhibitUserEdits[v]; }; ChangeCursor: PROC [v: ViewerClasses.Viewer, cursor: ViewerClasses.CursorType] = { IF v#NIL THEN v.cursor ฌ cursor; }; IPLogError: InterpressInterpreter.LogProc ~ { -- [class: INT, code: ATOM, explanation: ROPE] Message[Rope.Concat["InterpressMaster Error: ", explanation]]; }; barbLength: REAL = 10.0; offset: REAL = 25.0; scrolling: Rope.ROPE = "SCROLLING"; nextSlide: Rope.ROPE = "NEXT SLIDE"; previousSlide: Rope.ROPE = "PREVIOUS SLIDE"; scrollingBox: ImagerBox.Box = ImagerBox.BoxFromExtents[ImagerFont.RopeBoundingBox[SSButtonFont, scrolling] ]; nextSlideBox: ImagerBox.Box = ImagerBox.BoxFromExtents[ImagerFont.RopeBoundingBox[SSButtonFont, nextSlide] ]; previousSlideBox: ImagerBox.Box = ImagerBox.BoxFromExtents[ImagerFont.RopeBoundingBox[SSButtonFont, previousSlide] ]; pageWidth: REAL = 72.0*8.5; -- this only works for 8.5 inch wide page on 72 dpi display pageHeight: REAL = 72.0*11.0; -- this only works for 11 inch high page on 72 dpi display RefreshFrgnd: BufferedRefresh.RefreshProc ~ { OPEN Vectors2d; DoRefreshFrgnd: PROC = { -- action proc for DoSave DoArrow: PROC = { -- another action proc for DoSave barbLeft ฌ Add[zero, Scale[Normalize[[-1.0,1.0]], barbLength]]; barbRight ฌ Add[zero, Scale[Normalize[[1.0,1.0]], barbLength]]; angle ฌ AngleFromVector[VectorFromPoints[shaftTop, d.where] ]; context.SetStrokeWidth[scaleFactor*4]; context.SetColor[Imager.black]; context.MaskVector[shaftTop, d.where]; context.TranslateT[d.where]; context.RotateT[90 + angle]; context.MaskVector[zero, Scale[barbLeft, scaleFactor] ]; context.MaskVector[Scale[barbLeft, scaleFactor], zero]; context.MaskVector[zero, Scale[barbRight, scaleFactor]]; }; DoLabel: PROC = { -- and another action proc for DoSave context.TranslateT[d.where]; context.TranslateT[ [offset, offset] ]; context.SetXY[ [0.0, 0.0] ]; context.ScaleT[scaleFactor]; context.SetColor[Imager.white]; context.MaskBox[box]; context.SetFont[SSButtonFont]; context.SetColor[Imager.black]; context.ShowRope[r]; }; box: Imager.Box; angle: REAL ฌ 0.0; zero, shaftTop, barbLeft, barbRight: Imager.VEC ฌ [0.0, 0.0]; r: Rope.ROPE; SELECT d.op FROM $DuringScroll => { shaftTop ฌ d.startScroll; r ฌ scrolling; box ฌ scrollingBox; }; $DuringPage => { shaftTop ฌ d.startPage; IF d.where.x >= d.startPage.x THEN { r ฌ nextSlide; box ฌ nextSlideBox; } ELSE { r ฌ previousSlide; box ฌ previousSlideBox; }; }; ENDCASE => { r ฌ "HUH ??"; box ฌ previousSlideBox; -- don't bother with HUH box }; context.DoSave[DoArrow]; context.DoSave[DoLabel]; }; d: Data ฌ NARROW[clientData]; scaleFactor: REAL ฌ bsStyle.GetTransforms[bs: d.biScroller].viewerToClient.a; context: Imager.Context ฌ dc; IF d.op=$Idle OR d.op=$WindowPaint OR NOT d.useBR THEN RETURN[TRUE]; DoRefreshFrgnd[]; }; <> RefreshBkgnd: BufferedRefresh.RefreshProc ~ { DoRefreshBkgnd: PROC = { -- action proc for DoSave IF d.master#NIL AND d.iMemContext#NIL THEN ImagerMemory.Replay[c: d.iMemContext, into: context] < CONTINUE]; -- expect PostScriptJobAborted after one page for now. }>>; }; d: Data ฌ NARROW[clientData]; context: Imager.Context ฌ dc; context.DoSave[DoRefreshBkgnd]; RETURN[TRUE]; }; SetCA: PROC [c, a: INTEGER ฌ 0] = { useClip ฌ c=1; useFill ฌ a=1; }; useFill: BOOL ฌ FALSE; useClip: BOOL ฌ TRUE; ReadyBkgrnd: PROC [d: Data] ~ { <> IF d.master#NIL AND d.pageInMem#d.pageNumber THEN { -- memory context may be cached cacheVal: CacheVal ฌ Lookup[d]; IF cacheVal#NIL THEN { -- hit d.boundRect ฌ cacheVal.boundRect; d.iMemContext ฌ cacheVal.iMemContext; } ELSE { -- miss. Do not do bounding calculation here. Defer to Fill code. newVal: CacheVal ฌ NEW[CacheValRep]; newKey: CacheKey ฌ NEW[CacheKeyRep]; newKey.fileName ฌ d.fileName; newKey.pageNumber ฌ d.pageNumber; d.iMemContext ฌ newVal.iMemContext ฌ ImagerMemory.NewMemoryContext[]; Imager.ScaleT[d.iMemContext, pointsPerMeter]; -- establish IP coord system Imager.SetColor[d.iMemContext, Imager.black]; Imager.SetAmplifySpace[d.iMemContext, 1.0]; Imager.SetStrokeWidth[d.iMemContext, 0.0]; Imager.SetStrokeEnd[d.iMemContext, square]; Imager.SetStrokeJoint[d.iMemContext, miter]; InterpressInterpreter.DoPage[d.master, d.pageNumber, d.iMemContext, IPLogError]; d.boundRect ฌ newVal.boundRect ฌ nullRect; FunctionCache.Insert[x: globalCache, argument: newKey, value: newVal, size: ImagerMemory.GetContextSize[d.iMemContext], clientID: $SSPage]; }; d.pageInMem ฌ d.pageNumber; }; < { Message["SlideShow error: both PS and IP masters active. See maintainers."]; };>> }; PaintView: PROC [d: Data, op: ATOM] ~ { viewer: ViewerClasses.Viewer ฌ d.view; ReadyBkgrnd[d]; -- do this BEFORE calling ViewerOps.PaintViewer to keep it out of the paint proc locks SELECT op FROM $WindowPaint => { ViewerOps.PaintViewer[viewer: viewer, hint: all, clearClient: FALSE, whatChanged: $WindowPaint]; }; $View => { ViewerOps.PaintViewer[viewer: viewer, hint: all, clearClient: FALSE, whatChanged: d]; }; $Shift => { t: Imager.Transformation ฌ bsStyle.GetTransforms[d.biScroller].clientToViewer; BiScrollers.Shift[bs: d.biScroller, dx: t.a*(d.where.x-d.startScroll.x), dy: t.e*(d.where.y-d.startScroll.y), paint: TRUE]; }; ENDCASE => { Message["SlideShow saw undefined paint operation. See maintainers."]; ViewerOps.PaintViewer[viewer: viewer, hint: all, clearClient: FALSE, whatChanged: d]; }; }; ipIgnoreBackingMap, ipNoBuffer: BOOL = FALSE; <> <> GetBRParameters: PROC [d: Data, scale: REAL] RETURNS [ignoreBMap, noB: BOOL ฌ TRUE, clip: Imager.Rectangle ฌ nullRect] = { IF NOT d.useBR THEN RETURN[TRUE, TRUE, nullRect]; <> IF d.master#NIL THEN { box: Imager.Box; start: Imager.VEC; where: Imager.VEC ฌ d.where; ignoreBMap ฌ ipIgnoreBackingMap; noB ฌ ipNoBuffer; IF noB OR (NOT useClip) THEN RETURN; SELECT d.op FROM $StartScroll, $DuringScroll => start ฌ d.startScroll; $StartPage, $DuringPage => start ฌ d.startPage; ENDCASE => RETURN; -- return default nullRect box ฌ [xmin: MIN[start.x, where.x], ymin: MIN[start.y, where.y], xmax: MAX[start.x, where.x], ymax: MAX [start.y, where.y] ]; box.xmin ฌ box.xmin - offset - scale*previousSlideBox.xmax; box.ymin ฌ box.ymin - offset - scale*previousSlideBox.ymax; box.xmax ฌ box.xmax + offset + scale*previousSlideBox.xmax; box.ymax ฌ box.ymax + offset + scale*previousSlideBox.ymax; IF d.oldClip.xmin=-Real.LargestNumber THEN { clip ฌ ImagerBox.RectangleFromBox[box]; d.oldClip ฌ box; } ELSE { clip ฌ ImagerBox.RectangleFromBox[ImagerBox.BoundingBox[d.oldClip, box]]; d.oldClip ฌ box; }; }; }; DrawSandwich: PROC [d: Data, context: Imager.Context, invalidateBkgnd: BOOL ฌ FALSE] ~ { DoDrawSandwich: PROC = { clip: Imager.Rectangle ฌ nullRect; clientToViewer, viewerToClient: Imager.Transformation; ignoreBackingMap, noBuffer: BOOL ฌ TRUE; [clientToViewer, viewerToClient] ฌ bsStyle.GetTransforms[d.biScroller]; [ignoreBackingMap, noBuffer, clip] ฌ GetBRParameters[d, viewerToClient.a]; IF invalidateBkgnd THEN BufferedRefresh.SetLayerOK[d.sandwich, $SSBkgnd, FALSE]; BufferedRefresh.DrawSandwich[d.sandwich, context, clientToViewer, viewerToClient, d, Imager.white, ignoreBackingMap, noBuffer, clip]; }; Imager.DoSave[context, DoDrawSandwich]; }; SSPaint: ViewerClasses.PaintProc ~ TRUSTED { ENABLE UNCAUGHT => GOTO Finished; -- return and unlock viewers d: Data ฌ NARROW[BiScrollers.ClientDataOfViewer[self]]; sanityCheck: BOOL[TRUE..TRUE] ~ (d.view=self); IF whatChanged=NIL THEN { -- call from window manager. Viewer may have changed size. SlackProcess.QueueAction[d.slackHandle, Dispatch, LIST[$WindowPaint], d, NIL]; } ELSE IF whatChanged=$WindowPaint THEN { -- recall for window manager. Viewer may have changed size. BufferedRefresh.FitSandwichToScreen[d.sandwich, d.view.cw, d.view.ch, context]; DrawSandwich[d, context, TRUE]; } ELSE DrawSandwich[d, context, d.op=$Idle]; -- invalidateBkgnd for final paint after an interactive operation EXITS Finished => Message["SlideShow saw UNCAUGHT ERROR while painting. See maintainers."]; }; SSNotify: ViewerClasses.NotifyProc ~ {-- [self: Viewer, input: LIST OF REF ANY] d: Data ฌ NARROW[BiScrollers.ClientDataOfViewer[self]]; SlackProcess.QueueAction[d.slackHandle, Dispatch, input, d, NIL]; }; Dispatch: PROC [clientData: REF ANY, inputAction: REF] = { d: Data ฌ NARROW[clientData]; event: LIST OF REF ฌ NARROW[inputAction]; z: BiScrollers.ClientCoords ฌ IF event.rest#NIL THEN NARROW[event.rest.first] ELSE NIL; -- REF Vec d.op ฌ NARROW[event.first]; -- ATOM IF z#NIL THEN d.where ฌ [z.x, z.y]; -- mouseX in BiScroller coords SELECT d.op FROM $Abort => { d.aborted ฌ TRUE; d.op ฌ $Idle; }; $WindowPaint => { d.op ฌ $Idle; PaintView[d: d, op: $WindowPaint]; }; $StartScroll => { d.startScroll ฌ d.where; d.op ฌ $DuringScroll; d.aborted ฌ FALSE; IF d.useBR THEN PaintView[d: d, op: $View]; -- track scrolling }; $DuringScroll => IF ~d.aborted AND d.useBR THEN PaintView[d: d, op: $View]; -- track scrolling $EndScroll => { d.op ฌ $Idle; PaintView[d: d, op: IF d.aborted THEN $WindowPaint ELSE $Shift]; d.aborted ฌ FALSE; }; $StartPage => { d.startPage ฌ d.where; d.op ฌ $DuringPage; d.aborted ฌ FALSE; IF d.useBR THEN PaintView[d: d, op: $View]; -- track paging }; $DuringPage => IF ~d.aborted AND d.useBR THEN PaintView[d: d, op: $View]; -- track paging $EndPage => { nextSlide: BOOL ฌ d.where.x >= d.startPage.x; d.op ฌ $Idle; IF ~d.aborted THEN DeltaPage[d, d.pageNumber + (IF nextSlide THEN 1 ELSE -1)] ELSE PaintView[d: d, op: $WindowPaint]; d.aborted ฌ FALSE; }; ENDCASE => Message[IO.PutFR1["SlideShow: unknown Notify atom %g", IO.atom[d.op] ]]; }; SSDestroy: ViewerClasses.DestroyProc ~ { -- [self: Viewer] ENABLE UNWIND => NULL; d: Data ฌ NARROW[BiScrollers.ClientDataOfViewer[self]]; IF d.stream#NIL THEN {d.stream.Close[]; d.stream ฌ NIL;}; IF d.master#NIL THEN {InterpressInterpreter.Close[d.master]; d.master ฌ NIL;}; [] ฌ bsStyle.Destroy[d.biScroller]; d.sandwich ฌ NIL; d.container ฌ d.pageNumberViewer ฌ d.pageNumberSlider ฌ d.fileNameViewer ฌ d.view ฌ NIL; <> d.iMemContext ฌ NIL; d.biScroller ฌ NIL; [] ฌ FunctionCache.Obtain[globalCache, FunctionCache.Any, 9999, $SSPage]; SlackProcess.FlushQueue[d.slackHandle]; d.slackHandle ฌ NIL; }; SSExtremaProc: PROC [clientData: REF ANY, direction: Geom2D.Vec] RETURNS [min, max: Geom2D.Vec] ~ { --BiScrollers.ExtremaProc area: Geom2D.Rect ฌ [x: 0.0, y: 0.0, w: pageWidth, h: pageHeight]; [min, max] ฌ Geom2D.ExtremaOfRect[r: area, n: direction]; }; SSUserAction: BiScrollers.BSUserActionProc = { BiScrollers.DoBSUserAction[bs, input]; }; <> pdls: Rope.ROPE = IF release THEN "IP" ELSE "IP or PS"; localDir: Rope.ROPE = "/tilde/pier/slideshow/"; tipWDir: Rope.ROPE = IF release THEN "/Cedar10.1/PreView/" ELSE localDir; helpWDir: Rope.ROPE = IF release THEN "/Cedar10.1/PreView/" ELSE localDir; <> leaveRight: INTEGER = IF release THEN 250 ELSE 400; -- fudge factor when taking over the Cedar screen defaultWant: Rope.ROPE = IF release THEN NIL ELSE Rope.Concat[localDir, "AdultsAtPlay.ip"]; defaultGet: Rope.ROPE ฌ defaultWant; -- defaultGet is a variable helpFile: Rope.ROPE = "SlideShowHelp.tioga"; ssIcon: Icons.IconFlavor ฌ Icons.NewIconFromFile[Rope.Concat[tipWDir, "SlideShow.icons"], 0]; buffer: REF TEXT = NEW[TEXT[256]]; bsStyle: BiScrollers.BiScrollerStyle; bsClass: BiScrollers.BiScrollerClass; InitSlideShow: PROC = { ssTIP: TIPUser.TIPTable ฌ TIPUser.InstantiateNewTIPTable[Rope.Concat[tipWDir, "SlideShow.tip"]]; bsStyle ฌ BiScrollers.GetStyle[]; -- default has scrollbars bsClass ฌ bsStyle.NewBiScrollerClass[[ flavor: $SlideShow, extrema: SSExtremaProc, notify: SSNotify, paint: SSPaint, destroy: SSDestroy, bsUserAction: SSUserAction, tipTable: ssTIP, cursor: crossHairsCircle, mayStretch: FALSE, -- OK to scale X and Y differently preserve: [X: 0.5, Y: 1.0] --this specifies that the upper middle of the picture stays fixed when viewer size changes. ]]; }; InitSlideShow[]; Commander.Register[key: "SlideShow", proc: CreateSlideShow, doc: IO.PutFR["\nSlideShow [-r] [%g file]\nCreate a slide show for a set of slides in an %g master\n-r buffered refresh disable", IO.rope[pdls], IO.rope[pdls] ]]; Commander.Register[key: "SSFlush", proc: SSFlush, doc: "Flush cache of ImagerMemory contexts for SlideShow" ]; END. ` SlideShowImpl.mesa Copyright ำ 1990, 1992 by Xerox Corporation. All rights reserved. Kenneth A. Pier, March 24, 1993 5:02 pm PST Bier, March 13, 1991 6:16 pm PST Michael Plass, March 25, 1992 12:42 pm PST Russ Atkinson (RRA) August 12, 1992 10:38 pm PDT interpress stuff postscript stuff SimpleFeedback.PutF[$SystemScript, oneLiner, $Feedback, "%g", IO.atom[atom] ]; PROC [argument: Domain] RETURNS [good: BOOL]; PROC [data: REF] RETURNS [results: REF _ NIL]; PROC [data: REF] RETURNS [results: REF _ NIL]; PROC [data: REF] RETURNS [results: REF _ NIL]; Is cached bound box valid?? Playing with fire here. Changing cached entry without monitored record. Could cause problems with two SlideShows showing the same document. align top midpoint of image with top midpoint of viewer. scale about that midpoint by the smaller of the two ratios move the image down slightly, away from the top border of the viewer PROC [data: REF] RETURNS [results: REF _ NIL]; PROC [data: REF] RETURNS [results: REF _ NIL]; PROC [data: REF] RETURNS [results: REF _ NIL]; PROC [data: REF] RETURNS [results: REF _ NIL]; uses global scratch buffer PROC [data: REF] RETURNS [results: REF _ NIL]; reset interpress stuff reset postscript stuff clear the function cache of old SSPage entries (and maybe they'll be collected) set data values common to any PDL type See PSExecImpl.Create for use of process props to discover PS init file directory. Special init files needed for specific "devices." I modified Init.ps to remove extra InitGraphics call that was clobbering the BiScrollers transformation. InitGraphics in PS masters is still a problem. PROC [data: REF] RETURNS [results: REF _ NIL]; open the help viewer and grow it to cover the slideshow display, leaving the control panel visible there may be a better way than the following to manipulate the viewers but this is the only one that I found that works relibably. PROC [data: REF] RETURNS [results: REF _ NIL]; PROC [data: REF] RETURNS [results: REF _ NIL]; PROC [name: ROPE, : REF ANY]; PROC [qeGen: QueueEntryGenerator, actionsOnQueue: NAT] RETURNS [skipActions: NAT]; Notice that skipActions will be at most summary.count -1; The most recent action on the queue will be done if nothing else is appropriate. Always do the last During. [cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL]; -- TYPE = PROC [c: CHAR] RETURNS [quit: BOOL _ FALSE]; RefreshProc: TYPE = PROC [dc: Imager.Context, boundRect: Rectangle, clientData: REF ANY] RETURNS [drawnOn: BOOL _ TRUE]; scale the barbs, shaft, strokewidth by the inverse of the biscroller cToV scale factor scale the box and label by the inverse of the biscroller cToV scale factor by using viewerToClient, get the inverse transformation of the view context.DoSave[DoRefreshFrgnd]; -- might be needed if DoRefreshFrgnd changes for now, stop after a single page is rendered by raising this signal. If we don't do this the screen gets cleared. This is a problem. ERROR PS.PostScriptJobAborted RefreshProc: TYPE = PROC [dc: Imager.Context, boundRect: Rectangle, clientData: REF ANY] RETURNS [drawnOn: BOOL _ TRUE]; This proc works in conjunction with ReadyBkgrnd, which prepares for display. PS programs doing initgraphics screws up BiScroller transformation. Often get PS errors with a non Identity BiScroller transformation. Screen gets cleared at end of jobs. No way to cache individual pages like in ImagerMemory. Imager.DoWithBuffer doesn't work with PS interpreter. Why?? Following code required to get the context state to the default assumed by InterpressInterpreter.DoPage need bounding box of feedback region [self: Viewer, context: Context, whatChanged: REF ANY, clear: BOOL]; The following select statement also acts like a little state machine in that it handles aborting operations when the left button is clicked while an operation is in progress. drop stuff so collector has a chance at it if Viewers lets go as well clear the function cache of old SSPage entries (and maybe they'll be collected) This proc is required by BiScrollers to return the extremes of the displayed data d: Data _ NARROW[clientData]; BSUserActionProc: TYPE = PROC [bs: BiScroller, input: LORA]; ส#๖•NewlineDelimiter –(cedarcode) style™™Jšœ ฯeœ7™BJ™+J™ J™*J™0J™—codešฯk ˜ Kš œ™žœธžœ>žœ<žœ˜โ—Kšฯn œžœžœžœwžœธžœ<œžœงž˜รK˜Kšะbx ัbkx œ ก ˜K˜Kšœžœ˜4Kšœžœ˜.K˜Kšœ žœžœ ˜!šœ žœžœ˜Kšœžœ˜Kšœ ž˜K˜—Kšœ žœžœ ˜!šœ žœžœ˜K˜"K˜K˜K˜K˜—˜HK˜—Kšœžœ#˜8Kšœžœ$˜8Kšœžœ"˜5Kšœ žœ˜Kšœ žœ˜Kšœžœ˜Kšœžœ˜Kšœžœ3˜?Kšœžœฯc2˜GKšœžœ˜"KšŸ œ=˜IKšŸ œ<˜GKšŸ œ;˜EK˜@K˜BK˜iK˜pK˜Kšœžœžœ˜šœžœžœ˜Kšœ žœ˜K˜&K˜#Kšœžœžœ˜Kšœ žœžœ˜Kšœžœ˜K˜ K˜'K˜'K˜%K˜#Kšœข˜:Kšœžœ˜%Kšœžœ˜#Kšœžœ ˜Kšœžœ˜Kšœ žœ˜šœžœ˜K™—K˜%Kšœ žœข ˜7Kšœข˜7K˜'˜K™—Kšœœžœ˜Kšœžœ˜Kšœžœž˜K˜—K˜š Ÿœžœ žœžœžœ˜@K˜$Kšžœžœ˜$K˜—K˜šŸœ"˜4Kšœžœžœ˜!K™Nšœžœž˜/K˜K˜K˜K˜K˜K˜K˜K˜K˜K˜Kšžœ ˜K˜—K˜K˜—šŸœžœžœžœ˜Hšะbnœžœ˜6Kšฯsœคœคœ™-š žœ žœžœžœžœžœ˜)Kšœžœ ˜!Kš žœžœžœžœ žœžœ ˜bK˜—K˜—KšœžœZ˜fK˜K˜—šŸœžœ žœ"˜LK˜Kšžœžœžœ˜ K˜K˜—šŸœžœ˜*K˜KšžœžœžœDข!˜tK˜K˜—šŸœ˜%Kš žœžœžœ žœžœ™.Kšœ žœ˜Kšžœ žœžœ4žœ˜SKšœ1ข˜AK˜K˜—šŸœ˜&Kš žœžœžœ žœžœ™.Kšœ žœ˜Kšžœ žœžœ5žœ˜TKšœ5ข˜FK˜K˜—šŸœ˜#Kš žœžœžœ žœžœ™.Kšœžœข˜"Kšœžœข˜/Kšœžœ ข˜#Kšœ žœ˜K˜š žœ žœžœ žœžœ˜(K˜*Kšะbkœ˜K˜—š œžœ.žœžœžœ˜\K™—Kšžœ!žœ"ข˜Ošžœข˜šŸœžœ˜'K˜.K˜—Kšœžœžœ ข˜8KšœฯbœGžœ˜vK™HK™CKš œ#žœ žœžœ žœคข˜†K˜—K˜'K˜&Kšœ ข˜$Kšœ ข!˜,šœ)žœข(˜kK™8—šœ’žœ˜šK™:—šœ:žœžœ˜XK™D—Kšœ<žœ˜CKš œžœ$žœžœžœ˜SK˜K˜—šŸœ˜&Kš žœžœžœ žœžœ™.Kšœ žœ˜Kšœ)žœข˜UK˜K˜—šŸœ˜$Kš žœžœžœ žœžœ™.Kšœ žœ˜Kšžœ žœžœ.˜Dšžœข8˜?K˜UKšœ žœ˜!šžœ žœžœž˜QKšœMžœ˜TK˜Kšœ*žœข)˜ZKšžœ˜—šžœ žœžœž˜@KšœMžœ˜TK˜Kšœ*žœข)˜ZKšžœ˜—Kšœžœžœ˜)K˜—K˜K˜—šŸœ˜'Kš žœžœžœ žœžœ™.Kšœ žœ˜Kšžœ žœžœ1˜Gšžœข8˜?Kšœ žœ˜!šžœ žœžœž˜QKšœ)žœข˜]K˜Kšœ*žœข)˜ZKšžœ˜—šžœ žœžœž˜@Kšœ)žœข˜]K˜Kšœ*žœข)˜ZKšžœ˜—Kšœžœžœ˜,K˜—K˜K˜—šŸœ˜&Kš žœžœžœ žœžœ™.Kšœ žœ˜Kšžœ žœžœ0˜Fšžœข˜$Kšœ žœ˜!šžœ žœžœž˜QK˜K˜Kšœ*žœข)˜ZKšžœ˜—šžœ žœžœž˜@K˜K˜Kšœ*žœข)˜ZKšžœ˜—Kšœžœžœ˜+K˜—K˜—K˜šŸœžœžœžœžœ žœžœžœ˜AK™Kšžœ˜Kšœžœ˜.KšžœBžœ˜PK˜K˜—šŸœ˜"Kš žœžœžœ žœžœ™.šŸœžœžœžœ˜-Kšœ žœข*˜žœžœžœ˜wšœžœ˜"KšœžœF˜KKšœžœ8˜=KšœžœE˜JK˜—Kšœ[žœ&žœ˜ŒK˜LKšœ<žœžœžœ˜tKšœ@žœžœžœ˜zKšœRžœ˜lKšœSžœ˜mKšœDžœ˜^K˜Kšœ<ฅœ˜]Kšœ<ฅœ˜^K˜Kšœœข/œ˜IKšœ žœ˜K˜Kšœ]žœ˜išžœ ž˜˜Kšžœžœ ž˜4Kšžœ˜K˜—˜Kšžœžœ žœ˜5Kš œ žœ žœžœžœžœ˜คœคœคœPžœžœ จœ˜รK˜$K˜˜$˜K˜ K˜K˜K˜Kšœžœ˜ K˜K˜Kšœ žœ˜—K˜ K˜K˜K˜K˜K˜Kšœจœ˜—K˜;K˜Kšœ–žœE˜฿Kšœข)˜;K˜Kšœ๊ฆœ&˜’K˜)K˜Kšœ‚žœ žœ)˜ฝKšœ‘žœ žœ,˜ฯKšœ“žœ žœ*˜ฯK˜K˜˜(K˜˜K˜K˜K˜Kšœžœ˜ Kšœ žœ˜K˜ —Kšœจœ˜—Kšœ'žœข+˜ZK˜/K˜/Kšœ'žœข˜KK˜Kšœ ฆ œ\˜rKšœ ฆœ!žœ žœ˜FK˜Kšžœ žœžœข9˜jKšžœ žœžœ.˜DK˜—K™šŸœ˜+Kšœ žœ ˜Kšœžœ˜(šžœžœžœž˜Kšœข$˜AKšžœ ฆœ&ข˜UK˜—K˜K˜—šงœ˜(Kšœ žœ ˜Kšœžœ˜(šžœž˜˜ Kšœ"žœžœžœ˜jK˜—˜ Kš œ žœžœžœฆœ.˜RKš œžœžœžœžœ˜^Kšœžœ/˜EKšžœ&žœžœ˜4K˜/K˜—˜Kšœ žœžœฆœ/˜NK˜—Kšžœ˜—K˜K˜—š Ÿ œžœžœ žœžœ˜?šžœ žœžœ˜*K˜Kšœ žœ ข˜6Kšœžœข˜@Kšœ"žœžœžœ˜eK˜BKšœข3˜MK˜Kšœข-˜LKš žœžœžœ*žœžœNžœ˜ฌK˜—Kšžœžœ˜)K˜K˜—šŸ œžœ#žœ˜?šŸœ˜Kš žœžœžœžœžœžœ™7Kšœ žœ ˜K˜K˜K˜K˜#K˜K˜—Kšœžœ˜K˜2˜/K˜ Kšœžœžœ˜Kšœžœ˜ Kšœ žœ˜Kšœ žœ˜K˜—˜$K˜ Kšœžœžœ˜Kšœžœ˜ Kšœ žœ˜Kšœ žœ˜K˜Kšœ žœ!˜/—K˜'K˜*K˜ K˜K˜—šŸ œžœ@˜RKšžœžœžœ˜ K˜—K˜š Ÿ œ$ข ะcsขฉขฉข˜\K˜>K˜—K˜Kšœ žœ˜Kšœžœ˜Kšœžœ˜#Kšœžœ˜$Kšœžœ˜,K˜mK˜mK˜uK˜Kšœ žœข;˜XKšœ žœข:˜YK˜šŸ œ"˜.Kšœ žœžœ8žœžœžœ žœžœ™xK™Kšจะbl ˜K˜šŸœžœข˜2šŸœžœข!˜3K™VK˜?K˜?K˜>Kšœฆ œ˜&K˜K˜&K˜K˜KšœŸœ˜8KšœŸœ˜7KšœŸœ˜8K˜—šŸœžœข%˜7K™JK˜K˜'K˜Kšฆ˜K˜K˜K˜K˜K˜K˜—K˜Kšœžœ˜Kšœ,žœ˜=Kšœžœ˜ šžœž˜˜K˜K˜K˜K˜—˜K˜šžœžœ˜$K˜K˜K˜—šœžœ˜K˜K˜K˜—K˜—šžœ˜ K˜ Kšœข˜4K˜——K˜K˜K˜K˜—Kšœ žœ ˜šœ žœ<˜MKšœ!ฆœ™C—K˜Kšžœ žœžœžœ žœžœžœ˜DK™LK˜K˜K˜—šŸŸœ˜&K™EK™@Kšžœžœ™K˜,K˜KšŸ˜—šŸ œ"˜.Kšœ žœžœ8žœžœžœ žœžœ™xK™LšŸœžœข˜2Kš žœ žœžœžœžœ5˜_š œžœžœ žœžœ˜šœ žœ$žœ˜=K˜Kšžœ˜Kšžœ<˜>K˜—Kšžœ,˜.K™CK™BK™#K™6K™<šœKžœ˜OKšœžœžœžœข6˜u—K˜—K˜—Kšœ žœ ˜K˜K˜Kšžœžœ˜ K˜K˜—šŸœžœžœ ˜#K˜K˜K˜K˜—Kšœ žœžœ˜Kšœ žœžœ˜šŸ œžœ˜ Kšœžœ žœžœ žœžœžœœ˜4š žœ žœžœžœข˜SK˜šžœ žœžœข˜K˜!K˜%K˜—šžœขC˜JKšœžœ˜$Kšœžœ˜$K˜K˜"K˜EKšœ.ข˜JJ–7[context: Imager.Context, color: ImagerColor.Color]™gK˜-K˜+K˜*K˜+K˜,K˜PK˜*˜EK˜E—K˜—K˜K˜—šž˜˜ K˜MKšœž˜——K˜K˜—šŸ œžœžœ˜(K˜&KšœขV˜fšžœž˜˜Kšœ>žœ˜`K˜—˜ Kšœ>žœ˜UK˜—˜ K˜NKšœužœ˜{K˜—šžœ˜ K˜EKšœ>žœ˜UK˜——K˜K˜—Kšœ žœžœ˜-Kšœœžœžœœ˜%Kšœœ žœžœข8œ˜Uš Ÿœžœžœžœžœžœ(˜zKš žœžœ žœžœžœžœ ˜1šžžœ žœžœ˜Kšžœ,ข ˜Kšœ žœ'˜7Kšœ žœžœžœ˜.šžœ žœžœข;˜UKšœ2žœžœ˜NK˜—šžœžœžœข<˜dK˜OKšœžœ˜K˜—Kšžœ'ขA˜lšž˜K˜U—K˜K˜—šŸœขฉข˜OKšœ žœ'˜7Kšœ<žœ˜AK˜K˜—š Ÿœžœžœžœžœ˜:Kšœ žœ ˜Kš œžœžœžœžœ˜)Kšœžœ žœžœžœžœžœข ˜bK˜Kšœžœข˜#Kšžœžœžœข˜BK™ฎšžœž˜˜ Kšœ žœ˜K˜ K˜—˜K˜ K˜"K˜—˜K˜K˜Kšœ žœ˜Kšžœ žœข˜>K˜—Kšœžœ žœ žœข˜^˜K˜ Kšœžœ žœžœ ˜@Kšœ žœ˜K˜—˜K˜K˜Kšœ žœ˜Kšžœ žœข˜;K˜—Kšœžœ žœ žœข˜Y˜ Kšœ žœ˜-K˜ Kš žœ žœžœ žœžœ˜MKšžœ#˜'Kšœ žœ˜K˜—Kšžœ žœ-žœ˜S—K˜K˜—šŸ œ ข˜:Kšžœžœžœ˜Kšœ žœ'˜7K™EKšžœ žœžœžœ˜9K–[master: Interpress.Master]šžœ žœžœ4žœ˜NK˜#Kšœ žœ˜KšœTžœ˜XKšœœžœœ˜$Kšœžœ˜Kšœžœ˜K™OK˜IK˜'Kšœžœ˜K˜K˜—š Ÿ œžœžœžœžœ˜_Kšœข˜K™QKšœ žœ ™K˜BK˜9K˜K˜—šŸ œ"˜.Kšœžœžœžœ™˜nK™Kšžœ˜K˜K˜—…—’ ฦ`