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.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
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 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;
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.
ROPE ←
NIL, versionSpecified:
BOOL ←
FALSE] = {
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.STREAM ← IO.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;
};
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];
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;
};
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
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.