File: GGFileImpl.mesa
Copyright Ó 1987, 1989 by Xerox Corporation. All rights reserved.
Pier, April 23, 1992 4:51 pm PDT
Kurlander, September 1, 1987 1:47:01 pm PDT
Bier, March 18, 1992 6:25 pm PST
Doug Wyatt, December 15, 1989 8:35:22 pm PST
Contents: Created October 12, 1987 by merging GGFileInImpl and GGFileOutImpl
DIRECTORY
Atom, CardTab, CodeTimer, Convert, Feedback, FeedbackTypes, GGBasicTypes, GGCoreOps, GGEvent, GGFileIn, GGFileOut, GGFont, GGInterfaceTypes, GGModelTypes, GGParseIn, GGParseOut, GGScene, GGSegmentTypes, GGSelect, GGSlice, GGSliceOps, GGState, GGUIUtility, GGUtility, Imager, ImagerColor, ImagerColorPrivate, ImagerTransformation, IO, Real, RefTab, Rope, ViewerClasses;
GGFileImpl: CEDAR PROGRAM
IMPORTS Atom, CardTab, CodeTimer, Convert, Feedback, GGCoreOps, GGEvent, GGFont, GGParseIn, GGParseOut, GGScene, GGSelect, GGSlice, GGSliceOps, GGState, GGUIUtility, GGUtility, Imager, ImagerColor, ImagerColorPrivate, IO, Real, RefTab, Rope
EXPORTS GGFileIn, GGFileOut = BEGIN
Camera: TYPE = GGModelTypes.Camera;
Caret: TYPE = GGInterfaceTypes.Caret;
Color: TYPE = Imager.Color;
DefaultData: TYPE = GGModelTypes.DefaultData;
MsgRouter: TYPE = FeedbackTypes.MsgRouter;
FontData: TYPE = GGModelTypes.FontData;
GGData: TYPE = GGInterfaceTypes.GGData;
Point: TYPE = GGBasicTypes.Point;
Scene: TYPE = GGModelTypes.Scene;
Segment: TYPE = GGSegmentTypes.Segment;
SegmentClass: TYPE = GGSegmentTypes.SegmentClass;
Slice: TYPE = GGModelTypes.Slice;
SliceClass: TYPE = GGModelTypes.SliceClass;
SliceGenerator: TYPE = GGModelTypes.SliceGenerator;
StrokeEnd: TYPE = Imager.StrokeEnd;
StrokeJoint: TYPE = Imager.StrokeJoint;
Traj: TYPE = GGModelTypes.Traj;
Viewer: TYPE = ViewerClasses.Viewer;
Problem: PUBLIC SIGNAL [msg: Rope.ROPE] = Feedback.Problem;
OutputPixelArrayTable: TYPE = REF OutputPixelArrayTableObj;
OutputPixelArrayTableObj: TYPE = RECORD [
nextIndex: NAT ← 0,
table: RefTab.Ref ← NIL -- a mapping from pixel arrays to small integers
];
OutputColorTable: TYPE = REF OutputColorTableObj;
OutputColorTableObj: TYPE = RECORD [
pixelArrayTable: OutputPixelArrayTable,
nextColorIndex: NAT ← 0,
constantOp: CardTab.Ref, -- keys off the intensity
constantSpecial: RefTab.Ref, -- keys off the REF
sampled: RefTab.Ref -- keys off the REF, used for sampled colors and sampled blacks
];
InputPixelArrayTable: TYPE = REF InputPixelArrayTableObj;
InputPixelArrayTableObj: TYPE = RECORD [
table: CardTab.Ref ← NIL -- a mapping from small integers to pixel arrays
];
InputColorTable: TYPE = REF InputColorTableObj;
InputColorTableObj: TYPE = RECORD [
pixelArrayTable: InputPixelArrayTable,
colors: CardTab.Ref ← NIL -- a mapping from small integers to colors
];
CreateOutputColorTable: PROC [] RETURNS [ct: OutputColorTable] = {
ct ← NEW[OutputColorTableObj];
ct.pixelArrayTable ← NEW[OutputPixelArrayTableObj];
ct.pixelArrayTable.table ← RefTab.Create[mod: 17];
ct.constantOp ← CardTab.Create[mod: 17];
ct.constantSpecial ← RefTab.Create[mod: 11];
ct.sampled ← RefTab.Create[mod: 5];
};
NatRef: TYPE = REF NAT;
PickANumber: PROC [ct: OutputColorTable] RETURNS [natRef: NatRef] = {
natRef ← NEW[NAT ← ct.nextColorIndex];
ct.nextColorIndex ← ct.nextColorIndex + 1;
};
FindColorInIntensityTable: PROC [op: ImagerColor.OpConstantColor, table: CardTab.Ref] RETURNS [found: BOOLFALSE, nat: NAT ← 0] = {
intensity: REAL ← ImagerColorPrivate.IntensityFromColor[op];
key: CARD ← Real.Floor[intensity*32767];
};
AddColorToOutputTable: PROC [color: Imager.Color, ct: OutputColorTable] = {
gray: ImagerColor.OpConstantColor ← ImagerColor.ColorFromGray[1];
IF color=NIL THEN {
Treat as a special color.
}
ELSE {
WITH color SELECT FROM
op: ImagerColor.OpConstantColor => {
IF gray.colorOperator=op.colorOperator THEN { -- "MakeGray"
}
ELSE { --put out an RGB
r, g, b: REAL;
[r,g,b] ← GGCoreOps.ExtractRGB[op];
};
};
special: ImagerColor.SpecialColor => {
f.PutF[" %g]", [rope[special.name]]];
};
sampledBlack: ImagerColor.SampledBlack => {
};
sampledColor: ImagerColor.SampledColor => {
};
ENDCASE => ERROR; -- Gargoyle doesn't know about this type of color
};
};
Filing in
FileinSceneAndOptions: PUBLIC PROC [f: IO.STREAM, ggData: GGData, alignmentsOnly: BOOL, selectSlices: BOOL] RETURNS [success: BOOLFALSE, sceneName: Rope.ROPE] = {
Loads any objects in f into ggData scene. Merges any alignment line types in f into the viewer represented by ggData. Changes other control panel state variables to options found in f if NOT alignmentsOnly.
ENABLE GGParseIn.SyntaxError => {
Feedback.PutF[ggData.router, oneLiner, $Error, "position: %g, wasThere: %g, notThere: %g", [integer[position]], [rope[wasThere]], [rope[notThere]] ];
GOTO Abort;
};
scene: Scene ← ggData.scene;
version: REAL;
count: NAT;
entity: Slice;
finger, newEntities: LIST OF Slice;
[sceneName, version] ← ReadHeaderAndOptions[f, ggData, alignmentsOnly];
Read in the scene entities
GGParseIn.ReadWRope[f, "Entities:"];
GGParseIn.ReadWRope[f, "["];
count ← GGParseIn.ReadWNAT[f];
GGParseIn.ReadWRope[f, "]:"]; GGParseIn.ReadWhiteSpace[f];
[newEntities, finger] ← GGUtility.StartSliceList[];
FOR i: NAT IN[1..count] DO
entity ← FileinEntity[f, version, ggData.router, ggData.camera];
IF entity#NIL THEN [newEntities, finger] ← GGUtility.AddSlice[entity, newEntities, finger];
IF ggData.aborted[filein] THEN {
ggData.aborted[filein] ← FALSE;
GGUIUtility.SafeClose[f, ggData.router];
RETURN[FALSE, NIL]; -- signals a failed read
};
ENDLOOP;
GGUIUtility.SafeClose[f, ggData.router];
GGSelect.DeselectAll[scene, normal];
GGScene.AddSlices[scene, newEntities];
IF selectSlices THEN FOR sliceList: LIST OF Slice ← newEntities, sliceList.rest UNTIL sliceList=NIL DO
GGSelect.SelectEntireSlice[sliceList.first, scene, normal];
ENDLOOP;
RETURN[TRUE, sceneName];
EXITS
Abort => {}; -- RETURN[FALSE, NIL];
};
FileinSceneOnly: PUBLIC PROC [f: IO.STREAM, scene: Scene, selectSlices: BOOL, camera: Camera] RETURNS [success: BOOLFALSE, sceneName: Rope.ROPE] = {
Ignores the control panel state variables options in f. Merges any objects in f into scene.
ENABLE GGParseIn.SyntaxError => {
Feedback.PutFByName[$Gargoyle, oneLiner, $Error, "position: %g, wasThere: %g, notThere: %g", [integer[position]], [rope[wasThere]], [rope[notThere]] ];
GOTO Abort;
};
version: REAL;
count: NAT;
entity: Slice;
finger, newEntities: LIST OF Slice;
Read in the Header
GGParseIn.ReadWRope[f, "Gargoyle file for scene: "];
sceneName ← GGParseIn.ReadLine[f];
GGParseIn.ReadWRope[f, "Produced by version"];
version ← GGParseIn.ReadWReal[f];
version ← Real.Round[version*100.0]/100.0; -- compensate for fuzzy ReadWReal of version
Read in the alignment objects, etc.
IF version >= 8607.17 THEN SkipOptions[f];
Read the scene entities
GGParseIn.ReadWRope[f, "Entities:"];
GGParseIn.ReadWRope[f, "["];
count ← GGParseIn.ReadWNAT[f];
GGParseIn.ReadWRope[f, "]:"]; GGParseIn.ReadWhiteSpace[f];
[newEntities, finger] ← GGUtility.StartSliceList[];
FOR i: NAT IN[1..count] DO
entity ← FileinEntity[f, version, NIL, camera];
IF entity#NIL THEN [newEntities, finger] ← GGUtility.AddSlice[entity, newEntities, finger];
ENDLOOP;
GGUIUtility.SafeClose[f];
GGSelect.DeselectAll[scene, normal];
GGScene.AddSlices[scene, newEntities];
IF selectSlices THEN FOR sliceList: LIST OF Slice ← newEntities, sliceList.rest UNTIL sliceList=NIL DO
GGSelect.SelectEntireSlice[sliceList.first, scene, normal];
ENDLOOP;
RETURN[TRUE, sceneName];
EXITS
Abort => {}; -- RETURN[FALSE, NIL];
};
FileinOptionsOnly: PUBLIC PROC [f: IO.STREAM, ggData: GGData, alignmentsOnly: BOOL] RETURNS [success: BOOLFALSE, sceneName: Rope.ROPE] = {
Merges any alignment line types in f into the viewer represented by ggData. Changes other control panel state variables to options found in f if NOT alignmentsOnly.
ENABLE GGParseIn.SyntaxError => {
Feedback.PutF[ggData.router, oneLiner, $Error, "position: %g, wasThere: %g, notThere: %g", [integer[position]], [rope[wasThere]], [rope[notThere]] ];
GOTO Abort;
};
version: REAL;
[sceneName, version] ← ReadHeaderAndOptions[f, ggData, alignmentsOnly];
GGUIUtility.SafeClose[f, ggData.router];
RETURN[TRUE, sceneName];
EXITS
Abort => {}; -- RETURN[FALSE, NIL];
};
ReadHeaderAndOptions: PROC [f: IO.STREAM, ggData: GGData, alignmentsOnly: BOOL] RETURNS [sceneName: Rope.ROPE, version: REAL] = {
Read in the Header
GGParseIn.ReadWRope[f, "Gargoyle file for scene: "];
sceneName ← GGParseIn.ReadLine[f];
GGParseIn.ReadWRope[f, "Produced by version"];
version ← GGParseIn.ReadWReal[f];
version ← Real.Round[version*100.0]/100.0; -- compensate for fuzzy ReadWReal of version
Read in the options.
CodeTimer.StartInt[$ReadOptions, $Gargoyle];
IF version >= 8607.17 THEN ReadOptions[f, version, ggData, alignmentsOnly]
ELSE GGEvent.StandardAlignments[ggData, LIST[NIL]];
CodeTimer.StopInt[$ReadOptions, $Gargoyle];
};
ReadOptions: PROC [f: IO.STREAM, version: REAL, ggData: GGData, alignmentsOnly: BOOLFALSE] = {
keyWord, option: Rope.ROPE;
good: BOOL;
nextChar: CHAR;
twoCRsFound: BOOLFALSE;
Initialize Some Options
GGState.SetPalette[ggData, FALSE];
Read in the Options that are Mentioned
UNTIL twoCRsFound DO
[keyWord, good] ← GGParseIn.ReadKeyWord[f];
IF NOT good THEN {
nextChar ← IO.PeekChar[f];
IF IsEndLine[nextChar] THEN {
[] ← IO.GetChar[f];
twoCRsFound ← TRUE;
};
LOOP};
good ← GGParseIn.ReadHorizontalBlank[f];
IF NOT good THEN {
nextChar ← IO.PeekChar[f];
IF IsEndLine[nextChar] THEN {
[] ← IO.GetChar[f];
twoCRsFound ← TRUE;
};
LOOP};
option ← GGParseIn.ReadLine[f];
ProcessOption[keyWord, option, version, ggData, alignmentsOnly];
nextChar ← IO.PeekChar[f];
IF IsEndLine[nextChar] THEN {
[] ← IO.GetChar[f];
twoCRsFound ← TRUE;
};
ENDLOOP;
};
ReadListOfAtom: PUBLIC PROC [f: IO.STREAM] RETURNS [atomList: LIST OF ATOM] = {
cr: Rope.ROPE = Rope.FromChar[IO.CR];
lf: Rope.ROPE = Rope.FromChar[IO.LF];
rightParen: Rope.ROPE = Rope.FromChar[')];
rightBracket: Rope.ROPE = Rope.FromChar[']];
AtomsOnOneLineOrParenProc: SAFE PROC [char: CHAR] RETURNS [IO.CharClass] = {
SELECT char FROM
IO.LF, IO.CR, '), '] =>RETURN [break];
IO.SP, IO.TAB, ', , '; => RETURN [sepr];
ENDCASE => RETURN [other];
};
rope: Rope.ROPE;
end: BOOLFALSE;
[] ← IO.SkipWhitespace[f, TRUE];
atomList ← NIL;
WHILE TRUE DO
[rope, ----] ← IO.GetTokenRope[f, AtomsOnOneLineOrParenProc
!IO.EndOfStream => {end ← TRUE; CONTINUE}];
IF end OR rope = NIL THEN RETURN;
IF Rope.Equal[rope, cr] OR Rope.Equal[rope, lf] THEN RETURN;
IF Rope.Equal[rope, rightParen] THEN {
f.Backup[')];
RETURN;
};
IF Rope.Equal[rope, rightBracket] THEN {
f.Backup[']];
RETURN;
};
atomList ← AppendAtomToAtomList[Atom.MakeAtom[rope], atomList];
ENDLOOP;
};
AppendAtomToAtomList: PROC [atom: ATOM, list: LIST OF ATOM] RETURNS [LIST OF ATOM] = {
A copy of List.Nconc1 for LIST OF Rope.ROPE instead of LIST OF REF ANY
z: LIST OF ATOM ← list;
IF z = NIL THEN RETURN[CONS[atom,NIL]];
UNTIL z.rest = NIL DO z ← z.rest; ENDLOOP;
z.rest ← CONS[atom,NIL];
RETURN[list];
};
ProcessOption: PROC [keyWord, option: Rope.ROPE, version: REAL, ggData: GGData, alignmentsOnly: BOOLFALSE] = {
optionStream: IO.STREAMIO.RIS[option];
optionList: LIST OF Rope.ROPE;
value: REAL;
SELECT TRUE FROM
Rope.Equal[keyWord, "PaletteForFillColor", FALSE] => {
active: BOOL ← GGParseIn.ReadBool[optionStream, version].truth;
IF active THEN GGState.SetPalette[ggData, TRUE];
RETURN;
};
Rope.Equal[keyWord, "PaletteForStrokeColor", FALSE] => {
active: BOOL ← GGParseIn.ReadBool[optionStream, version].truth;
IF active THEN GGState.SetPalette[ggData, TRUE];
RETURN;
};
Rope.Equal[keyWord, "Palette", FALSE] => {
active: BOOL ← GGParseIn.ReadBool[optionStream, version].truth;
IF active THEN GGState.SetPalette[ggData, TRUE];
RETURN;
};
Rope.Equal[keyWord, "Behaviors", FALSE] => {
behaviors: LIST OF ATOM ← ReadListOfAtom[optionStream];
FOR list: LIST OF ATOM ← behaviors, list.rest UNTIL list = NIL DO
IF list.first = $PaletteForFillColor THEN GGState.SetPaletteForFillColor[ggData, TRUE]
ELSE IF list.first = $PaletteForStrokeColor THEN GGState.SetPaletteForStrokeColor[ggData, TRUE];
ENDLOOP;
RETURN;
};
Rope.Equal[keyWord, "Scripts", FALSE] => {
names: LIST OF Rope.ROPE ← GGParseIn.ReadListOfRope[optionStream];
ggData.debug.autoScriptNames ← GGCoreOps.NewRopeListt[];
FOR list: LIST OF Rope.ROPE ← names, list.rest UNTIL list = NIL DO
GGCoreOps.AppendRope[list.first, ggData.debug.autoScriptNames];
ENDLOOP;
RETURN;
};
Rope.Equal[keyWord, "Slope", FALSE] => {
IF version>=8706.16 THEN { -- slope values and ON states
values: LIST OF REAL;
on: LIST OF BOOL;
[----, values, on] ← GGParseIn.ReadScalarButtonValues[optionStream, version];
GGState.AddSlopeList[ggData, values, on];
}
ELSE { -- slope values only
values, ptr: LIST OF REAL;
optionList ← GGParseIn.ReadListOfRope[optionStream];
[values, ptr] ← GGCoreOps.StartRealList[];
FOR list: LIST OF Rope.ROPE ← optionList, list.rest UNTIL list = NIL DO
value ← Convert.RealFromRope[list.first];
[values, ptr] ← GGCoreOps.AddReal[value, values, ptr];
ENDLOOP;
GGState.AddSlopeList[ggData, values, NIL];
};
RETURN;
};
Rope.Equal[keyWord, "Angle", FALSE] => {
IF version>=8706.16 THEN { -- angle values and ON states
values: LIST OF REAL;
on: LIST OF BOOL;
[----, values, on] ← GGParseIn.ReadScalarButtonValues[optionStream, version];
GGState.AddAngleList[ggData, values, on];
}
ELSE { -- angle values only
values, ptr: LIST OF REAL;
optionList ← GGParseIn.ReadListOfRope[optionStream];
[values, ptr] ← GGCoreOps.StartRealList[];
FOR list: LIST OF Rope.ROPE ← optionList, list.rest UNTIL list = NIL DO
value ← Convert.RealFromRope[list.first];
[values, ptr] ← GGCoreOps.AddReal[value, values, ptr];
ENDLOOP;
GGState.AddAngleList[ggData, values, NIL];
};
RETURN;
};
Rope.Equal[keyWord, "Radius", FALSE] => {
IF version>=8706.16 THEN { -- radius values and ON states
values: LIST OF REAL;
on: LIST OF BOOL;
names: LIST OF Rope.ROPE;
[names, values, on] ← GGParseIn.ReadScalarButtonValues[optionStream, version];
GGState.AddRadiusList[ggData, names, values, on];
}
ELSE { -- radius values only
values, ptr: LIST OF REAL;
optionList ← GGParseIn.ReadListOfRope[optionStream];
[values, ptr] ← GGCoreOps.StartRealList[];
FOR list: LIST OF Rope.ROPE ← optionList, list.rest UNTIL list = NIL DO
value ← Convert.RealFromRope[list.first];
[values, ptr] ← GGCoreOps.AddReal[value, values, ptr];
ENDLOOP;
GGState.AddRadiusList[ggData, NIL, values, NIL];
};
RETURN;
};
Rope.Equal[keyWord, "LineDistance", FALSE] => {
IF version>=8706.16 THEN { -- LineDistance values and ON states
values: LIST OF REAL;
on: LIST OF BOOL;
names: LIST OF Rope.ROPE;
[names, values, on] ← GGParseIn.ReadScalarButtonValues[optionStream, version];
GGState.AddLineDistanceList[ggData, names, values, on];
}
ELSE { -- LineDistance values only
values, ptr: LIST OF REAL;
optionList ← GGParseIn.ReadListOfRope[optionStream];
[values, ptr] ← GGCoreOps.StartRealList[];
FOR list: LIST OF Rope.ROPE ← optionList, list.rest UNTIL list = NIL DO
value ← Convert.RealFromRope[list.first];
[values, ptr] ← GGCoreOps.AddReal[value, values, ptr];
ENDLOOP;
GGState.AddLineDistanceList[ggData, NIL, values, NIL];
};
RETURN;
};
Rope.Equal[keyWord, "Anchor", FALSE] => {
anchored, good: BOOL;
[anchored, good] ← GGParseIn.ReadBool[optionStream, version];
IF anchored AND good THEN {
point: Point ← GGParseIn.ReadPoint[optionStream];
ggData.anchor^ ← [exists: TRUE, point: point, chair: NIL, attractor: NIL];
}
ELSE ggData.anchor.exists ← FALSE;
RETURN;
};
ENDCASE;
IF NOT alignmentsOnly THEN SELECT TRUE FROM
Rope.Equal[keyWord, "Midpoints", FALSE] => {
on, good: BOOL;
[on, good] ← GGParseIn.ReadBool[optionStream, version];
GGState.SetMidpoints[ggData, on AND good];
};
Rope.Equal[keyWord, "Heuristics", FALSE] => {
on, good: BOOL;
[on, good] ← GGParseIn.ReadBool[optionStream, version];
GGState.SetHeuristics[ggData, on AND good];
};
Rope.Equal[keyWord, "ShowAlignments", FALSE] => {
on, good: BOOL;
[on, good] ← GGParseIn.ReadBool[optionStream, version];
GGState.SetShowAlignments[ggData, on AND good];
};
Rope.Equal[keyWord, "ShowColors", FALSE] => {
on, good: BOOL;
[on, good] ← GGParseIn.ReadBool[optionStream, version];
GGState.SetShowColors[ggData, on AND good];
};
Rope.Equal[keyWord, "Gravity", FALSE] => {
on, good: BOOL;
[on, good] ← GGParseIn.ReadBool[optionStream, version];
GGState.SetGravity[ggData, on AND good];
};
Rope.Equal[keyWord, "ScaleUnit", FALSE] => {
real: REAL ← GGParseIn.ReadWReal[optionStream];
IF real>0.0 THEN GGState.SetScaleUnit[ggData, real, NIL];
};
Rope.Equal[keyWord, "DisplayStyle", FALSE] => {
rope: Rope.ROPE ← GGParseIn.ReadWWord[optionStream];
GGState.SetDisplayStyle[ggData, GGUIUtility.DisplayStyleFromRope[rope]];
};
Rope.Equal[keyWord, "GravityExtent", FALSE] => {
real: REAL ← GGParseIn.ReadWReal[optionStream];
GGState.SetGravityExtent[ggData, real];
};
Rope.Equal[keyWord, "GravityType", FALSE] => {
rope: Rope.ROPE ← GGParseIn.ReadWWord[optionStream];
GGState.SetGravityType[ggData, GGUIUtility.GravityTypeFromRope[rope]];
};
Rope.Equal[keyWord, "DefaultFont", FALSE] => {
fontData: FontData;
fontData ← GGFont.ParseFontData[data: NIL, inStream: optionStream, literalP: TRUE, transformP: TRUE, storedSizeP: TRUE, designSizeP: TRUE ! GGFont.ParseError => CONTINUE;];
fontData.substituteOK ← TRUE; -- bad hack here. Avoids a bogus default font
GGState.SetDefaultFont[ggData, fontData];
};
Rope.Equal[keyWord, "Defaults", FALSE] => {
strokeJoint, strokeEnd: Rope.ROPE;
ggData.defaults.fillColor ← GGParseIn.ReadColor[optionStream, version];
ggData.defaults.strokeColor ← GGParseIn.ReadColor[optionStream, version];
ggData.defaults.strokeWidth ← GGParseIn.ReadWReal[optionStream];
strokeJoint ← GGParseIn.ReadWWord[optionStream];
ggData.defaults.strokeJoint ← SELECT TRUE FROM
Rope.Equal[strokeJoint, "miter", FALSE] => miter,
Rope.Equal[strokeJoint, "bevel", FALSE] => bevel,
ENDCASE => round;
strokeEnd ← GGParseIn.ReadWWord[optionStream];
ggData.defaults.strokeEnd ← SELECT TRUE FROM
Rope.Equal[strokeEnd, "square", FALSE] => square,
Rope.Equal[strokeEnd, "butt", FALSE] => butt,
ENDCASE => round;
};
Rope.Equal[keyWord, "Dashed", FALSE] => {
dashed, good: BOOL;
[dashed, good] ← GGParseIn.ReadBool[optionStream, version];
ggData.defaults.dashed ← dashed AND good;
IF ggData.defaults.dashed THEN {
ggData.defaults.pattern ← GGParseIn.ReadArrayOfReal[optionStream];
ggData.defaults.offset ← GGParseIn.ReadWReal[optionStream];
ggData.defaults.length ← GGParseIn.ReadWReal[optionStream];
};
};
Rope.Equal[keyWord, "Shadows", FALSE] => {
shadowed, good: BOOL;
ggData.defaults.textColor ← GGParseIn.ReadColor[optionStream, version];
IF ggData.defaults.textColor=NIL THEN ggData.defaults.textColor ← Imager.black;
fixes NIL text color defaults in many older files. Added by Pier, July 17, 1991
[shadowed, good] ← GGParseIn.ReadBool[optionStream, version];
ggData.defaults.dropShadowOn ← shadowed AND good;
IF ggData.defaults.dropShadowOn THEN {
ggData.defaults.dropShadowOffset ← GGParseIn.ReadPoint[optionStream];
ggData.defaults.dropShadowColor ← GGParseIn.ReadColor[optionStream, version];
};
};
Rope.Equal[keyWord, "Active", FALSE] => { -- Active is not yet stored
active, good: BOOL;
[active, good] ← GGParseIn.ReadBool[optionStream, version];
GGState.SetActive[ggData, active AND good];
};
ENDCASE => SIGNAL Problem[msg: Rope.Concat["Unknown keyword in gargoyle file: ", keyWord]];
}; -- end ProcessOption
SkipOptions: PROC [f: IO.STREAM] = {
keyWord, option: Rope.ROPE;
good: BOOL;
nextChar: CHAR;
twoCRsFound: BOOLFALSE;
UNTIL twoCRsFound DO
[keyWord, good] ← GGParseIn.ReadKeyWord[f];
IF NOT good THEN {
nextChar ← IO.PeekChar[f];
IF IsEndLine[nextChar] THEN {
[] ← IO.GetChar[f];
twoCRsFound ← TRUE;
};
LOOP};
good ← GGParseIn.ReadHorizontalBlank[f];
IF NOT good THEN {
nextChar ← IO.PeekChar[f];
IF IsEndLine[nextChar] THEN {
[] ← IO.GetChar[f];
twoCRsFound ← TRUE;
};
LOOP};
option ← GGParseIn.ReadLine[f];
ProcessOption[keyWord, option, ggData];
nextChar ← IO.PeekChar[f];
IF IsEndLine[nextChar] THEN {
[] ← IO.GetChar[f];
twoCRsFound ← TRUE;
};
ENDLOOP;
};
FileinEntity: PROC [f: IO.STREAM, version: REAL, router: MsgRouter, camera: Camera] RETURNS [entity: Slice] = {
nextWord: Rope.ROPE;
IF version > 8605.22 THEN {
IF version >= 8705.14 THEN {
entity ← GGSliceOps.FileinSlice[f, version, router, camera];
}
ELSE {
nextWord ← GGParseIn.ReadWWord[f];
SELECT TRUE FROM
Rope.Equal[nextWord, "Outline:"] => {
class: SliceClass ← GGSlice.FetchSliceClass[$Outline];
entity ← class.filein[f, version, router, camera];
};
Rope.Equal[nextWord, "Slice"] => {
entity ← GGSliceOps.FileinSlice[f, version, router, camera];
};
ENDCASE => ERROR
}
}
ELSE {
nextWord ← GGParseIn.ReadWWord[f];
SELECT TRUE FROM
Rope.Equal[nextWord, "Outline:"] => {
class: SliceClass ← GGSlice.FetchSliceClass[$Outline];
entity ← class.filein[f, version, router, camera];
};
Rope.Equal[nextWord, "Cluster"] => {
entity ← GGSliceOps.FileinSlice[f, version, router, camera];
};
ENDCASE => ERROR;
};
};
Filing out
FileoutSceneAndOptions: PUBLIC PROC [f: IO.STREAM, ggData: GGData, fileName: Rope.ROPE, scene: Scene ← NIL] = {
sceneOut: Scene ← IF scene#NIL THEN scene ELSE ggData.scene;
sliceCount: NAT ← GGScene.CountSlices[sceneOut, first];
DoFileOut: PROC [slice: Slice] RETURNS [done: BOOLFALSE] = {
f.PutChar[IO.CR]; -- CR before each top-Level slice
GGSliceOps.FileoutSlice[f, slice];
};
f.PutF["Gargoyle file for scene: %g\n", [rope[fileName]]];
f.PutF["Produced by version %g\n\n", [rope[GGUtility.versionRope]]];
FileoutOptions[f, ggData];
f.PutF["Entities: [%g]:\n\n", [integer[sliceCount]]];
[] ← GGScene.WalkSlices[sceneOut, first, DoFileOut];
};
FileoutSceneOnly: PUBLIC PROC [f: IO.STREAM, scene: Scene, fileName: Rope.ROPE] = {
sliceCount: NAT ← GGScene.CountSlices[scene, first];
DoFileOut: PROC [slice: Slice] RETURNS [done: BOOLFALSE] = {
f.PutChar[IO.CR];
GGSliceOps.FileoutSlice[f, slice];
};
f.PutF["Gargoyle file for scene: %g\n", [rope[fileName]]];
f.PutF["Produced by version %g\n\n", [rope[GGUtility.versionRope]]];
f.PutChar[IO.CR];
f.PutChar[IO.CR];
f.PutF["Entities: [%g]:\n\n", [integer[sliceCount]]];
[] ← GGScene.WalkSlices[scene, first, DoFileOut];
};
FileoutOptions: PROC [f: IO.STREAM, ggData: GGData] = {
values: LIST OF REAL;
on: LIST OF BOOL;
names: LIST OF Rope.ROPE;
defaults: DefaultData;
anchor: Caret;
f.PutF["Scripts: "];
GGParseOut.WriteListOfRope[f, ggData.debug.autoScriptNames.list];
f.PutChar[IO.CR];
f.PutF["Slope: "];
[values, on] ← GGState.GetSlopeAlignments[ggData];
GGParseOut.WriteScalarButtonValues[f, NIL, values, on];
f.PutChar[IO.CR];
f.PutF["Angle: "];
[values, on] ← GGState.GetAngleAlignments[ggData];
GGParseOut.WriteScalarButtonValues[f, NIL, values, on];
f.PutChar[IO.CR];
f.PutF["Radius: "];
[names, values, on] ← GGState.GetRadiusAlignments[ggData];
GGParseOut.WriteScalarButtonValues[f, names, values, on];
f.PutChar[IO.CR];
f.PutF["LineDistance: "];
[names, values, on] ← GGState.GetLineDistanceAlignments[ggData];
GGParseOut.WriteScalarButtonValues[f, names, values, on];
f.PutF["\nMidpoints: "];
GGParseOut.WriteBool[f, GGState.GetMidpoints[ggData]];
f.PutF["\nHeuristics: "];
GGParseOut.WriteBool[f, GGState.GetHeuristics[ggData]];
f.PutF["\nShowAlignments: "];
GGParseOut.WriteBool[f, GGState.GetShowAlignments[ggData]];
f.PutF["\nScaleUnit: %g", [real[GGState.GetScaleUnit[ggData]]] ];
f.PutF["\nDisplayStyle: %g", [rope[GGUIUtility.DisplayStyleToRope[GGState.GetDisplayStyle[ggData]] ]] ];
f.PutF["\nGravity: "];
GGParseOut.WriteBool[f, GGState.GetGravity[ggData]];
f.PutF["\nGravityExtent: %g", [real[GGState.GetGravityExtent[ggData]]] ];
f.PutF["\nGravityType: %g", [rope[GGUIUtility.GravityTypeToRope[GGState.GetGravityType[ggData]] ]] ];
defaults ← GGState.GetDefaults[ggData];
f.PutF["\nDefaultFont: %g ", [rope[defaults.font.literal]] ];
GGParseOut.WriteFactoredTransformationVEC[f, defaults.font.transform];
f.PutF[" %g %g", [real[defaults.font.storedSize]], [real[defaults.font.designSize]] ];
f.PutF["\nDefaults: "];
GGParseOut.WriteColor[f, defaults.fillColor];
f.PutChar[' ]; -- put a SPACE
GGParseOut.WriteColor[f, defaults.strokeColor];
f.PutF[" %g", [real[defaults.strokeWidth]] ];
f.PutF[" %g", [rope[SELECT defaults.strokeJoint FROM
bevel => "bevel",
miter => "miter",
ENDCASE => "round"
]] ];
f.PutF[" %g", [rope[SELECT defaults.strokeEnd FROM
square => "square",
butt => "butt",
ENDCASE => "round"
]] ];
f.PutF["\nDashed: "];
GGParseOut.WriteBool[f, defaults.dashed];
IF defaults.dashed THEN {
f.PutChar[' ]; -- put a SPACE
GGParseOut.WriteArrayOfReal[f, defaults.pattern];
f.PutF[" %g %g", [real[defaults.offset]], [real[defaults.length]] ];
};
f.PutChar[' ]; -- put a SPACE
f.PutF["\nShadows: "];
GGParseOut.WriteColor[f, defaults.textColor];
GGParseOut.WriteBool[f, defaults.dropShadowOn];
IF defaults.dropShadowOn THEN {
f.PutChar[' ]; -- put a SPACE
GGParseOut.WritePoint[f, defaults.dropShadowOffset];
GGParseOut.WriteColor[f, defaults.dropShadowColor];
};
anchor ← GGState.GetAnchor[ggData];
f.PutF["\nAnchor: "];
GGParseOut.WriteBool[f, IF anchor=NIL THEN FALSE ELSE anchor.exists];
IF anchor.exists THEN {
f.PutChar[' ]; -- put a SPACE
GGParseOut.WritePoint[f, anchor.point];
};
f.PutF["\nPaletteForFillColor: "];
GGParseOut.WriteBool[f, GGState.GetPaletteForFillColor[ggData]];
f.PutF["\nPaletteForStrokeColor: "];
GGParseOut.WriteBool[f, GGState.GetPaletteForStrokeColor[ggData]];
f.PutF["\nPalette: "];
GGParseOut.WriteBool[f, GGState.GetPalette[ggData]];
f.PutChar[IO.CR];
f.PutChar[IO.CR];
};
IsEndLine: PROC [c: CHAR] RETURNS [BOOL] = {
RETURN[c=IO.CR OR c=IO.LF];
};
InitStats: PROC [] = {
interval: CodeTimer.Interval;
interval ← CodeTimer.CreateInterval[$ReadOptions];
CodeTimer.AddInt[interval, $Gargoyle];
};
InitStats[];
END.