PreViewTool.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Last Edited by: Ken Pier, October 9, 1986 11:47:31 am PDT
Mike Spreitzer November 14, 1986 8:18:29 pm PST
Bland, August 28, 1986 4:25:55 pm PDT
Eric Nickell, June 27, 1986 11:22:18 am PDT
Doug Wyatt, June 7, 1986 1:52:25 pm PDT
DIRECTORY
AIS, Ascii, BasicTime, BiScrollers, Buttons, Commander, CommandTool, Containers, Convert, FileNames, FS, GriffinImageUtils, Icons, Imager, ImagerBackdoor, ImagerColorOperator, ImagerMemory, ImagerPixelArray, Interminal, Interpress, IO, IPMaster, Labels, List, MessageWindow, PDFileReader, PDImageReader, PopUpButtons, PressReader, PreView, PreViewClient, Process, Real, Rope, Rules, ShowPress, Sliders, Terminal, TiogaMenuOps, TIPUser, UserProfile, ViewerClasses, ViewerOps, ViewerSpecs, ViewerTools;
PreViewTool: CEDAR MONITOR
IMPORTS AIS, Ascii, BiScrollers, --Buttons,-- Commander, CommandTool, Containers, Convert, FileNames, FS, GriffinImageUtils, Icons, Imager, ImagerBackdoor, ImagerColorOperator, ImagerMemory, ImagerPixelArray, Interminal, Interpress, IO, IPMaster, Labels, List, MessageWindow, PDFileReader, PDImageReader, PopUpButtons, PressReader, PreView, Process, Real, Rope, Rules, ShowPress, Sliders, Terminal, 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
pointsPerInch: REAL = 72.0;
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];
buttonAlign: INTEGER ← -2; -- align standard viewer with PopUp buttons
labelAlign: INTEGER ← -1; -- align label with PopUp buttons
entryHSpace: INTEGER ← 2; -- horizontal space between items on a line
curIndent: INTEGER ← 0;
secondLine: INTEGER ← 14;
bsY: INTEGER ← 31;
selClass: PopUpButtons.Class = PopUpButtons.MakeClass[[
proc: SelectionOps,
choices: LIST[
[$Center, "Center PreView selection in viewer"],
[$CenterAndFit, "Center and fit PreView selection in viewer"],
[$CenterAndScale, "Center and scale PreView selection to viewer"],
[$SelectPage, "Set PreView selection to entire page"],
[$SetSelection, "Set PreView selection to \"x y w h\" (in inches)"]
],
doc: "Selection: selection operations for current page"
]];
stuffClass: PopUpButtons.Class = PopUpButtons.MakeClass[[
proc: Stuff,
choices: LIST[
[$Selection, "Stuff PreView selection"],
[$Page, "Stuff entire page"],
PopUpButtons.nullChoice,
[$Fitted, "Fit and Stuff PreView selection"],
[$PageFitted, "Fit and Stuff entire page"],
PopUpButtons.nullChoice,
[$Bordered, "Stuff PreView selection with borders"],
[$PageBordered, "Stuff entire page with borders"],
PopUpButtons.nullChoice,
[$BorderedAndFitted, "Fit and Stuff PreView selection with borders"],
[$PageBorderedAndFitted, "Fit and Stuff entire page with borders"],
PopUpButtons.nullChoice
],
doc: "Stuff: stuff PreView images into Tioga document"
]];
toIPClass: PopUpButtons.Class = PopUpButtons.MakeClass[[
proc: ToIP,
choices: LIST[
[$Selection, "PreView selection to IP file"],
[$Page, "Entire page to IP file"]
],
doc: "ToIP: convert to Interpress and store in (Tioga) selected filename "
]];
pageClass: PopUpButtons.Class = PopUpButtons.MakeClass[[
proc: PageTurn,
choices: LIST[
[$TurnForward, "Display next page"],
PopUpButtons.nullChoice,
[$TurnBackward, "Display previous page"],
[$FirstPage, "Display first page"],
[$FromTiogaSelection, "Display (Tioga) selected page number"],
[$LastPage, "Display last page"]
],
doc: "Page: move among pages in PreView document"
]];
IPLogError: PUBLIC Interpress.LogProc = {
[class: INT, code: ATOM, explanation: ROPE]
MessageWindow.Append[message: Rope.Concat["InterpressMaster Error: ", explanation], clearFirst: TRUE];
MessageWindow.Blink[];
};
WhichFileType: PROC [fileName: Rope.ROPE] RETURNS [PreView.FileInfo] = {
expects a file name which may not have an extension; will try extensions .ip, .interpress, .press, .pd, .ais .griffin in that order
fname: Rope.ROPENIL;
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
did not find full name, so try a few extensions
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] = {
given a filename, figure out if it is an interpress, press, PD, AIS, or Griffin file (or none)
uses the extension as a hint as to the filetype.
fileInfo ← NEW[PreView.FileInfoRep ← [] ]; --initialize to fileType none, etc.
{
ref: REF ANYNIL;
s: IO.STREAMFS.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;
Extension as hint did not help; so try all other possibilities
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, xSize, ySize: REAL] RETURNS [preViewer: ViewerClasses.Viewer] = {
bs: BiScrollers.BiScroller ← NIL;
tV: ViewerClasses.Viewer;
data: Data ← NIL;
fileInfo: PreView.FileInfo ← NIL;
button: Buttons.Button;
rule: Rules.Rule;
versionSpecified: BOOL ← Rope.SkipTo[s: fileNames.first, skip: "!"]#Rope.Length[fileNames.first];
curIndent ← 0;
fileInfo ← WhichFileType[fileNames.first]; -- adds file extension to the named file if needed
SELECT fileInfo.filetype FROM
ip => {
ipmaster: Interpress.Master ← Interpress.Open[fileName: fileInfo.fullFName, log: IPLogError !
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 ySize*72.0, pageWidth: IF switches['V] THEN versatecPageWidth ELSE xSize*72.0, 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: ySize*72.0, pageWidth: xSize*72.0, 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.
[fileInfo.fullFName, versionSpecified] ← InitAIS[data: aisData, fileNames: fileNames, singleName: fileInfo.fullFName];
IF 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: ySize*72.0, pageWidth: xSize*72.0, 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;
};
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: FALSE],
iconic: TRUE,
menu: NIL,
icon: pvIcon,
data: data,
scrollable: FALSE],
paint: FALSE ];
bs ← bsStyle.CreateBiScroller[
class: pvBSClass,
info: [
parent: data.container,
wx: 0,
wy: bsY,
border: FALSE,
scrollable: FALSE,
data: data],
paint: FALSE ];
tV ← BiScrollers.CreateScale[ [parent: preViewer, wx: 0, wy: 0, border: FALSE], bs];
tV ← BiScrollers.CreateRotate[ [parent: preViewer, wx: tV.wx+tV.ww+entryHSpace, wy: 0, border: FALSE], bs];
tV ← BiScrollers.CreateFit[ [parent: preViewer, wx: tV.wx+tV.ww+entryHSpace, wy: 0, border: FALSE], bs];
tV ← BiScrollers.CreateReset[ [parent: preViewer, wx: tV.wx+tV.ww+entryHSpace, wy: 0, border: FALSE], bs];
tV ← BiScrollers.CreateEdge[ [parent: preViewer, wx: tV.wx+tV.ww+entryHSpace, wy: 0, border: FALSE], bs];
tV ← BiScrollers.CreatePrev[ [parent: preViewer, wx: tV.wx+tV.ww+entryHSpace, wy: 0, border: FALSE], bs];
button ← stuffClass.Instantiate[viewerInfo: [ name: "Stuff", wx: curIndent, wy: secondLine, border: FALSE, parent: data.container], instanceData: data, paint: FALSE];
curIndent ← button.wx + button.ww;
button ← toIPClass.Instantiate[viewerInfo: [ name: "ToIP", wx: curIndent, wy: secondLine, border: FALSE, parent: data.container], instanceData: data, paint: FALSE];
curIndent ← button.wx + button.ww;
button ← selClass.Instantiate[viewerInfo: [ name: "Selection", wx: curIndent, wy: secondLine, border: FALSE, parent: data.container], instanceData: data, paint: FALSE];
curIndent ← button.wx + button.ww;
button ← pageClass.Instantiate[viewerInfo: [ name: "Page", wx: curIndent, wy: secondLine, border: FALSE, parent: data.container], instanceData: data, paint: FALSE];
curIndent ← button.wx + button.ww;
button ← Labels.Create[
info: [
name: "AtPage:",
wx: curIndent,
wy: secondLine+labelAlign,
border: FALSE,
parent: data.container],
paint: FALSE];
curIndent ← button.wx + button.ww;
data.pageNumberViewer ← ViewerTools.MakeNewTextViewer[
info: [
wx: curIndent,
wy: secondLine+ViewerSpecs.windowBorderSize+buttonAlign,
ww: 40,
wh: ViewerSpecs.scrollBarW+2*ViewerSpecs.windowBorderSize,
parent: data.container,
border: FALSE,
scrollable: FALSE],
paint: FALSE];
ViewerTools.InhibitUserEdits[data.pageNumberViewer];
curIndent ← data.pageNumberViewer.wx + data.pageNumberViewer.ww;
data.pageNumberSlider ← Sliders.Create[
info: [
wx: curIndent,
wy: secondLine,
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: secondLine+ViewerSpecs.captionHeight+4*ViewerSpecs.windowBorderSize,
wh: ViewerSpecs.menuBarHeight]];
Containers.ChildXBound[data.container, rule];
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.ROPENIL, versionSpecified: BOOLFALSE] = {
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 ← fileNames.rest.rest.first;
grnName: Rope.ROPE ← fileNames.rest.first;
bluName: Rope.ROPE ← fileNames.first;
fullCP: FS.ComponentPositions ← FS.ExpandName[singleName].cp; -- a full FName
grnCP: FS.ComponentPositions ← FS.ExpandName[grnName].cp; -- not a full FName
IF data.abort THEN {data.abort ← FALSE; RETURN[NIL]}; -- set asynchronously by CheckForAbort
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 CheckForAbort
state.op ← ImagerColorOperator.RGBLinearColorModel[maxSampleValue: ImagerPixelArray.MaxSampleValue[pa: state.pa, i: 0]];
Now construct a viewer caption like Foo-*.ais!33
newName ← Rope.Concat[Rope.Substr[base: fileNames.first, start: 0, len: Rope.SkipTo[s: fileNames.first, pos: 0, skip: "-"]], "-*.ais!"]; -- everything thru the name base
newName ← Rope.Concat[newName, Rope.Substr[base: singleName, start: fullCP.ver.start, len: fullCP.ver.length] ];
IF grnCP.ver.length#0 THEN versionSpecified ← TRUE;
}
ELSE { -- single file AIS image
bps: [0..16] ← 0;
IF data.abort THEN {data.abort ← FALSE; RETURN[NIL]}; -- set asynchronously by CheckForAbort
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 CheckForAbort
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;
};
CheckForAbort: PROC ~ {
tsc: TIPUser.TIPScreenCoords ~ NEW[TIPUser.TIPScreenCoordsRec];
Process.SetPriority[Process.priorityRealTime]; --VERY high!
DO--Forever
vt: Terminal.Virtual ~ Terminal.Current[];
keyBits: Terminal.KeyBits ~ Terminal.GetKeys[vt: vt];
IF (keyBits[LeftShift]=down OR keyBits[RightShift]=down) AND keyBits[Spare3]=down THEN {
CheckForAbortInternal: ENTRY PROC ~ {
ENABLE UNWIND => NULL;
ref: REF ~ BiScrollers.ClientDataOfViewer[viewer];
IF ref#NIL THEN WITH ref SELECT FROM
data: Data => {
KillIt: PROC [data: Data] = TRUSTED {
IF data.process#NIL THEN {Process.Abort[data.process]; data.process ← NIL};
};
WITH data SELECT FROM
ipData: IPData => KillIt[ipData];
aisData: AISData => KillIt[aisData];
gData: GData => KillIt[gData];
pressData: PressData => KillIt[pressData];
pdData: PDData => data.abort ← TRUE; -- don't use Process.Abort
ENDCASE => ERROR;
};
ENDCASE;
};
mouse: Interminal.MousePosition ~ Interminal.GetMousePosition[];
viewer: ViewerClasses.Viewer;
tsc^ ← [
mouseX: mouse.mouseX,
mouseY: (IF mouse.color THEN vt.colorHeight ELSE vt.bwHeight) - mouse.mouseY,
color: mouse.color
];
viewer ← ViewerOps.MouseInViewer[tsc: tsc].viewer;
IF viewer#NIL AND BiScrollers.ViewerIsABiScroller[viewer] THEN CheckForAbortInternal[];
};
Process.Pause[ticks: Process.SecondsToTicks[2]];
ENDLOOP;
};
ResetProcess: PUBLIC ENTRY PROC [data: Data] = {
this PROC is here solely to synchronize with the Paint Proc in PreViewImpl
ENABLE UNWIND => NULL;
data.process ← NIL;
};
SelectionOps: PopUpButtons.PopUpButtonProc = { --PROC [viewer: Viewer, instanceData, classData, key: REF ANY]
data: Data ← NARROW[instanceData];
viewer: ViewerClasses.Viewer ← BiScrollers.QuaBiScroller[data.preViewer].QuaViewer[inner: TRUE];
SELECT key FROM
$Center => { -- 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];
};
$CenterAndFit, $CenterAndScale => { -- 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 key=$CenterAndFit THEN BiScrollers.Scale[bs: BiScrollers.QuaBiScroller[data.preViewer], op: [variant: reset[] ], paint: FALSE ]; -- reset scale before fitting
BiScrollers.Scale[bs: BiScrollers.QuaBiScroller[data.preViewer], op: [variant: byArg[arg: MIN[vW/sW, vH/sH]]], paint: TRUE ];
};
$SelectPage => { -- 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
};
$SetSelection => { -- select x y w h (in inches)
selAsRope: Rope.ROPE ← ViewerTools.GetSelectionContents[];
selAsStream: IO.STREAM = IO.RIS[selAsRope];
sel: Imager.Rectangle;
{ENABLE IO.Error, IO.EndOfStream => {
MessageWindow.Append["Select \"x y w h\" (in inches) before clicking", TRUE];
GOTO NeverMind;
};
sel.x ← selAsStream.GetReal[] * pointsPerInch;
sel.y ← selAsStream.GetReal[] * pointsPerInch;
sel.w ← selAsStream.GetReal[] * pointsPerInch;
sel.h ← selAsStream.GetReal[] * pointsPerInch;
};
IF data.bBox.active THEN PreView.PVFeedback[data: data, v: viewer, op: remove];
data.bBox^ ← [active: TRUE, rect: sel, mode: waitingForSecondPoint, lastX: sel.x+sel.w, lastY: sel.y+sel.h, x0: sel.x, y0: sel.y];
PreView.PVFeedback[data: data, v: viewer, op: paint];
EXITS NeverMind => NULL;
};
ENDCASE => ERROR;
EXITS
NoSel => MessageWindow.Append["No PreView Selection", TRUE];
};
Stuff: PopUpButtons.PopUpButtonProc = { --PROC [viewer: Viewer, instanceData, classData, key: REF ANY]
data: Data ← NARROW[instanceData];
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;
data.stuffWithFit ← shift;
IF key=$Page OR key=$PageFitted OR key=$PageBordered OR key=$PageFitted THEN {
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
}
ELSE 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 ← key=$Bordered OR key=$BorderedAndFitted OR key=$PageBordered OR key=$PageBorderedAndFitted;
data.stuffWithFit ← key=$Fitted OR key=$BorderedAndFitted OR key=$PageFitted OR key=$PageBorderedAndFitted;
PreView.DoFileOps[op: stuff, viewer: BiScrollers.QuaBiScroller[data.preViewer].QuaViewer[inner: TRUE], data: data, fileName: NIL, clip: TRUE];
};
ToIP: PopUpButtons.PopUpButtonProc = { --PROC [viewer: Viewer, instanceData, classData, key: REF ANY]
data: Data ← NARROW[instanceData];
iv: ViewerClasses.Viewer ← BiScrollers.QuaBiScroller[data.preViewer].QuaViewer[inner: TRUE];
name: Rope.ROPE ← ViewerTools.GetSelectionContents[];
IF key=$Selection 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: key=$Selection];
};
PageTurn: PopUpButtons.PopUpButtonProc = { --PROC [viewer: Viewer, instanceData, classData, key: REF ANY]
data: Data ← NARROW[instanceData];
SELECT key FROM
$FirstPage => DeltaPage[data, 1];
$TurnForward => DeltaPage[data, MIN[MAX[data.pageNumber+1, 1], (data.lastPageNumber)]];
$TurnBackward => DeltaPage[data, MIN[MAX[data.pageNumber-1, 1], (data.lastPageNumber)]];
$LastPage => DeltaPage[data, data.lastPageNumber];
$FromTiogaSelection => {
stream: IO.STREAMIO.RIS[ViewerTools.GetSelectionContents[]];
where: INT ← stream.GetInt[ ! IO.Error, IO.EndOfStream => {
MessageWindow.Append["Select a valid page number", TRUE];
GOTO Abort;
};
];
DeltaPage[data, MIN[MAX[where, 1], (data.lastPageNumber)]];
};
ENDCASE => ERROR;
EXITS
Abort => NULL;
};
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: REFNIL, msg: Rope.ROPENIL];
ENABLE Convert.Error => {
result ← $Failure;
msg ← "Preview: Specify positive real numbers for page sizes";
GOTO Abort;
};
xSize: REAL ← 8.5; -- default size in inches
ySize: REAL ← 11.0; -- default size in inches
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['S] THEN { -- command arguments are two real numbers specifying page size
xSize ← Convert.RealFromRope[args.first];
args ← args.rest;
ySize ← Convert.RealFromRope[args.first];
args ← args.rest;
IF xSize<=0.1 OR ySize <=0.1 THEN {
result ← $Failure;
msg ← "Preview: Specify positive real numbers for page sizes";
GOTO Abort;
};
};
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, xSize: xSize, ySize: ySize];
}
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, xSize: xSize, ySize: ySize];
ENDLOOP;
EXITS
Abort => NULL;
};
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 ANYLIST[]; --shared
defaultExtensionList: LIST OF Rope.ROPE = LIST["ip", "interpress", "press", "pd", "ais", "griffin"];
extensionList: LIST OF Rope.ROPE ← defaultExtensionList;
tryTioga: BOOLFALSE;
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
TRUSTED {Process.Detach[FORK CheckForAbort[]]};
Commander.Register[key: "Preview", proc: MakePreViewer, doc: "Create a PreViewer for a Press, PD, Interpress, or AIS file" ];
};
PVStart[];
END.