GGFileImpl.mesa
Copyright Ó 1987, 1989, 1991, 1992 by Xerox Corporation. All rights reserved.
Pier, December 1, 1992 2:26 pm PST
Kurlander, September 1, 1987 1:47:01 pm PDT
Bier, December 3, 1992 5:27 pm PST
Doug Wyatt, April 16, 1992 4:32 pm PDT
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, SimpleFeedback, SymTab, 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, SimpleFeedback, SymTab
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;
ROPE: TYPE = Rope.ROPE;
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;
Transformation: TYPE = ImagerTransformation.Transformation;
Viewer: TYPE = ViewerClasses.Viewer;
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:
BOOL ¬
FALSE, 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, closeStreamWhenDone:
BOOL ←
TRUE]
RETURNS [success:
BOOL ¬
FALSE, sceneName:
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.PutFL[ggData.router, oneLiner, $Error, "position: %g, wasThere: %g, notThere: %g", LIST[[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, IF alignmentsOnly THEN alignments ELSE all];
Read in the scene entities
GGParseIn.ReadRope[f, "Entities:"];
GGParseIn.ReadChar[f, '[];
count ¬ GGParseIn.ReadNAT[f];
GGParseIn.ReadRope[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;
IF closeStreamWhenDone THEN 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, closeStreamWhenDone:
BOOL ←
TRUE]
RETURNS [success:
BOOL ¬
FALSE, sceneName: Rope.
ROPE] = {
Ignores the control panel state variables options in f. Merges any objects in f into scene.
ENABLE GGParseIn.SyntaxError =>
{
SimpleFeedback.PutFL[$Gargoyle, oneLiner, $Error, "position: %g, wasThere: %g, notThere: %g", LIST[[integer[position]], [rope[wasThere]], [rope[notThere]]] ];
GOTO Abort;
};
version: REAL;
count: NAT;
entity: Slice;
finger, newEntities: LIST OF Slice;
Read in the Header
GGParseIn.ReadRope[f, "Gargoyle file for scene: "];
sceneName ¬ GGParseIn.ReadLine[f];
GGParseIn.ReadRope[f, "Produced by version"];
version ¬ GGParseIn.ReadReal[f];
version ¬ Real.Round[version*100.0]/100.0; -- compensate for fuzzy ReadReal of version
Read in the alignment objects, etc.
IF version >= 8607.17 THEN SkipOptions[f];
IF version >= 9207.29 THEN ReadSceneFields[f, version, scene];
IF version >= 8607.17 THEN ReadSceneFields[f, version, scene];
Read the scene entities
GGParseIn.ReadRope[f, "Entities:"];
GGParseIn.ReadChar[f, '[];
count ¬ GGParseIn.ReadNAT[f];
GGParseIn.ReadRope[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;
IF closeStreamWhenDone THEN 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, closeStreamWhenDone:
BOOL ←
TRUE]
RETURNS [success:
BOOL ¬
FALSE, 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.PutFL[ggData.router, oneLiner, $Error, "position: %g, wasThere: %g, notThere: %g", LIST[[integer[position]], [rope[wasThere]], [rope[notThere]]] ];
GOTO Abort;
};
version: REAL;
[sceneName, version] ¬ ReadHeaderAndOptions[f, ggData, IF alignmentsOnly THEN alignments ELSE all];
IF closeStreamWhenDone THEN GGUIUtility.SafeClose[f, ggData.router];
RETURN[TRUE, sceneName];
EXITS
Abort => {}; -- RETURN[FALSE, NIL];
};
ReadHeaderAndOptions:
PROC [f:
IO.
STREAM, ggData: GGData, type: OptionType]
RETURNS [sceneName: Rope.
ROPE, version:
REAL] = {
Read in the Header
GGParseIn.ReadRope[f, "Gargoyle file for scene: "];
sceneName ¬ GGParseIn.ReadLine[f];
GGParseIn.ReadRope[f, "Produced by version"];
version ¬ GGParseIn.ReadReal[f];
version ¬ Real.Round[version*100.0]/100.0; -- compensate for fuzzy ReadReal of version
Read in the options.
CodeTimer.StartInt[$ReadOptions, $Gargoyle];
IF version >= 8607.17
THEN ReadOptions[f, version, ggData, type]
ELSE GGEvent.StandardAlignments[ggData, LIST[NIL]];
CodeTimer.StopInt[$ReadOptions, $Gargoyle];
};
ReadSceneFields:
PROC [f:
IO.
STREAM, version:
REAL, scene: Scene] = {
keyWord, option: Rope.ROPE;
good: BOOL;
nextChar: CHAR;
twoCRsFound: BOOL ¬ FALSE;
Read in the Scene Fields 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];
ProcessSceneField[keyWord, option, version, scene];
nextChar ¬ IO.PeekChar[f];
IF IsEndLine[nextChar]
THEN {
[] ¬ IO.GetChar[f];
twoCRsFound ¬ TRUE;
};
ENDLOOP;
};
ReadOptions:
PROC [f:
IO.
STREAM, version:
REAL, ggData: GGData, type: OptionType] = {
keyWord, option: Rope.ROPE;
good: BOOL;
nextChar: CHAR;
twoCRsFound: BOOL ¬ FALSE;
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, type];
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: BOOL ¬ FALSE;
[] ¬ 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];
};
OptionType: TYPE = {alignments, normal, sceneField, all, none};
optionTable: SymTab.Ref;
OptionData: TYPE = REF OptionDataObj;
OptionDataObj:
TYPE =
RECORD [
process: ProcessOptionProc ← NIL,
processScene: ProcessSceneFieldProc ← NIL,
type: OptionType
];
FindOption:
PROC [name:
ROPE]
RETURNS [optionData: OptionData ←
NIL] = {
found: BOOL;
val: REF;
[found, val] ← SymTab.Fetch[optionTable, name];
IF found THEN optionData ← NARROW[val];
};
RegisterAllOptions:
PROC [] = {
RegisterOption:
PROC [name:
ROPE, process: ProcessOptionProc, type: OptionType] = {
optionData: OptionData;
optionData ← NEW[OptionDataObj ← [process: process, processScene: NIL, type: type]];
[] ← SymTab.Store[optionTable, name, optionData];
};
RegisterSceneField:
PROC [name:
ROPE, process: ProcessSceneFieldProc] = {
optionData: OptionData;
optionData ← NEW[OptionDataObj ← [process: NIL, processScene: process, type: sceneField]];
[] ← SymTab.Store[optionTable, name, optionData];
};
optionTable ← SymTab.Create[29];
RegisterOption["ViewTransform", ProcessViewTransform, normal];
RegisterOption["PaletteForFillColor", ProcessPaletteForFillColor, normal];
RegisterOption["PaletteForStrokeColor", ProcessPaletteForStrokeColor, normal];
RegisterOption["Palette", ProcessPalette, normal];
RegisterOption["Scripts", ProcessScripts, normal];
RegisterOption["Slope", ProcessSlope, alignments];
RegisterOption["Angle", ProcessAngle, alignments];
RegisterOption["Radius", ProcessRadius, alignments];
RegisterOption["LineDistance", ProcessLineDistance, alignments];
RegisterOption["Anchor", ProcessAnchor, alignments];
RegisterOption["Midpoints", ProcessMidpoints, normal];
RegisterOption["Heuristics", ProcessHeuristics, normal];
RegisterOption["ShowAlignments", ProcessShowAlignments, normal];
RegisterOption["ShowColors", ProcessShowColors, normal];
RegisterOption["Gravity", ProcessGravity, normal];
RegisterOption["ScaleUnit", ProcessScaleUnit, normal];
RegisterOption["DisplayStyle", ProcessDisplayStyle, normal];
RegisterOption["GravityExtent", ProcessGravityExtent, normal];
RegisterOption["GravityType", ProcessGravityType, normal];
RegisterOption["DefaultFont", ProcessDefaultFont, normal];
RegisterOption["Defaults", ProcessDefaults, normal];
RegisterOption["Dashed", ProcessDashed, normal];
RegisterOption["Shadows", ProcessShadows, normal];
RegisterOption["Active", ProcessActive, normal];
RegisterSceneField["BackgroundColor", ProcessBackgroundColor];
};
ProcessSceneField:
PROC [keyWord, option: Rope.
ROPE, version:
REAL, scene: Scene] = {
optionStream: IO.STREAM;
optionData: OptionData;
optionStream ¬ IO.RIS[option];
optionData ← FindOption[keyWord];
IF optionData =
NIL
THEN {
SIGNAL Problem[msg: Rope.Concat["Unknown keyword in gargoyle file: ", keyWord]];
SimpleFeedback.PutF[$Gargoyle, oneLiner, $Error, "Unknown keyword in gargoyle file: %g", [rope[keyWord]]];
}
ELSE {
IF optionData.type # sceneField THEN RETURN;
optionData.processScene[keyWord, scene, optionStream, version];
};
};
ProcessOption:
PROC [keyWord, option: Rope.
ROPE, version:
REAL, ggData: GGData, types: OptionType] = {
optionStream: IO.STREAM;
optionData: OptionData;
IF types = none THEN RETURN;
optionStream ¬ IO.RIS[option];
optionData ← FindOption[keyWord];
IF optionData =
NIL
THEN {
SIGNAL Problem[msg: Rope.Concat["Unknown keyword in gargoyle file: ", keyWord]];
SimpleFeedback.PutF[$Gargoyle, oneLiner, $Error, "Unknown keyword in gargoyle file: %g", [rope[keyWord]]];
}
ELSE {
IF types = sceneField AND NOT optionData.type = sceneField THEN RETURN;
IF types = alignments AND NOT optionData.type = alignments THEN RETURN;
IF types = normal AND NOT optionData.type = normal THEN RETURN;
IF optionData.type = sceneField
THEN optionData.processScene[keyWord, ggData.scene, optionStream, version]
ELSE optionData.process[keyWord, ggData, optionStream, version];
};
};
ProcessOptionProc: TYPE = PROC [keyWord: ROPE, ggData: GGData, optionStream: IO.STREAM, version: REAL];
ProcessSceneFieldProc: TYPE = PROC [keyWord: ROPE, scene: Scene, optionStream: IO.STREAM, version: REAL];
ProcessViewTransform: ProcessOptionProc = {
clientToViewer: Transformation ← GGParseIn.ReadTransformation[optionStream];
GGState.SetBiScrollersTransform[ggData, clientToViewer];
};
ProcessPaletteForFillColor: ProcessOptionProc = {
active: BOOL ¬ GGParseIn.ReadBool[optionStream];
IF active THEN GGState.SetPalette[ggData, TRUE];
};
ProcessPaletteForStrokeColor: ProcessOptionProc = {
active: BOOL ¬ GGParseIn.ReadBool[optionStream];
IF active THEN GGState.SetPalette[ggData, TRUE];
};
ProcessPalette: ProcessOptionProc = {
active: BOOL ¬ GGParseIn.ReadBool[optionStream];
IF active THEN GGState.SetPalette[ggData, TRUE];
};
ProcessScripts: ProcessOptionProc = {
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;
};
ProcessSlope: ProcessOptionProc = {
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: LIST OF ROPE;
value: 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];
};
};
ProcessAngle: ProcessOptionProc = {
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;
value: REAL;
optionList: LIST OF ROPE;
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];
};
};
ProcessRadius: ProcessOptionProc = {
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;
value: REAL;
optionList: LIST OF ROPE;
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];
};
};
ProcessLineDistance: ProcessOptionProc = {
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;
value: REAL;
optionList: LIST OF ROPE;
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];
};
};
ProcessAnchor: ProcessOptionProc = {
anchored: BOOL;
anchored ¬ GGParseIn.ReadBool[optionStream];
IF anchored
THEN {
point: Point ¬ GGParseIn.ReadPoint[optionStream];
ggData.anchor ¬ [exists: TRUE, point: point, chair: NIL, attractor: NIL];
}
ELSE ggData.anchor.exists ¬ FALSE;
};
ProcessMidpoints: ProcessOptionProc = {
on: BOOL;
on ¬ GGParseIn.ReadBool[optionStream];
GGState.SetMidpoints[ggData, on];
};
ProcessHeuristics: ProcessOptionProc = {
on: BOOL;
on ¬ GGParseIn.ReadBool[optionStream];
GGState.SetHeuristics[ggData, on];
};
ProcessShowAlignments: ProcessOptionProc = {
on: BOOL;
on ¬ GGParseIn.ReadBool[optionStream];
GGState.SetShowAlignments[ggData, on];
};
ProcessShowColors: ProcessOptionProc = {
on: BOOL;
on ¬ GGParseIn.ReadBool[optionStream];
GGState.SetShowColors[ggData, on];
};
ProcessGravity: ProcessOptionProc = {
on: BOOL;
on ¬ GGParseIn.ReadBool[optionStream];
GGState.SetGravity[ggData, on];
};
ProcessScaleUnit: ProcessOptionProc = {
real: REAL ¬ GGParseIn.ReadReal[optionStream];
IF real>0.0 THEN GGState.SetScaleUnit[ggData, real, NIL];
};
ProcessDisplayStyle: ProcessOptionProc = {
rope: Rope.ROPE ¬ GGParseIn.ReadWord[optionStream];
GGState.SetDisplayStyle[ggData, GGUIUtility.DisplayStyleFromRope[rope]];
};
ProcessGravityExtent: ProcessOptionProc = {
real: REAL ¬ GGParseIn.ReadReal[optionStream];
GGState.SetGravityExtent[ggData, real];
};
ProcessGravityType: ProcessOptionProc = {
rope: Rope.ROPE ¬ GGParseIn.ReadWord[optionStream];
GGState.SetGravityType[ggData, GGUIUtility.GravityTypeFromRope[rope]];
};
ProcessDefaultFont: ProcessOptionProc = {
fontData: FontData ¬ GGFont.CreateFontData[]; -- assure non-NIL font data
fontData ¬ GGFont.ParseFontData[data: fontData, 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];
};
ProcessDefaults: ProcessOptionProc = {
strokeJoint, strokeEnd: Rope.ROPE;
ggData.defaults.fillColor ¬ GGParseIn.ReadColor[optionStream, version];
ggData.defaults.strokeColor ¬ GGParseIn.ReadColor[optionStream, version];
ggData.defaults.strokeWidth ¬ GGParseIn.ReadReal[optionStream];
strokeJoint ¬ GGParseIn.ReadWord[optionStream];
ggData.defaults.strokeJoint ¬
SELECT
TRUE
FROM
Rope.Equal[strokeJoint, "miter", FALSE] => miter,
Rope.Equal[strokeJoint, "bevel", FALSE] => bevel,
ENDCASE => round;
strokeEnd ¬ GGParseIn.ReadWord[optionStream];
ggData.defaults.strokeEnd ¬
SELECT
TRUE
FROM
Rope.Equal[strokeEnd, "square", FALSE] => square,
Rope.Equal[strokeEnd, "butt", FALSE] => butt,
ENDCASE => round;
};
ProcessDashed: ProcessOptionProc = {
dashed: BOOL;
dashed ¬ GGParseIn.ReadBool[optionStream];
ggData.defaults.dashed ¬ dashed;
IF ggData.defaults.dashed
THEN {
ggData.defaults.pattern ¬ GGParseIn.ReadArrayOfReal[optionStream];
ggData.defaults.offset ¬ GGParseIn.ReadReal[optionStream];
ggData.defaults.length ¬ GGParseIn.ReadReal[optionStream];
};
};
ProcessShadows: ProcessOptionProc = {
shadowed: 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 ¬ GGParseIn.ReadBool[optionStream];
ggData.defaults.dropShadowOn ¬ shadowed;
IF ggData.defaults.dropShadowOn
THEN {
ggData.defaults.dropShadowOffset ¬ GGParseIn.ReadPoint[optionStream];
ggData.defaults.dropShadowColor ¬ GGParseIn.ReadColor[optionStream, version];
};
};
ProcessActive: ProcessOptionProc = {
active: BOOL;
active ¬ GGParseIn.ReadBool[optionStream];
GGState.SetActive[ggData, active];
};
ProcessBackgroundColor: ProcessSceneFieldProc = {
color: Imager.Color ¬ GGParseIn.ReadColor[optionStream, version];
GGScene.SetBackgroundColor[scene, color];
};
SkipOptions:
PROC [f:
IO.
STREAM] = {
keyWord, option: Rope.ROPE;
good: BOOL;
nextChar: CHAR;
twoCRsFound: BOOL ¬ FALSE;
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.ReadWord[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.ReadWord[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:
BOOL ¬
FALSE] = {
f.PutChar[IO.LF]; -- CR before each top-Level slice
GGSliceOps.FileoutSlice[f, slice];
};
f.PutF1["Gargoyle file for scene: %g\n", [rope[fileName]]];
f.PutF1["Produced by version %g\n\n", [rope[GGUtility.versionRope]]];
FileoutOptions[f, ggData];
FileoutSceneFields[f, ggData.scene];
f.PutChar[IO.LF];
f.PutF1["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:
BOOL ¬
FALSE] = {
f.PutChar[IO.LF];
GGSliceOps.FileoutSlice[f, slice];
};
f.PutF1["Gargoyle file for scene: %g\n", [rope[fileName]]];
f.PutF1["Produced by version %g\n\n", [rope[GGUtility.versionRope]]];
FileoutSceneFields[f, scene];
f.PutChar[IO.LF];
f.PutF1["Entities: [%g]:\n\n", [integer[sliceCount]]];
[] ¬ GGScene.WalkSlices[scene, first, DoFileOut];
};
FileoutSceneFields:
PROC [f:
IO.
STREAM, scene: Scene] = {
f.PutRope["BackgroundColor: "];
GGParseOut.WriteColor[f, GGScene.GetBackgroundColor[scene]];
f.PutChar[IO.LF];
};
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.PutRope["ViewTransform: "];
GGParseOut.WriteTransformation[f, GGState.GetBiScrollersTransform[ggData]];
f.PutChar[IO.LF];
f.PutRope["Scripts: "];
GGParseOut.WriteListOfRope[f, ggData.debug.autoScriptNames.list];
f.PutChar[IO.LF];
f.PutRope["Slope: "];
[values, on] ¬ GGState.GetSlopeAlignments[ggData];
GGParseOut.WriteScalarButtonValues[f, NIL, values, on];
f.PutChar[IO.LF];
f.PutRope["Angle: "];
[values, on] ¬ GGState.GetAngleAlignments[ggData];
GGParseOut.WriteScalarButtonValues[f, NIL, values, on];
f.PutChar[IO.LF];
f.PutRope["Radius: "];
[names, values, on] ¬ GGState.GetRadiusAlignments[ggData];
GGParseOut.WriteScalarButtonValues[f, names, values, on];
f.PutChar[IO.LF];
f.PutRope["LineDistance: "];
[names, values, on] ¬ GGState.GetLineDistanceAlignments[ggData];
GGParseOut.WriteScalarButtonValues[f, names, values, on];
f.PutRope["\nMidpoints: "];
GGParseOut.WriteBool[f, GGState.GetMidpoints[ggData]];
f.PutRope["\nHeuristics: "];
GGParseOut.WriteBool[f, GGState.GetHeuristics[ggData]];
f.PutRope["\nShowAlignments: "];
GGParseOut.WriteBool[f, GGState.GetShowAlignments[ggData]];
f.PutF1["\nScaleUnit: %g", [real[GGState.GetScaleUnit[ggData]]] ];
f.PutF1["\nDisplayStyle: %g", [rope[GGUIUtility.DisplayStyleToRope[GGState.GetDisplayStyle[ggData]] ]] ];
f.PutRope["\nGravity: "];
GGParseOut.WriteBool[f, GGState.GetGravity[ggData]];
f.PutF1["\nGravityExtent: %g", [real[GGState.GetGravityExtent[ggData]]] ];
f.PutF1["\nGravityType: %g", [rope[GGUIUtility.GravityTypeToRope[GGState.GetGravityType[ggData]] ]] ];
defaults ¬ GGState.GetDefaults[ggData];
f.PutF1["\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.PutRope["\nDefaults: "];
GGParseOut.WriteColor[f, defaults.fillColor];
f.PutChar[' ]; -- put a SPACE
GGParseOut.WriteColor[f, defaults.strokeColor];
f.PutF1[" %g", [real[defaults.strokeWidth]] ];
f.PutF1[" %g", [rope[
SELECT defaults.strokeJoint
FROM
bevel => "bevel",
miter => "miter",
ENDCASE => "round"
]] ];
f.PutF1[" %g", [rope[
SELECT defaults.strokeEnd
FROM
square => "square",
butt => "butt",
ENDCASE => "round"
]] ];
f.PutRope["\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.PutRope["\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.PutRope["\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.PutRope["\nPalette: "];
GGParseOut.WriteBool[f, GGState.GetPalette[ggData]];
f.PutRope["\nActive: "];
GGParseOut.WriteBool[f, GGState.GetActive[ggData]];
f.PutChar[IO.LF];
};
IsEndLine:
PROC [c:
CHAR]
RETURNS [
BOOL] = {
RETURN[c=IO.CR OR c=IO.LF];
};
RegisterAllOptions[];
END.