ShowPDTool.mesa
Last Edited by: Ken Pier, July 11, 1985 3:08:54 pm PDT
Michael Plass, March 13, 1984 2:23:30 pm PST
DIRECTORY
Buttons, Commander, Containers, FS, Imager, ImagerBackdoor, IO, MessageWindow, Real, Rope, Rules, ShowPD, PDFileFormat, PDFileReader, PDReaderPage, Process, Sliders, ViewerClasses, ViewerOps, ViewerSpecs, ViewerTools, ImagerPixelMap;
ShowPDTool: CEDAR MONITOR
IMPORTS Buttons, Commander, Containers, FS, Imager, ImagerBackdoor, IO, MessageWindow, PDFileReader, PDReaderPage, Process, Real, Rope, Rules, Sliders, ViewerOps, ViewerSpecs, ViewerTools, ImagerPixelMap
EXPORTS ShowPD = BEGIN
pdViewerClass: ViewerClasses.ViewerClass ← NEW[ViewerClasses.ViewerClassRec];
ShowData: TYPE = ShowPD.ShowData;
ShowDataRec: TYPE = ShowPD.ShowDataRec;
pdPageSize: REAL = 11.0*72.0; -- points
screenResolution: REAL = 72.0;
viewerOverheadSize: INT = (ViewerSpecs.captionHeight + ViewerSpecs.menuHeight + ViewerSpecs.menuBarHeight + ViewerSpecs.windowBorderSize*2);
visibleGrey: Imager.Color ← ImagerBackdoor.MakeStipple[122645B];
invisibleGrey: Imager.Color ← ImagerBackdoor.MakeStipple[100040B];
CreateShowViewer: PUBLIC PROC[fileName: Rope.ROPE, reduction: REAL ← 1.0] RETURNS[pdViewer: ViewerClasses.Viewer] = TRUSTED {
myShowData: ShowData;
curIndent: INTEGER ← 0;
topLine: INTEGER ← 0;
button: Buttons.Button;
rule: Rules.Rule;
file: PDFileReader.Handle←NIL;
file ← PDFileReader.Open[fileName !
FS.Error => CONTINUE;
PDFileReader.Error => {
MessageWindow.Append[message: Rope.Cat[description, " for ", fileName], clearFirst: TRUE];
MessageWindow.Blink[];
GOTO Quit;
};
PDFileReader.Warning => {
MessageWindow.Append[message: Rope.Cat[description, " for ", fileName], clearFirst: TRUE];
MessageWindow.Blink[];
GOTO Quit;
};
];
IF file = NIL THEN {
fileName ← Rope.Concat[fileName, ".pd"];
file ← PDFileReader.Open[fileName !
FS.Error => {
MessageWindow.Append[message: Rope.Cat["Can't open ShowPD viewer on ", fileName, " | "], clearFirst: TRUE];
MessageWindow.Append[message: error.explanation, clearFirst: FALSE];
MessageWindow.Blink[];
GOTO Quit;
};
PDFileReader.Error => {
MessageWindow.Append[message: Rope.Cat[description, " for ", fileName], clearFirst: TRUE];
MessageWindow.Blink[];
GOTO Quit;
};
PDFileReader.Warning => {
MessageWindow.Append[message: Rope.Cat[description, " for ", fileName], clearFirst: TRUE];
MessageWindow.Blink[];
GOTO Quit;
};
];
};
myShowData ← NEW[ ShowDataRec ← [show: file, pageNumber: 1, top: pdPageSize, height: 0.0]];
[myShowData.pageStructure, myShowData.lastPageNumber] ← PDReaderPage.GetPageStructure[file];
myShowData.scaleFactor ← screenResolution/(file.herald.fResolution*reduction);
myShowData.pdContainer ← Containers.Create[
info: [
name: fileName,
iconic: TRUE,
data: myShowData,
scrollable: FALSE],
paint: FALSE ];
button ← Buttons.Create[
info: [
name: "FirstPage",
wx: curIndent,
wy: topLine,
border: FALSE,
parent: myShowData.pdContainer],
proc: FirstPage,
clientData: myShowData,
documentation: "Left-click for the first page of the PD file",
paint: FALSE];
curIndent ← button.wx + button.ww;
button ← Buttons.Create[
info: [
name: "TurnPage",
wx: curIndent,
wy: topLine,
border: FALSE,
parent: myShowData.pdContainer],
proc: TurnPage,
clientData: myShowData,
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: myShowData.pdContainer],
proc: LastPage,
clientData: myShowData,
documentation: "Left-click for last page in PD file",
paint: FALSE];
curIndent ← button.wx + button.ww;
button ← Buttons.Create[
info: [
name: "Page",
wx: curIndent,
wy: topLine,
border: FALSE,
parent: myShowData.pdContainer],
proc: PageNumber,
clientData: myShowData,
documentation: "Left-click for selected page number",
paint: FALSE];
curIndent ← button.wx + button.ww;
myShowData.pageNumberViewer ← ViewerTools.MakeNewTextViewer[
info: [
wx: curIndent,
wy: topLine+ViewerSpecs.windowBorderSize,
ww: 40,
wh: ViewerSpecs.scrollBarW+2*ViewerSpecs.windowBorderSize,
parent: myShowData.pdContainer,
border: FALSE,
scrollable: FALSE],
paint: FALSE];
curIndent ← myShowData.pageNumberViewer.wx + myShowData.pageNumberViewer.ww;
myShowData.pageNumberSlider ← Sliders.Create[
info: [
wx: curIndent,
wy: topLine,
ww: myShowData.pdContainer.ww-curIndent,
wh: ViewerSpecs.scrollBarW+2*ViewerSpecs.windowBorderSize,
border: FALSE,
parent: myShowData.pdContainer,
scrollable: FALSE],
filterProc: NormalizePageNumber,
sliderProc: PageNumberSlider,
orientation: horizontal,
foreground: visibleGrey,
background: invisibleGrey,
clientData: myShowData,
paint: FALSE];
Containers.ChildXBound[myShowData.pdContainer, myShowData.pageNumberSlider];
rule ← Rules.Create[
info: [
parent: myShowData.pdContainer,
wx: 0,
wy: topLine+ViewerSpecs.captionHeight+4*ViewerSpecs.windowBorderSize,
wh: ViewerSpecs.menuBarHeight]];
Containers.ChildXBound[myShowData.pdContainer, rule];
myShowData.pdViewer ← pdViewer ← ViewerOps.CreateViewer[
flavor: $PD,
info: [
name: fileName,
parent: myShowData.pdContainer,
wx: 0,
wy: topLine+ViewerSpecs.captionHeight+5*ViewerSpecs.windowBorderSize,
border: FALSE,
scrollable: TRUE,
data: myShowData],
paint: FALSE ];
Containers.ChildXBound[myShowData.pdContainer, myShowData.pdViewer];
Containers.ChildYBound[myShowData.pdContainer, myShowData.pdViewer];
ViewerOps.PaintViewer[viewer: myShowData.pdContainer, hint: all];
DeltaPage[myShowData, 1];
EXITS
Quit => RETURN;
};
NormalizePageNumber: Sliders.FilterProc = TRUSTED {
my: ShowData ← NARROW[clientData];
RETURN [Real.FDiv[Real.RoundI[value*(my.lastPageNumber)], (my.lastPageNumber)]]
};
FirstPage: Buttons.ButtonProc = TRUSTED {
my: ShowData ← NARROW[clientData];
DeltaPage[my, 1];
my.abortPainting←TRUE;
Process.Detach[FORK PaintIt[my.pdViewer, my, pdPageSize]];
};
TurnPage: Buttons.ButtonProc = TRUSTED {
my: ShowData ← NARROW[clientData];
where: INTIF mouseButton = red THEN +1 ELSE -1;
DeltaPage[my, MIN[MAX[my.pageNumber+where, 1], (my.lastPageNumber)]];
my.abortPainting←TRUE;
Process.Detach[FORK PaintIt[my.pdViewer, my, pdPageSize]];
};
LastPage: Buttons.ButtonProc = TRUSTED {
my: ShowData ← NARROW[clientData];
DeltaPage[my, (my.lastPageNumber)];
my.abortPainting←TRUE;
Process.Detach[FORK PaintIt[my.pdViewer, my, pdPageSize]];
};
PageNumber: Buttons.ButtonProc = TRUSTED {
my: ShowData ← NARROW[clientData];
stream: IO.STREAMIO.RIS[ViewerTools.GetContents[my.pageNumberViewer]];
where: INT ← stream.GetInt[];
DeltaPage[my, MIN[MAX[where, 1], (my.lastPageNumber)]];
my.abortPainting←TRUE;
Process.Detach[FORK PaintIt[my.pdViewer, my, pdPageSize]];
};
PageNumberSlider: Sliders.SliderProc = TRUSTED {
my: ShowData ← NARROW[clientData];
SELECT reason FROM
abort => {
ViewerTools.SetContents[my.pageNumberViewer, IO.PutFR["%-g", IO.real[my.pageNumber]]];
};
move => {
ViewerTools.SetContents[my.pageNumberViewer, IO.PutFR["%-g", IO.real[Real.RoundI[(my.lastPageNumber)*value]]]];
};
set => {
DeltaPage[my, MIN[MAX[Real.RoundI[(my.lastPageNumber)*value], 1], (my.lastPageNumber)]];
my.abortPainting←TRUE;
Process.Detach[FORK PaintIt[my.pdViewer, my, pdPageSize]];
};
ENDCASE;
};
--PaintProc: TYPE = PROC [self: Viewer, context: Imager.Context, whatChanged: REF ANY, clear: BOOL];
PDPaint: ViewerClasses.PaintProc = TRUSTED {
bbox: Imager.Rectangle;
showData: ShowData ← NARROW[self.data];
herald: PDFileFormat.Herald←showData.show.herald;
IF showData.clearClient THEN RETURN; --dummy call to clear the viewer
WITH whatChanged SELECT FROM
handle: PDReaderPage.Handle => {
scaleFactor: REAL ← showData.scaleFactor;
context.TranslateT[[0, self.ch-showData.top]];
IF herald.imageSSize<herald.imageFSize THEN { --portrait mode PD file
context.TranslateT[[herald.imageSSize*scaleFactor, 0]];
context.RotateT[90.0];
};
context.ScaleT[scaleFactor];
bbox ← ImagerBackdoor.GetBounds[context];
IF bbox.y <= (herald.imageSSize-handle.pixelMap.sOrigin) THEN {
t: ImagerPixelMap.PixelMap ~ handle.pixelMap;
w: ImagerPixelMap.DeviceRectangle ~ ImagerPixelMap.Window[t];
IF w.sSize > 0 THEN {
context.SetColor[Imager.black];
ImagerBackdoor.DrawBits[context: context, base: handle.pixelMap.refRep.pointer, wordsPerLine: handle.pixelMap.refRep.rast, sMin: t.sMin, fMin: t.fMin, fSize: t.fSize, sSize: t.sSize, tx: w.fMin, ty: herald.imageSSize-w.sMin+w.sSize];
};
}
ELSE showData.abortPainting←TRUE; --abort my own painting !!
};
ENDCASE => {
showData.abortPainting←TRUE; --abort clients painting
Process.Detach[FORK PaintIt[self: self, data: showData, newvalue: showData.top]];
};
}; -- PDPaint
PDScroll: ViewerClasses.ScrollProc = TRUSTED {
my: ShowData ← NARROW[self.data];
my.height ← self.ch;
SELECT op FROM
query => RETURN [
top: Real.Fix[(1.0-my.top/pdPageSize)*100.0],
bottom: Real.Fix[(1.0-(my.top-my.height)/pdPageSize)*100.0]];
up => IF my.top > my.height THEN {
my.abortPainting←TRUE;
Process.Detach[FORK PaintIt[self, my, MAX[my.top-amount, my.height]]];
};
down => IF my.top < pdPageSize THEN {
my.abortPainting←TRUE;
Process.Detach[FORK PaintIt[self, my, MIN[my.top+amount, pdPageSize]]];
};
thumb => {
my.abortPainting←TRUE;
Process.Detach[FORK PaintIt[self, my, MAX[MIN[(100-amount)*pdPageSize/100, pdPageSize], my.height]]];
};
ENDCASE => ERROR;
}; -- PDScroll
--DestroyProc: TYPE = PROC [self: Viewer] ;
PDDestroy: ViewerClasses.DestroyProc = TRUSTED {
showData: ShowData ← NARROW[self.data];
showData.abortPainting←TRUE; --can't be SURE this will stop reading stream
Process.Detach[FORK PDDestroyInterlocked[showData]];
}; -- PDDestroy
PDDestroyInterlocked: ENTRY PROCEDURE [showData: ShowData] = {
PDFileReader.Close[handle: showData.show];
}; -- PDDestroy
PaintIt: ENTRY PROCEDURE [self: ViewerClasses.Viewer, data: ShowData, newvalue: REAL] = {
page: PDReaderPage.PageRecRef;
DeltaTop[data, newvalue];
page ← PDReaderPage.ResetToPage[data: data];
data.abortPainting←FALSE; --may be set true later by Viewers
IF page#NIL THEN []←PDReaderPage.InterpretPage[handle: data.show, viewer: self, pages: data.pageStructure];
};
DeltaPage: PROCEDURE [data: ShowData, newvalue: INT] = {
data.pageNumber ← newvalue;
ViewerTools.SetContents[data.pageNumberViewer, IO.PutFR["%-g", IO.int[newvalue]]];
Sliders.SetContents[data.pageNumberSlider, Real.FDiv[newvalue, (data.lastPageNumber)]];
};
DeltaTop: PROCEDURE [data: ShowData, newvalue: REAL] = {
data.top ← newvalue;
};
CommandProc: TYPE = PROC [cmd: Handle] RETURNS [result: REFNIL, msg: Rope.ROPENIL];
Break: PROC [char: CHAR] RETURNS [IO.CharClass] = {
IF char = '← OR char = '; THEN RETURN [break];
IF char = ' OR char = '  OR char = ', OR char = '\n THEN RETURN [sepr];
RETURN [other];
};
MakeShowPD: Commander.CommandProc = TRUSTED {
reduction: REAL ← 1;
fileName: Rope.ROPENIL;
cis: IO.STREAMIO.RIS[cmd.commandLine];
fileName ← IO.GetTokenRope[cis, Break ! IO.EndOfStream => CONTINUE].token;
reduction ← IO.GetReal[cis ! IO.EndOfStream, IO.Error => CONTINUE];
[] ← CreateShowViewer[fileName, reduction];
}; -- MakeShowPD
pdViewerClass.paint ← PDPaint;
pdViewerClass.destroy ← PDDestroy;
pdViewerClass.scroll ← PDScroll;
ViewerOps.RegisterViewerClass[$PD, pdViewerClass];
Commander.Register[
key: "ShowPD",
proc: MakeShowPD,
doc: "Show a PD file in a Viewer" ];
END. -- ShowPDTool.