<> <> DIRECTORY AIS USING [Error, OpenFile, ReadRaster], Ascii USING [Upper], BasicTime USING [GMT, nullGMT], BiScrollers USING [Align, BiScroller, BiScrollerClass, BiScrollerStyle, bsMenu, GetStyle, QuaBiScroller, QuaViewer, Scale], Buttons USING [Button, ButtonProc, Create], <> Commander USING [CommandProc, Handle, Register], CommandTool USING [Failed, ParseToList], Containers USING [ChildXBound, ChildYBound, Create], FileNames USING [CurrentWorkingDirectory, Directory, GetShortName, ResolveRelativePath, Tail, StripVersionNumber], FS USING [ComponentPositions, Error, ExpandName, FileInfo, OpenFile, OpenFileFromStream, StreamOpen], GriffinImageUtils USING [ReadGriffinImage], Icons USING [IconFlavor, NewIconFromFile], Imager USING [Color, Error], ImagerBackdoor USING [MakeStipple], ImagerColorOperator USING [BlackColorModel, GrayLinearColorModel, RGBLinearColorModel], ImagerMemory USING [NewMemoryContext], ImagerPixelArray USING [Error, FromAIS, Join3AIS, MaxSampleValue], Interpress USING [LogProc, Open, OpenMaster], IO USING [EndOfStream, Error, GetInt, int, PutFR, real, RIS, SetIndex, STREAM], IPMaster USING [Error, GetHeader], List USING [Append, Remove], Menus USING [AppendMenuEntry, CopyMenu, CreateEntry, Menu], MessageWindow USING [Append, Blink], PDFileReader USING [Error, FromStream, Handle, Rep, Warning], PDImageReader USING [GetPageStructure, Handle, Rep], PressReader USING [FromOpenFile, PressReaderError], PreView USING [AISData, AISState, AISStateRep, BBoxStateRep, Data, DoFileOps, FileInfo, FileInfoRep, FileType, GData, IPData, NameList, PDData, PressData, PVBasicTransformProc, PVDestroy, PVExtremaProc, PVFeedback, PVGetName, PVNotify, PVPaint, Rep, Switches, SwitchRange], PreViewClient USING [], Process USING [Abort], Real USING [FDiv, RoundI], Rope USING [Cat, Concat, Equal, Fetch, Length, ROPE, SkipTo, Substr], Rules USING [Create, Rule], ShowPress USING [Handle, Open, ShowPressError], Sliders USING [Create, FilterProc, SetContents, SliderProc], TiogaMenuOps USING [Open], TIPUser USING [InstantiateNewTIPTable, TIPTable], UserProfile USING [Boolean, CallWhenProfileChanges, ListOfTokens, ProfileChangedProc], ViewerClasses USING [Viewer], ViewerOps USING [AddProp, FetchProp, PaintViewer], ViewerSpecs USING [captionHeight, menuBarHeight, scrollBarW, windowBorderSize], ViewerTools USING [GetContents, GetSelectionContents, MakeNewTextViewer, SetContents]; PreViewTool: CEDAR MONITOR IMPORTS AIS, Ascii, BiScrollers, --ChoiceButtons, --Buttons, Commander, CommandTool, Containers, FileNames, FS, GriffinImageUtils, Icons, Imager, ImagerBackdoor, ImagerColorOperator, ImagerMemory, ImagerPixelArray, Interpress, IO, IPMaster, List, Menus, MessageWindow, PDFileReader, PDImageReader, PressReader, PreView, Process, Real, Rope, Rules, ShowPress, Sliders, TiogaMenuOps, TIPUser, UserProfile, ViewerOps, ViewerSpecs, ViewerTools EXPORTS PreView, PreViewClient = BEGIN FileType: TYPE = PreView.FileType; Data: TYPE = PreView.Data; Rep: TYPE = PreView.Rep; IPData: TYPE = PreView.IPData; PressData: TYPE = PreView.PressData; PDData: TYPE = PreView.PDData; AISData: TYPE = PreView.AISData; GData: TYPE = PreView.GData; AISState: TYPE = PreView.AISState; pvIcon: Icons.IconFlavor = Icons.NewIconFromFile["PreView.icons", 0]; ipPrefix: Rope.ROPE = "Interpress/"; defaultPageHeight: REAL = 11.0*72.0; -- points defaultPageWidth: REAL = 8.5*72.0; -- points versatecPageHeight: REAL = 40.0*72.0; -- points versatecPageWidth: REAL = 40.0*72.0; -- points screenResolution: REAL = 72.0; -- points per inch pointsPerMica: REAL = 72.0/2540.0; micasPerPoint: REAL = 2540.0/72.0; pointsPerMeter: REAL = 72.0/.0254; metersPerPoint: REAL = .0254/72.0; visibleGrey: Imager.Color = ImagerBackdoor.MakeStipple[122645B]; invisibleGrey: Imager.Color = ImagerBackdoor.MakeStipple[100040B]; LProc: Interpress.LogProc = { <<[master: OpenMaster, class: ErrorClass, code: ATOM, explanation: ROPE]>> MessageWindow.Append[message: Rope.Concat["InterpressMaster Error: ", explanation], clearFirst: TRUE]; MessageWindow.Blink[]; }; WhichFileType: PROC [fileName: Rope.ROPE] RETURNS [PreView.FileInfo] = { <> fname: Rope.ROPE _ NIL; created: BasicTime.GMT _ BasicTime.nullGMT; [fullFName: fname, created: created] _ FS.FileInfo[name: fileName ! FS.Error => CONTINUE]; IF fname#NIL THEN RETURN[DiscoverFileType[fname, created]];-- named file exists <> IF extensionList = NIL THEN extensionList _ defaultExtensionList; FOR l: LIST OF Rope.ROPE _ extensionList, l.rest UNTIL l=NIL DO fname _ Rope.Cat[fileName, ".", l.first]; [fullFName: fname, created: created] _ FS.FileInfo[name: fname ! FS.Error => LOOP]; RETURN[DiscoverFileType[fname, created]]; -- file with extension exists ENDLOOP; RETURN[NEW[PreView.FileInfoRep _ [] ]]; -- file does not exist }; DiscoverFileType: PROC [fileName: Rope.ROPE, created: BasicTime.GMT] RETURNS [fileInfo: PreView.FileInfo] = { <> <> fileInfo _ NEW[PreView.FileInfoRep _ [] ]; --initialize to fileType none, etc. { ref: REF ANY _ NIL; s: IO.STREAM _ FS.StreamOpen[fileName: fileName ! FS.Error => GOTO None]; cp: FS.ComponentPositions _ FS.ExpandName[fileName].cp; ext: Rope.ROPE _ Rope.Substr[base: fileName, start: cp.ext.start, len: cp.ext.length]; SELECT TRUE FROM Rope.Equal[s1: ext, s2: "ip", case: FALSE], Rope.Equal[s1: ext, s2: "interpress", case: FALSE] => IF (ref _ IPMaster.GetHeader[stream: s, prefix: ipPrefix ! IPMaster.Error => CONTINUE;])#NIL THEN {fileInfo^ _ [ip, fileName, created, ref]; RETURN;}; Rope.Equal[s1: ext, s2: "press", case: FALSE] => IF (ref _ PressReader.FromOpenFile[openFile: FS.OpenFileFromStream[self: s] ! PressReader.PressReaderError => CONTINUE;])#NIL THEN {fileInfo^ _ [press, fileName, created, ref]; RETURN;}; Rope.Equal[s1: ext, s2: "pd", case: FALSE] => IF (ref _ PDFileReader.FromStream[stream: s ! PDFileReader.Error, PDFileReader.Warning => CONTINUE;])#NIL THEN {fileInfo^ _ [pd, fileName, created, ref]; RETURN;}; Rope.Equal[s1: ext, s2: "ais", case: FALSE] => IF (ref _ AIS.OpenFile[name: fileName ! AIS.Error, FS.Error => CONTINUE;])#NIL THEN {fileInfo^ _ [ais, fileName, created, ref]; RETURN;}; Rope.Equal[s1: ext, s2: "griffin", case: FALSE] => IF (ref _ GriffinImageUtils.ReadGriffinImage[name: fileName ! FS.Error => CONTINUE;])#NIL THEN {fileInfo^ _ [griffin, fileName, created, ref]; RETURN;}; ENDCASE => NULL; <> IO.SetIndex[s,0]; --reset stream for subsequent calls IF (ref _ IPMaster.GetHeader[stream: s, prefix: ipPrefix ! IPMaster.Error => CONTINUE;])#NIL THEN {fileInfo^ _ [ip, fileName, created, ref]; RETURN;}; IO.SetIndex[s,0]; --reset stream for subsequent calls IF (ref _ PressReader.FromOpenFile[openFile: FS.OpenFileFromStream[self: s] ! PressReader.PressReaderError => CONTINUE;])#NIL THEN {fileInfo^ _ [press, fileName, created, ref]; RETURN;}; IO.SetIndex[s,0]; --reset stream for subsequent calls IF (ref _ PDFileReader.FromStream[stream: s ! PDFileReader.Error, PDFileReader.Warning => CONTINUE;])#NIL THEN {fileInfo^ _ [pd, fileName, created, ref]; RETURN;}; IF (ref _ AIS.OpenFile[name: fileName ! AIS.Error, FS.Error => CONTINUE;])#NIL THEN {fileInfo^ _ [ais, fileName, created, ref]; RETURN;}; IF (ref _ GriffinImageUtils.ReadGriffinImage[name: fileName ! FS.Error => CONTINUE;])#NIL THEN {fileInfo^ _ [griffin, fileName, created, ref]; RETURN;}; fileInfo^ _ [none, NIL, BasicTime.nullGMT, NIL]; EXITS None => fileInfo^ _ [none, NIL, BasicTime.nullGMT, NIL]; }; }; CreatePreViewer: PUBLIC PROC [fileNames: PreView.NameList, switches: PreView.Switches] RETURNS [preViewer: ViewerClasses.Viewer] = { bs: BiScrollers.BiScroller _ NIL; <> data: Data _ NIL; curIndent, topLine: INTEGER _ 0; button: Buttons.Button; menu: Menus.Menu; rule: Rules.Rule; fileInfo: PreView.FileInfo _ NIL; versionSpecified: BOOL _ fileNames.rest#NIL OR Rope.SkipTo[s: fileNames.first, skip: "!"]#Rope.Length[fileNames.first]; -- don't do versions with multiple AIS files fileInfo _ WhichFileType[fileNames.first]; -- adds file extension to the named file if needed SELECT fileInfo.filetype FROM ip => { ipmaster: Interpress.OpenMaster _ Interpress.Open[fileName: fileInfo.fullFName, logProc: LProc, logData: NIL ! FS.Error => { MessageWindow.Append[message: error.explanation, clearFirst: TRUE]; GOTO Quit; }; IPMaster.Error => { --ErrorDesc: TYPE = RECORD[code: ATOM, explanation: ROPE, index: INT _ 0] MessageWindow.Append[message: Rope.Cat[error.explanation, " for ", fileInfo.fullFName], clearFirst: TRUE]; GOTO Quit; }; Imager.Error => { --ErrorDesc: TYPE = RECORD [code: ATOM, explanation: ROPE] MessageWindow.Append[message: Rope.Cat[error.explanation, " for ", fileInfo.fullFName], clearFirst: TRUE]; GOTO Quit; }; IO.Error, IO.EndOfStream => { MessageWindow.Append[message: Rope.Cat["IO Stream Error for ", fileInfo.fullFName], clearFirst: TRUE]; GOTO Quit; }; ]; IF ipmaster.pages=0 THEN { MessageWindow.Append[message: Rope.Concat["Zero pages in ", fileInfo.fullFName], clearFirst: TRUE]; GOTO Quit; }; data _ NEW[ip Rep _ [fileInfo: fileInfo, pageNumber: 1, lastPageNumber: ipmaster.pages, pageHeight: IF switches['V] THEN versatecPageHeight ELSE defaultPageHeight, pageWidth: IF switches['V] THEN versatecPageWidth ELSE defaultPageWidth, switches: switches, kind: ip[ipMaster: ipmaster]]]; -- pages IN [1..end] }; press => { pressfile: ShowPress.Handle _ ShowPress.Open[fileInfo.fullFName ! FS.Error => { MessageWindow.Append[message: error.explanation, clearFirst: TRUE]; GOTO Quit; }; ShowPress.ShowPressError => { SELECT code FROM $CantReadFile => MessageWindow.Append[message: Rope.Concat["Can't open PreViewer on ", fileInfo.fullFName], clearFirst: TRUE]; $CantFindFonts => MessageWindow.Append[message: Rope.Concat["Can't Find Fonts for ", fileInfo.fullFName], clearFirst: TRUE]; ENDCASE => MessageWindow.Append[message: Rope.Concat["ShowPressError on ", fileInfo.fullFName], clearFirst: TRUE]; GOTO Quit; }; Imager.Error => { MessageWindow.Append[message: Rope.Cat[error.explanation, " for ", fileInfo.fullFName], clearFirst: TRUE]; GOTO Quit; }; ]; IF pressfile.lastPart-1=0 THEN { MessageWindow.Append[message: Rope.Concat["Zero pages in ", fileInfo.fullFName], clearFirst: TRUE]; GOTO Quit; }; data _ NEW[press Rep _ [fileInfo: fileInfo, pageNumber: 1, lastPageNumber: pressfile.lastPart-1, pageHeight: defaultPageHeight, pageWidth: defaultPageWidth, switches: switches, kind: press[presshandle: pressfile]]]; }; pd => { pdfile: PDFileReader.Handle _ NARROW[fileInfo.ref]; -- DiscoverFileType did a PDFileReader.FromStream already pdData: PDData _ NEW[pd Rep _ [fileInfo: fileInfo, pageNumber: 1, pageHeight: (pdfile.herald.imageSSize/pdfile.herald.sResolution)*screenResolution, pageWidth: (pdfile.herald.imageFSize/pdfile.herald.fResolution)*screenResolution, switches: switches, kind: pd[pdhandle: pdfile, scalePD: NOT switches['F]]]]; [pdData.pageStructure, pdData.lastPageNumber] _ PDImageReader.GetPageStructure[pdfile]; pdData.scaleFactors _ [x: screenResolution/pdfile.herald.fResolution, y: screenResolution/pdfile.herald.sResolution]; IF switches['F] THEN { -- "full" scale, so ExtremaProc has to know about pixels pdData.pageWidth _ pdData.pageWidth*(pdfile.herald.fResolution/screenResolution); pdData.pageHeight _ pdData.pageHeight*(pdfile.herald.sResolution/screenResolution); }; IF pdData.lastPageNumber=0 THEN { MessageWindow.Append[message: Rope.Concat["Zero pages in ", fileInfo.fullFName], clearFirst: TRUE]; GOTO Quit; }; data _ pdData; }; ais => { aisData: AISData _ NEW[ais Rep _ [fileInfo: fileInfo, pageNumber: 1, lastPageNumber: 1, switches: switches, kind: ais[state: NEW[PreView.AISStateRep _ []]]]]; aisData.state.openFile _ NARROW[fileInfo.ref]; -- DiscoverFileType did an AIS.OpenFile already << --read the AIS file(s) and get ready for display. aisData.state will be further filled in by this call.>> IF (fileInfo.fullFName _ InitAIS[data: aisData, fileNames: fileNames, singleName: fileInfo.fullFName]) = NIL THEN GOTO Quit; aisData.pageHeight _ aisData.state.scans; aisData.pageWidth _ aisData.state.pixels; data _ aisData; }; griffin => { data _ NEW[griffin Rep _ [fileInfo: fileInfo, pageNumber: 1, lastPageNumber: 1, pageHeight: defaultPageHeight, pageWidth: defaultPageWidth, switches: switches, kind: griffin[image: NARROW[fileInfo.ref]]]]; -- single page }; ENDCASE => { IF tryTioga THEN { [] _ TiogaMenuOps.Open[fileNames.first]; RETURN; } ELSE MessageWindow.Append[message: Rope.Concat["Unknown file or filetype: ", fileNames.first], clearFirst: TRUE]; GOTO Quit; }; menu _ Menus.CopyMenu[BiScrollers.bsMenu]; Menus.AppendMenuEntry[menu: menu, entry: Menus.CreateEntry[name: "Selection", proc: SelectionOps, clientData: data, documentation: "Left: center selection, Middle: center and fit selection, Right: select entire page "]]; data.bBox _ NEW[PreView.BBoxStateRep _ []]; data.iMemContext _ ImagerMemory.NewMemoryContext[]; <> data.container _ preViewer _ Containers.Create[ info: [ name: IF versionSpecified THEN Rope.Concat["PreView: ", data.fileInfo.fullFName] ELSE Rope.Cat["PreView: ", FileNames.StripVersionNumber[data.fileInfo.fullFName], " (!", FileNames.Tail[data.fileInfo.fullFName, '!], ")"], label: FileNames.GetShortName[path: data.fileInfo.fullFName, stripOffVersionNumber: TRUE], iconic: TRUE, menu: menu, icon: pvIcon, data: data, scrollable: FALSE], paint: FALSE ]; button _ Buttons.Create[ info: [ name: "Stuff", wx: curIndent, wy: topLine, border: FALSE, parent: data.container], proc: Stuff, clientData: data, documentation: "Click to stuff an IP node at the current selection", paint: FALSE]; curIndent _ button.wx + button.ww; button _ Buttons.Create[ info: [ name: "ToIP", wx: curIndent, wy: topLine, border: FALSE, parent: data.container], proc: ToIP, clientData: data, documentation: "Click to create an IP Master", paint: FALSE]; curIndent _ button.wx + button.ww; button _ Buttons.Create[ info: [ name: "FirstPage", wx: curIndent, wy: topLine, border: FALSE, parent: data.container], proc: FirstPage, clientData: data, documentation: "Left-click for the first page of the file", paint: FALSE]; curIndent _ button.wx + button.ww; button _ Buttons.Create[ info: [ name: "TurnPage", wx: curIndent, wy: topLine, border: FALSE, parent: data.container], proc: TurnPage, clientData: data, documentation: "Left-click for next page; Right-click for previous page", paint: FALSE]; curIndent _ button.wx + button.ww; button _ Buttons.Create[ info: [ name: "LastPage", wx: curIndent, wy: topLine, border: FALSE, parent: data.container], proc: LastPage, clientData: data, documentation: "Left-click for last page of the file", paint: FALSE]; curIndent _ button.wx + button.ww; button _ Buttons.Create[ info: [ name: "Page", wx: curIndent, wy: topLine, border: FALSE, parent: data.container], proc: PageNumber, clientData: data, documentation: "Left-click for selected page number", paint: FALSE]; curIndent _ button.wx + button.ww; data.pageNumberViewer _ ViewerTools.MakeNewTextViewer[ info: [ wx: curIndent, wy: topLine+ViewerSpecs.windowBorderSize, ww: 40, wh: ViewerSpecs.scrollBarW+2*ViewerSpecs.windowBorderSize, parent: data.container, border: FALSE, scrollable: FALSE], paint: FALSE]; curIndent _ data.pageNumberViewer.wx + data.pageNumberViewer.ww; data.pageNumberSlider _ Sliders.Create[ info: [ wx: curIndent, wy: topLine, ww: data.container.ww-curIndent, wh: ViewerSpecs.scrollBarW+2*ViewerSpecs.windowBorderSize, border: FALSE, parent: data.container, scrollable: FALSE], filterProc: NormalizePageNumber, sliderProc: PageNumberSlider, orientation: horizontal, foreground: visibleGrey, background: invisibleGrey, clientData: data, paint: FALSE]; Containers.ChildXBound[data.container, data.pageNumberSlider]; rule _ Rules.Create[ info: [ parent: data.container, wx: 0, wy: topLine+ViewerSpecs.captionHeight+4*ViewerSpecs.windowBorderSize, wh: ViewerSpecs.menuBarHeight]]; Containers.ChildXBound[data.container, rule]; <<>> <> <> <<>> <> <> <> <> <> <> <> <<>> bs _ bsStyle.CreateBiScroller[ class: pvBSClass, info: [ parent: data.container, wx: 0, wy: rule.wy+rule.wh+2*ViewerSpecs.windowBorderSize, border: FALSE, scrollable: FALSE, data: data], paint: FALSE ]; data.preViewer _ bs.QuaViewer[inner: FALSE]; ViewerOps.AddProp[viewer: bs.QuaViewer[inner: TRUE], prop: $PVWDir, val: FileNames.CurrentWorkingDirectory[]]; Containers.ChildXBound[data.container, data.preViewer]; Containers.ChildYBound[data.container, data.preViewer]; ViewerOps.PaintViewer[viewer: data.container, hint: all, clearClient: TRUE]; DeltaPage[data, 1]; PVListAdd[LIST[data]]; EXITS Quit => { MessageWindow.Blink[]; RETURN; }; }; InitAIS: PROC [data: AISData, fileNames: PreView.NameList, singleName: Rope.ROPE] RETURNS [newName: Rope.ROPE _ NIL] = { ENABLE { FS.Error => { MessageWindow.Append[message: error.explanation, clearFirst: TRUE]; newName _ NIL; CONTINUE; }; ImagerPixelArray.Error => { MessageWindow.Append[message: error.explanation, clearFirst: TRUE]; newName _ NIL; CONTINUE; }; }; state: AISState _ data.state; IF fileNames.rest#NIL THEN { --multi-file color AIS image redName: Rope.ROPE _ Rope.Concat[fileNames.rest.rest.first, ".ais"]; grnName: Rope.ROPE _ Rope.Concat[fileNames.rest.first, ".ais"]; bluName: Rope.ROPE _ Rope.Concat[fileNames.first, ".ais"]; IF data.abort THEN {data.abort _ FALSE; RETURN[NIL]}; -- set asynchronously by StopIfYouCan state.pa_ ImagerPixelArray.Join3AIS[name1: redName, name2: grnName, name3: bluName]; -- in red, green, blue order !! [scanCount: state.scans, scanLength: state.pixels] _ AIS.ReadRaster[state.openFile]^; -- must be identical raster info in all separations IF data.abort THEN {data.abort _ FALSE; RETURN[NIL]}; -- set asynchronously by StopIfYouCan state.op _ ImagerColorOperator.RGBLinearColorModel[maxSampleValue: ImagerPixelArray.MaxSampleValue[pa: state.pa, i: 0]]; newName _ Rope.Concat[Rope.Substr[base: fileNames.first, start: 0, len: Rope.SkipTo[s: fileNames.first, pos: 0, skip: "-"]], "-*.ais"]; } ELSE { -- single file AIS image bps: [0..16] _ 0; IF data.abort THEN {data.abort _ FALSE; RETURN[NIL]}; -- set asynchronously by StopIfYouCan state.pa_ ImagerPixelArray.FromAIS[singleName]; [scanCount: state.scans, scanLength: state.pixels, scanMode: , bitsPerPixel: bps] _ AIS.ReadRaster[state.openFile]^; IF data.abort THEN {data.abort _ FALSE; RETURN[NIL]}; -- set asynchronously by StopIfYouCan state.op _ IF bps#0 THEN ImagerColorOperator.GrayLinearColorModel[sWhite: ImagerPixelArray.MaxSampleValue[pa: state.pa, i: 0], sBlack: 0.0] ELSE ImagerColorOperator.BlackColorModel[clear: FALSE]; newName _ singleName; }; state.active _ TRUE; }; StopIfYouCan: ENTRY Buttons.ButtonProc = { --pvList is a global list of all PreView Datas ENABLE UNWIND => NULL; KillIt: PROC [data: Data] = TRUSTED { IF data.process#NIL THEN {Process.Abort[data.process]; data.process _ NIL}; }; FOR l: LIST OF REF ANY _ pvList, l.rest UNTIL l=NIL DO data: PreView.Data _ NARROW[l.first]; data.abort _ TRUE; -- this aborts PD file painting, which can't properly use Process.Abort WITH data SELECT FROM ipData: IPData => KillIt[ipData]; aisData: AISData => KillIt[aisData]; gData: GData => KillIt[gData]; pressData: PressData => NULL; -- punt on Press files pdData: PDData => NULL; ENDCASE => ERROR; ENDLOOP; }; ResetProcess: PUBLIC ENTRY PROC [data: Data] = { <> ENABLE UNWIND => NULL; data.process _ NIL; }; SelectionOps: Buttons.ButtonProc = { data: Data _ NARROW[clientData]; viewer: ViewerClasses.Viewer _ BiScrollers.QuaBiScroller[data.preViewer].QuaViewer[inner: TRUE]; SELECT mouseButton FROM red => { -- center selection in viewer IF NOT data.bBox.active THEN GOTO NoSel; BiScrollers.Align[bs: BiScrollers.QuaBiScroller[data.preViewer], client: [variant: coord[x: data.bBox.rect.x+(data.bBox.rect.w/2.0), y: data.bBox.rect.y+(data.bBox.rect.h/2.0)]], viewer: [variant: fraction[fx: 0.5, fy: 0.5]], paint: TRUE]; }; yellow => { -- center selection in viewer then scale to fit inside viewer vH, vW, sH, sW: REAL _ 1.0; -- viewer and selection dimensions IF NOT data.bBox.active THEN GOTO NoSel; sH _ MAX[sH, data.bBox.rect.h]; sW _ MAX[sW, data.bBox.rect.w]; vH _ MAX[vH, viewer.ch]; vW _ MAX[vW, viewer.cw]; BiScrollers.Align[bs: BiScrollers.QuaBiScroller[data.preViewer], client: [variant: coord[x: data.bBox.rect.x+(data.bBox.rect.w/2.0), y: data.bBox.rect.y+(data.bBox.rect.h/2.0)]], viewer: [variant: fraction[fx: 0.5, fy: 0.5]], paint: FALSE]; IF NOT shift THEN BiScrollers.Scale[bs: BiScrollers.QuaBiScroller[data.preViewer], op: [variant: reset[] ], paint: FALSE ]; BiScrollers.Scale[bs: BiScrollers.QuaBiScroller[data.preViewer], op: [variant: byArg[arg: MIN[vW/sW, vH/sH]]], paint: TRUE ]; }; blue => { -- select entire page IF data.bBox.active THEN PreView.PVFeedback[data: data, v: BiScrollers.QuaBiScroller[data.preViewer].QuaViewer[inner: TRUE], op: remove]; -- remove any old selection data.bBox^ _ [active: TRUE, rect: [x: 0.0, y: 0.0, w: data.pageWidth, h: data.pageHeight], mode: waitingForSecondPoint, x0: 0.0, y0: 0.0, lastX: data.pageWidth, lastY: data.pageHeight]; -- fake the box into the right state to select the whole page PreView.PVFeedback[data: data, v: BiScrollers.QuaBiScroller[data.preViewer].QuaViewer[inner: TRUE], op: paint]; -- paint new selection }; ENDCASE => ERROR; EXITS NoSel => MessageWindow.Append["No PreView Selection", TRUE]; }; ToIP: Buttons.ButtonProc = { --parent: REF ANY, clientData: REF ANY, mouseButton: MouseButton _ red, shift, control: BOOL _ FALSE data: Data _ NARROW[clientData]; iv: ViewerClasses.Viewer _ BiScrollers.QuaBiScroller[data.preViewer].QuaViewer[inner: TRUE]; name: Rope.ROPE _ ViewerTools.GetSelectionContents[]; IF mouseButton#blue AND (data.bBox.rect.w=0 OR data.bBox.rect.h=0) THEN { MessageWindow.Append["Specify clipping box before left clicking ToIP", TRUE]; RETURN; }; IF name=NIL OR Rope.Length[name]=0 THEN { MessageWindow.Append["Select a file name before buttoning ToIP", TRUE]; RETURN; }; IF Rope.Length[FileNames.Directory[name]]=0 THEN name _ Rope.Concat[NARROW[ViewerOps.FetchProp[viewer: iv, prop: $PVWDir]], name]; PreView.DoFileOps[op: ipMaster, viewer: iv, data: data, fileName: name, clip: mouseButton#blue]; }; Stuff: Buttons.ButtonProc = { data: Data _ NARROW[clientData]; IF data.bBox.rect.w=0 OR data.bBox.rect.h=0 THEN { MessageWindow.Append["Specify clipping box before clicking Stuff", TRUE]; RETURN; }; data.stuffWithBorders _ mouseButton=blue; PreView.DoFileOps[op: stuff, viewer: BiScrollers.QuaBiScroller[data.preViewer].QuaViewer[inner: TRUE], data: data, fileName: NIL, clip: TRUE]; }; FirstPage: Buttons.ButtonProc = { data: Data _ NARROW[clientData]; DeltaPage[data, 1]; }; TurnPage: Buttons.ButtonProc = { data: Data _ NARROW[clientData]; where: INT _ IF mouseButton = red THEN +1 ELSE -1; DeltaPage[data, MIN[MAX[data.pageNumber+where, 1], (data.lastPageNumber)]]; }; LastPage: Buttons.ButtonProc = { data: Data _ NARROW[clientData]; DeltaPage[data, (data.lastPageNumber)]; }; PageNumber: Buttons.ButtonProc = { data: Data _ NARROW[clientData]; stream: IO.STREAM _ IO.RIS[ViewerTools.GetContents[data.pageNumberViewer]]; where: INT _ stream.GetInt[]; DeltaPage[data, MIN[MAX[where, 1], (data.lastPageNumber)]]; }; NormalizePageNumber: Sliders.FilterProc = { data: Data _ NARROW[clientData]; RETURN [Real.FDiv[Real.RoundI[value*(data.lastPageNumber)], (data.lastPageNumber)]] }; PageNumberSlider: Sliders.SliderProc = { data: Data _ NARROW[clientData]; SELECT reason FROM abort => { ViewerTools.SetContents[data.pageNumberViewer, IO.PutFR["%-g", IO.real[data.pageNumber]]]; }; move => { ViewerTools.SetContents[data.pageNumberViewer, IO.PutFR["%-g", IO.real[Real.RoundI[(data.lastPageNumber)*value]]]]; }; set => { DeltaPage[data, MIN[MAX[Real.RoundI[(data.lastPageNumber)*value], 1], (data.lastPageNumber)]]; }; ENDCASE; }; DeltaPage: PROCEDURE [data: Data, newvalue: INT] = { ViewerTools.SetContents[data.pageNumberViewer, IO.PutFR["%-g", IO.int[newvalue]]]; Sliders.SetContents[data.pageNumberSlider, Real.FDiv[newvalue, (data.lastPageNumber)]]; IF data.pageNumber=newvalue THEN RETURN; -- just did the initialization needed data.pageNumber _ newvalue; ViewerOps.PaintViewer[viewer: data.preViewer, hint: all, clearClient: TRUE]; }; MakePreViewer: Commander.CommandProc = { <<[cmd: Handle] RETURNS [result: REF _ NIL, msg: Rope.ROPE _ NIL];>> args: PreView.NameList _ LIST[]; --LIST OF Rope.ROPE nameList: PreView.NameList _ LIST[]; --LIST OF Rope.ROPE switches: PreView.Switches _ ALL[FALSE]; argLength: NAT _ 0; switchChar: CHAR = '-; [list: args, length: argLength] _ CommandTool.ParseToList[cmd: cmd, starExpand: TRUE, switchChar: switchChar ! CommandTool.Failed => CONTINUE; ]; IF args = NIL OR argLength < 1 THEN RETURN[$Failure, "Unable to parse command line"]; IF Rope.Fetch[base: args.first, index: 0] = switchChar THEN { tChar: CHAR; FOR iChar: INT IN [1..Rope.Length[args.first]) DO IF (tChar _ Ascii.Upper[Rope.Fetch[base: args.first, index: iChar]]) IN PreView.SwitchRange THEN switches[tChar] _ TRUE; ENDLOOP; args _ args.rest; }; IF switches['C] THEN { -- command arguments are RGB components of a single color image FOR a: PreView.NameList _ args, a.rest UNTIL a=NIL DO nameList _ CONS[FileNames.ResolveRelativePath[a.first], nameList]; ENDLOOP; [] _ CreatePreViewer[fileNames: nameList, switches: switches]; } ELSE FOR rl: PreView.NameList _ args, rl.rest UNTIL rl = NIL DO --open a PreViewer on each file [] _ CreatePreViewer[fileNames: LIST[FileNames.ResolveRelativePath[rl.first]], switches: switches]; ENDLOOP; }; PVChangedProc: UserProfile.ProfileChangedProc = { extensionList _ UserProfile.ListOfTokens[key: "PreView.Extensions", default: defaultExtensionList]; tryTioga _ UserProfile.Boolean[key: "PreView.TryTiogaOpen", default: FALSE]; }; PVListRemove: PUBLIC ENTRY PROC [ref: REF ANY] = { ENABLE UNWIND => NULL; pvList _ List.Remove[ref: ref, list: pvList]; }; PVListAdd: PUBLIC ENTRY PROC [list: LIST OF REF ANY] = { ENABLE UNWIND => NULL; pvList _ List.Append[l1: pvList, l2: list]; }; pvList: LIST OF REF ANY _ LIST[]; --shared defaultExtensionList: LIST OF Rope.ROPE = LIST["ip", "interpress", "press", "pd", "ais", "griffin"]; extensionList: LIST OF Rope.ROPE _ defaultExtensionList; tryTioga: BOOL _ FALSE; bsStyle: PUBLIC BiScrollers.BiScrollerStyle; pvBSClass: BiScrollers.BiScrollerClass; PVStart: PROC = { pvTIP: TIPUser.TIPTable _ TIPUser.InstantiateNewTIPTable["PreView.tip"]; bsStyle _ BiScrollers.GetStyle[]; -- default gets BiScrollersButtonned pvBSClass _ bsStyle.NewBiScrollerClass[[ flavor: $PreViewer, extrema: PreView.PVExtremaProc, notify: PreView.PVNotify, paint: PreView.PVPaint, destroy: PreView.PVDestroy, get: PreView.PVGetName, tipTable: pvTIP, cursor: crossHairsCircle, mayStretch: FALSE, -- NOT OK to scale X and Y differently vanilla: PreView.PVBasicTransformProc, --proc which provides the vanilla transform for BiScrollers preserve: [X: 0.0, Y: 1.0] --this specifies point that stays fixed when viewer size changes ]]; UserProfile.CallWhenProfileChanges[proc: PVChangedProc]; -- PVChangedProc called immediately after this registration call [] _ Buttons.Create[info: [name: "PVSTOP!"], proc: StopIfYouCan]; Commander.Register[key: "Preview", proc: MakePreViewer, doc: "Create a PreViewer for a Press, PD, Interpress, or AIS file" ]; }; PVStart[]; END.