<> <> <> <> <> <> <<>> DIRECTORY Ascii, Atom, AtomButtons, BasicTime, --CombinePoly,-- CubicSplines, FS, GGAlign, GGBasicTypes, GGBoundBox, GGCaret, GGError, GGEvent, GGFromImager, GGGravity, GGInterface, GGInterfaceTypes, GGModelTypes, GGMultiGravity, GGObjects, GGOutline, GGParseOut, GGRefresh, GGSegment, GGSegmentTypes, GGSelect, GGSequence, GGShapes, GGSlice, GGStatistics, --GGTouch,-- GGTraj, GGUtility, GGVector, GGWindow, Imager, ImagerInterpress, ImagerTransformation, Interpress, IO, IPMaster, MessageWindow, --PrincOpsUtils,-- RealFns, Random, Rope, Rosary, ViewerTools; GGEventImplA: CEDAR PROGRAM IMPORTS Atom, AtomButtons, BasicTime, --CombinePoly,-- FS, GGAlign, GGBoundBox, GGCaret, GGError, GGEvent, GGFromImager, GGGravity, GGInterface, GGMultiGravity, GGObjects, GGOutline, GGParseOut, GGRefresh, GGSegment, GGSelect, GGSequence, GGShapes, GGSlice, GGStatistics, --GGTouch,-- GGTraj, GGUtility, GGVector, GGWindow, Imager, ImagerInterpress, ImagerTransformation, Interpress, IO, MessageWindow, --PrincOpsUtils,-- Random, RealFns, Rope, ViewerTools EXPORTS GGEvent = BEGIN BoundBox: TYPE = GGBoundBox.BoundBox; Slice: TYPE = GGModelTypes.Slice; SliceGenerator: TYPE = GGModelTypes.SliceGenerator; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; SliceDescriptorGenerator: TYPE = GGModelTypes.SliceDescriptorGenerator; EntityGenerator: TYPE = GGModelTypes.EntityGenerator; FeatureData: TYPE = GGInterfaceTypes.FeatureData; GargoyleData: TYPE = GGInterfaceTypes.GargoyleData; Joint: TYPE = GGModelTypes.Joint; JointGenerator: TYPE = GGModelTypes.JointGenerator; ObjectBag: TYPE = GGGravity.ObjectBag; OutlineDescriptor: TYPE = GGModelTypes.OutlineDescriptor; TriggerBag: TYPE = GGGravity.TriggerBag; Outline: TYPE = GGModelTypes.Outline; Point: TYPE = GGBasicTypes.Point; Scene: TYPE = GGModelTypes.Scene; Segment: TYPE = GGSegmentTypes.Segment; SegAndIndex: TYPE = GGSequence.SegAndIndex; Sequence: TYPE = GGModelTypes.Sequence; SliceParts: TYPE = GGModelTypes.SliceParts; Traj: TYPE = GGModelTypes.Traj; TrajGenerator: TYPE = GGModelTypes.TrajGenerator; SegmentGenerator: TYPE = GGModelTypes.SegmentGenerator; SequenceGenerator: TYPE = GGModelTypes.SequenceGenerator; Vector: TYPE = GGBasicTypes.Vector; NotYetImplemented: PUBLIC SIGNAL = CODE; EnterEditingMode: PROC [gargoyleData: GargoyleData, refChar: REF CHAR] = { IF refChar^=Ascii.BS THEN { -- try to enter editing of a single selected text slice sliceDescGen: SliceDescriptorGenerator _ GGSelect.SelectedSlices[gargoyleData.scene, normal]; sliceDesc: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen]; IF sliceDesc=NIL OR sliceDesc.slice.class.type#$Text OR GGSelect.NextSliceDescriptor[sliceDescGen]#NIL THEN { GGError.AppendHerald[gargoyleData.feedback, "Select a single text slice for editing", oneLiner]; GGError.Blink[gargoyleData.feedback]; RETURN; }; GGSelect.DeselectSlice[slice: sliceDesc.slice, parts: sliceDesc.parts, scene: gargoyleData.scene, selectClass: normal]; gargoyleData.refresh.textInProgress _ sliceDesc.slice; -- successfully enter editing mode GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; } ELSE { slice: Slice _ gargoyleData.refresh.textInProgress _ NewTextSlice[text: Rope.FromChar[refChar^], gargoyleData: gargoyleData]; -- start a new text slice IF slice=NIL THEN RETURN; -- can't start a string with whitespace gargoyleData.refresh.startBoundBox^ _ slice.boundBox^; gargoyleData.refresh.addedObject _ slice; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectAdded, gargoyleData: gargoyleData, remake: sceneBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; }; }; -- end EnterEditingMode AddChar: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; slice: Slice; obBox: BoundBox; refChar: REF CHAR; IF NARROW[event.first, ATOM]#$AddChar THEN ERROR; refChar _ NARROW[event.rest.first]; IF gargoyleData.refresh.textInProgress=NIL THEN { GGCaret.NoAttractor[gargoyleData.caret]; -- so the feedback goes away. EnterEditingMode[gargoyleData, refChar]; RETURN; } ELSE { -- add to textInProgress GGStatistics.StartInterval[$AddChar, GGStatistics.GlobalTable[]]; slice _ gargoyleData.refresh.textInProgress; obBox _ GGBoundBox.CopyBoundBox[slice.boundBox]; -- remember old bound box for now IF refChar^=Ascii.BS THEN { GGSlice.BackspaceText[slice: slice]; gargoyleData.refresh.startBoundBox^ _ slice.boundBox^; -- bBox was updated by GGSlice GGBoundBox.EnlargeByBox[bBox: gargoyleData.refresh.startBoundBox, by: obBox]; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, gargoyleData: gargoyleData, remake: sceneBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; <> } ELSE { GGSlice.AppendText[slice: slice, text: Rope.FromChar[refChar^] ]; gargoyleData.refresh.startBoundBox^ _ slice.boundBox^; -- boundBox was updated by GGSlice GGBoundBox.EnlargeByBox[bBox: gargoyleData.refresh.startBoundBox, by: obBox]; gargoyleData.refresh.addedObject _ slice; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectAdded, gargoyleData: gargoyleData, remake: none, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; <> }; GGStatistics.StopInterval[$AddChar, GGStatistics.GlobalTable[]]; }; }; -- end AddChar NewTextSlice: PRIVATE PROC [text: Rope.ROPE, gargoyleData: GargoyleData] RETURNS [slice: Slice] = { caretPos: Point _ GGCaret.GetPoint[gargoyleData.caret]; success: BOOL; fontName, problem: Rope.ROPE; slice _ GGSlice.MakeTextSlice[text, Imager.black, 1.0]; [fontName, ----, ----, problem] _ GGUtility.FontDataFromUserData[defaultPrefix, defaultFamily, defaultFace, 1.0, defaultPreferredSize]; IF problem#NIL THEN ERROR; success _ GGSlice.SetTextFont[slice, defaultPrefix, defaultFamily, defaultFace, fontName, 1.0, defaultPreferredSize, ImagerTransformation.TranslateTo[defaultTransform, caretPos], gargoyleData.feedback]; IF NOT success THEN ERROR; GGObjects.AddSlice[gargoyleData.scene, slice, -1]; gargoyleData.refresh.startBoundBox^ _ slice.boundBox^; GGSelect.DeselectAll[gargoyleData.scene, normal]; -- speeds up text entry gargoyleData.refresh.addedObject _ slice; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectAdded, gargoyleData: gargoyleData, remake: sceneBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; }; AddText: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; text: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; [] _ NewTextSlice[text, gargoyleData]; }; AmplifySpaceFromSelection: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; amplifySpace: REAL _ NARROW[event.rest.first, REF REAL]^; slices: SliceDescriptorGenerator _ GGSelect.SelectedSlices[gargoyleData.scene, normal]; gargoyleData.refresh.startBoundBox^ _ GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, normal]^; -- remember original bound box FOR sliceD: SliceDescriptor _ GGSelect.NextSliceDescriptor[slices], GGSelect.NextSliceDescriptor[slices] UNTIL sliceD=NIL DO GGSlice.SetTextAmplifySpace[sliceD.slice, amplifySpace, gargoyleData.feedback]; ENDLOOP; GGBoundBox.EnlargeByBox[bBox: gargoyleData.refresh.startBoundBox, by: GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, normal] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: FALSE]; -- GGSlice.SetTextAmplifySpace can post error messages }; -- end AmplifySpaceFromSelection PrintAmplifySpace: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; sliceDescGen: SliceDescriptorGenerator _ GGSelect.SelectedSlices[gargoyleData.scene, normal]; sliceDesc: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen]; IF sliceDesc=NIL OR sliceDesc.slice.class.type#$Text OR GGSelect.NextSliceDescriptor[sliceDescGen]#NIL THEN { GGError.AppendHerald[gargoyleData.feedback, "Select the single text slice whose amplify space need", oneLiner]; GGError.Blink[gargoyleData.feedback]; } ELSE GGError.PutF[gargoyleData.feedback, oneLiner, "Amplify space: %g", [real[GGSlice.GetTextAmplifySpace[sliceDesc.slice]]]]; }; DropShadowOn: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; offsetX: REAL _ NARROW[event.rest.first, REF REAL]^; offsetY: REAL _ NARROW[event.rest.rest.first, REF REAL]^; slices: SliceDescriptorGenerator _ GGSelect.SelectedSlices[gargoyleData.scene, normal]; gargoyleData.refresh.startBoundBox^ _ GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, normal]^; -- remember original bound box FOR sliceD: SliceDescriptor _ GGSelect.NextSliceDescriptor[slices], GGSelect.NextSliceDescriptor[slices] UNTIL sliceD=NIL DO GGSlice.DropShadowOn[sliceD.slice, [offsetX, offsetY]]; ENDLOOP; GGBoundBox.EnlargeByBox[bBox: gargoyleData.refresh.startBoundBox, by: GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, normal] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; }; DropShadowOff: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; slices: SliceDescriptorGenerator _ GGSelect.SelectedSlices[gargoyleData.scene, normal]; gargoyleData.refresh.startBoundBox^ _ GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, normal]^; -- remember original bound box FOR sliceD: SliceDescriptor _ GGSelect.NextSliceDescriptor[slices], GGSelect.NextSliceDescriptor[slices] UNTIL sliceD=NIL DO GGSlice.DropShadowOff[sliceD.slice]; ENDLOOP; GGBoundBox.EnlargeByBox[bBox: gargoyleData.refresh.startBoundBox, by: GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, normal] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; }; <> <> <> <> <<>> <> <> <> <<>> <> <> <<>> <> <> <<>> <> <> <> <> <> <> < pair such as "Helvetica-BI 12". The <-FontFace> may be left off, denoting regular font. Gargoyle assumes FontPrefix = Xerox/PressFonts/ and lets transformation M = Scale[]. The font is made with ImagerFont.Scale[font, 1] (in all cases I know about).>> < pair such as "Helvetica-BI 12". The <-FontFace> may be left off, denoting regular font. Gargoyle assumes FontPrefix = Xerox/XC1-2-2/ and lets transformation M = Scale[]. The font is made with ImagerFont.Scale[font, 1] (in all cases I know about).>> < pair such as "CMR 10". Gargoyle assumes FontPrefix = Xerox/TiogaFonts/ and lets transformation M = Scale[]. The font is made with ImagerFont.Scale[font, 1] if the font is CMR, with ImagerFont.Scale[font, 1.0/], if the font is Helvetica, TimesRoman, Tioga. If the font is one of the traditional TiogaFonts (e.g. Helvetica, TimesRoman, Tioga, ...) Gargoyle will attempt to find the corresponding strike font. For example, SetScreenFont TimesRoman-BI 9 will find the font in file ///fonts/xerox/tiogafonts/TimesRoman9BI.ks. If the user requests a TiogaFont not in the Tioga font set (usually an odd size), Gargoyle will fail to change the font. I don't know which camp Terminal is in. At any rate, Gargoyle will have to keep track of which fonts are in which camp.>> < triple. Gargoyle makes no assumptions. The user must provide a factored transformation. For example:>> <> <> <> < quadruple. Again, Gargoyle uses its information about font camps to successfully make a unit sized font. Otherwise, Gargoyle makes no assumptions.>> <*(1.0/) isn't quite 1.0. We can either round within epsilon for screen fonts, or we can keep around an unscaled font when we know we should be hitting the fast case.>> <> <> <<>> <> <> SetFontAux: PROC [clientData: REF ANY, prefix: Rope.ROPE, family: Rope.ROPE, face: Rope.ROPE, fontName: Rope.ROPE, size: REAL, preferredSize: REAL, transform: ImagerTransformation.Transformation] = { gargoyleData: GargoyleData _ NARROW[clientData]; slices: SliceDescriptorGenerator _ GGSelect.SelectedSlices[gargoyleData.scene, normal]; gargoyleData.refresh.startBoundBox^ _ GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, normal]^; -- remember original bound box FOR sliceD: SliceDescriptor _ GGSelect.NextSliceDescriptor[slices], GGSelect.NextSliceDescriptor[slices] UNTIL sliceD=NIL DO [] _ GGSlice.SetTextFont[sliceD.slice, prefix, family, face, fontName, size, preferredSize, transform, gargoyleData.feedback]; ENDLOOP; GGBoundBox.EnlargeByBox[bBox: gargoyleData.refresh.startBoundBox, by: GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, normal] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: FALSE]; -- GGSlice.SetTextFont can post error messages }; SetLookAlikes: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { <> gargoyleData: GargoyleData _ NARROW[clientData]; lastDesc: SliceDescriptor; sliceDescGen: SliceDescriptorGenerator _ GGSelect.SelectedSlices[gargoyleData.scene, normal]; FOR sliceD: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen], GGSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD=NIL DO lastDesc _ sliceD; -- find the LAST selected slice ENDLOOP; BEGIN IF lastDesc=NIL OR lastDesc.slice.class.type#$Text THEN GOTO BadLastSlice ELSE { prefix, family, face, fontName, problem: Rope.ROPE; transform: ImagerTransformation.Transformation; preferredSize: REAL _ -1.0; fontRope: Rope.ROPE _ GGSlice.GetFontValuesRope[lastDesc.slice]; [prefix, family, face, transform, preferredSize] _ GGSlice.GetFontValues[lastDesc.slice]; [fontName, ----, ----, problem] _ GGUtility.FontDataFromUserData[prefix, family, face, 1.0, preferredSize]; IF problem#NIL THEN ERROR; gargoyleData.refresh.startBoundBox^ _ GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, normal]^; -- remember original bound box sliceDescGen _ GGSelect.SelectedSlices[gargoyleData.scene, normal]; FOR sliceD: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen], GGSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD=NIL DO [] _ GGSlice.SetTextFont[sliceD.slice, prefix, family, face, fontName, 1.0, preferredSize, ImagerTransformation.TranslateTo[transform, ImagerTransformation.Factor[GGSlice.GetFontValues[sliceD.slice].transform].t ], gargoyleData.feedback]; ENDLOOP; GGBoundBox.EnlargeByBox[bBox: gargoyleData.refresh.startBoundBox, by: GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, normal] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; GGError.PutFHerald[gargoyleData.feedback, oneLiner, "Text slices with font %g selected", [rope[fontRope]] ]; }; EXITS BadLastSlice => { GGError.AppendHerald[gargoyleData.feedback, "Select a final text slice for Font Look Alike", oneLiner]; GGError.Blink[gargoyleData.feedback]; }; END; }; ChangeFont: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { < from the Tioga selection to all selected text slices>> gargoyleData: GargoyleData _ NARROW[clientData]; fail: BOOL _ FALSE; newFamily, newFace: Rope.ROPE; prefix, family, face, fontName, problem: Rope.ROPE; transform: ImagerTransformation.Transformation; preferredSize: REAL _ -1.0; fontRope: Rope.ROPE; inStream: IO.STREAM _ IO.RIS[IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]]; [fail, ----, newFamily, newFace, ----, ----] _ GGUtility.ParseFontData[inStream, FALSE, TRUE, TRUE]; BEGIN IF fail THEN GOTO ParseError ELSE { sliceDescGen: SliceDescriptorGenerator _ GGSelect.SelectedSlices[gargoyleData.scene, normal]; gargoyleData.refresh.startBoundBox^ _ GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, normal]^; -- remember original bound box FOR sliceD: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen], GGSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD=NIL DO IF sliceD.slice.class.type#$Text THEN LOOP; [prefix, family, face, transform, preferredSize] _ GGSlice.GetFontValues[sliceD.slice]; [fontName, ----, ----, problem] _ GGUtility.FontDataFromUserData[prefix, newFamily, newFace, 1.0, preferredSize]; IF problem#NIL THEN GOTO FontNameProblem; [] _ GGSlice.SetTextFont[sliceD.slice, prefix, newFamily, newFace, fontName, 1.0, preferredSize, transform, gargoyleData.feedback]; ENDLOOP; GGBoundBox.EnlargeByBox[bBox: gargoyleData.refresh.startBoundBox, by: GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, normal] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; GGError.PutFHerald[gargoyleData.feedback, oneLiner, "Text slices with font %g selected", [rope[fontRope]] ]; }; EXITS ParseError => GGError.PutF[gargoyleData.feedback, oneLiner, "Font Parse Error: %g%g", [rope[family]], [rope[face]] ]; FontNameProblem => { gargoyleData: GargoyleData _ NARROW[clientData]; GGError.PutF[gargoyleData.feedback, oneLiner, "%g", [rope[problem]] ]; }; END; }; SetPressFont: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { < . e.g. "Cream-BI 10">> inStream: IO.STREAM _ IO.RIS[NARROW[event.rest.first]]; -- "Cream-BI 12" fail: BOOL _ FALSE; size: REAL _ 1.0; prefix, family, face, fontName, problem: Rope.ROPE; prefix _ "xerox/pressfonts/"; -- default prefix for SetPressFont BEGIN [fail, ----, family, face, ----, size] _ GGUtility.ParseFontData[inStream, FALSE, TRUE, TRUE, FALSE, TRUE]; IF fail THEN GOTO ParseError ELSE { [fontName, ----, ----, problem] _ GGUtility.FontDataFromUserData[prefix, family, face, 1.0, size]; IF problem#NIL THEN GOTO FontNameProblem; SetFontAux[clientData, prefix, family, face, fontName, size, 1.0, NIL]; }; EXITS FontNameProblem => { gargoyleData: GargoyleData _ NARROW[clientData]; GGError.PutF[gargoyleData.feedback, oneLiner, "%g", [rope[problem]] ]; }; ParseError => { gargoyleData: GargoyleData _ NARROW[clientData]; GGError.PutF[gargoyleData.feedback, oneLiner, "Font Parse Error: %g%g%g %g", [rope[prefix]], [rope[family]], [rope[face]], [real[size]] ]; }; END; }; SetPrintFont: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { < . e.g. "Modern-BI 23">> inStream: IO.STREAM _ IO.RIS[NARROW[event.rest.first]]; -- "Modern-BI 23" fail: BOOL _ FALSE; size: REAL _ -1.0; prefix, family, face, fontName, problem: Rope.ROPE; prefix _ "xerox/xc1-2-2/"; -- default prefix for SetPrintFont BEGIN [fail, ----, family, face, ----, size] _ GGUtility.ParseFontData[inStream, FALSE, TRUE, TRUE, FALSE, TRUE]; IF fail THEN GOTO ParseError ELSE { [fontName, ----, ----, problem] _ GGUtility.FontDataFromUserData[prefix, family, face, 1.0, size]; IF problem#NIL THEN GOTO FontNameProblem; SetFontAux[clientData, prefix, family, face, fontName, size, 1.0, NIL]; }; EXITS FontNameProblem => { gargoyleData: GargoyleData _ NARROW[clientData]; GGError.PutF[gargoyleData.feedback, oneLiner, "%g", [rope[problem]] ]; }; ParseError => { gargoyleData: GargoyleData _ NARROW[clientData]; GGError.PutF[gargoyleData.feedback, oneLiner, "Font Parse Error: %g%g%g %g", [rope[prefix]], [rope[family]], [rope[face]], [real[size]] ]; }; END; }; <> < . e.g. "xerox/myfonts/ fontOne-BI [1.0 2.0 3.0 4.0 5.0 6.0]. Whitespace is critical!!>> <> <> <> <> <> <<[fail, prefix, family, face, transform, ----] _ GGUtility.ParseFontData[inStream, TRUE, TRUE, TRUE, TRUE, FALSE];>> <> <> <> <> <> <> <<}>> <> <<[faceRope, problem] _ GGUtility.FaceRopeFromFace[prefix, family, face, 1.0];>> <> <> <<};>> <> < {>> <> <> <<};>> < {>> <> <> <<};>> <> <<};>> <<>> SetScreenFont: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { < . e.g. "Cream-BI 10">> prefix, family, face, fontName, problem: Rope.ROPE; preferredSize: REAL _ -1.0; inStream: IO.STREAM _ IO.RIS[NARROW[event.rest.first]]; -- "Cream-BI 12" fail: BOOL _ FALSE; BEGIN prefix _ "xerox/tiogafonts/"; -- default prefix for SetScreenFont [fail, ----, family, face, ----, preferredSize] _ GGUtility.ParseFontData[inStream, FALSE, TRUE, TRUE, FALSE, TRUE]; IF fail THEN GOTO ParseError ELSE { [fontName, ----, ----, problem] _ GGUtility.FontDataFromUserData[prefix, family, face, 1.0, preferredSize]; IF problem#NIL THEN GOTO FontNameProblem; SetFontAux[clientData, prefix, family, face, fontName, preferredSize, preferredSize, NIL]; }; EXITS ParseError => { gargoyleData: GargoyleData _ NARROW[clientData]; GGError.PutF[gargoyleData.feedback, oneLiner, "Font Parse Error: %g%g%g %g", [rope[prefix]], [rope[family]], [rope[face]], [real[preferredSize]] ]; }; FontNameProblem => { gargoyleData: GargoyleData _ NARROW[clientData]; GGError.PutF[gargoyleData.feedback, oneLiner, "%g", [rope[problem]] ]; }; END; }; SetFontDetailed: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { < e.g. "xerox/myfonts/ fontOne-BI [1.0 2.0 3.0 4.0 5.0 6.0] 12. Whitespace is critical!!>> fail: BOOL _ FALSE; prefix, family, face, fontName, problem: Rope.ROPE; transform: ImagerTransformation.Transformation; preferredSize: REAL _ -1.0; inStream: IO.STREAM _ IO.RIS[NARROW[event.rest.first]]; [fail, prefix, family, face, transform, preferredSize] _ GGUtility.ParseFontData[inStream, TRUE, TRUE, TRUE, TRUE, TRUE]; BEGIN IF fail THEN { gargoyleData: GargoyleData _ NARROW[clientData]; scratch: IO.STREAM _ IO.ROS[]; IF transform#NIL THEN GGParseOut.WriteFactoredTransformation[scratch, transform]; GGError.PutF[gargoyleData.feedback, oneLiner, "Font Parse Error: %g%g%g %g %g", [rope[prefix]], [rope[family]], [rope[face]], [rope[IO.RopeFromROS[scratch]]], [real[preferredSize]] ]; } ELSE { [fontName, ----, ----, problem] _ GGUtility.FontDataFromUserData[prefix, family, face, 1.0, preferredSize]; IF problem#NIL THEN GOTO FontNameProblem; SetFontAux[clientData, prefix, family, face, fontName, 1.0, preferredSize, transform]; }; EXITS FontNameProblem => { gargoyleData: GargoyleData _ NARROW[clientData]; GGError.PutF[gargoyleData.feedback, oneLiner, "%g", [rope[problem]] ]; }; END; }; SetFontLiteral: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = {}; SetDefaultFontValues: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { <> gargoyleData: GargoyleData _ NARROW[clientData]; sliceDescGen: SliceDescriptorGenerator _ GGSelect.SelectedSlices[gargoyleData.scene, normal]; sliceDesc: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen]; IF sliceDesc=NIL OR sliceDesc.slice.class.type#$Text OR GGSelect.NextSliceDescriptor[sliceDescGen]#NIL THEN { GGError.AppendHerald[gargoyleData.feedback, "Select a single text slice for default font setting", oneLiner]; GGError.Blink[gargoyleData.feedback]; } ELSE { [defaultPrefix, defaultFamily, defaultFace, defaultTransform, defaultPreferredSize] _ GGSlice.GetFontValues[sliceDesc.slice]; GGError.PutF[gargoyleData.feedback, oneLiner, "New Default Font: %g", [rope[GGSlice.GetFontValuesRope[sliceDesc.slice]]] ]; }; }; ShowFontValues: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { < transformation preferredSize>> gargoyleData: GargoyleData _ NARROW[clientData]; sliceDescGen: SliceDescriptorGenerator _ GGSelect.SelectedSlices[gargoyleData.scene, normal]; sliceDesc: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen]; IF sliceDesc=NIL OR sliceDesc.slice.class.type#$Text OR GGSelect.NextSliceDescriptor[sliceDescGen]#NIL THEN { GGError.AppendHerald[gargoyleData.feedback, "Select a single text slice for font printing", oneLiner]; GGError.Blink[gargoyleData.feedback]; } ELSE GGError.PutF[gargoyleData.feedback, oneLiner, "Font Values: %g", [rope[GGSlice.GetFontValuesRope[sliceDesc.slice]]] ]; }; ShowFontValuesLiteral: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = {}; ShowDefaultFontValues: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; scratch: IO.STREAM _ IO.ROS[]; GGParseOut.WriteFactoredTransformation[scratch, defaultTransform]; GGError.PutF[gargoyleData.feedback, oneLiner, "Default Font Values: %g %g%g %g %g", [rope[defaultPrefix]], [rope[defaultFamily]], [rope[defaultFace]], [rope[IO.RopeFromROS[scratch]]], [real[defaultPreferredSize]] ]; }; FindTextMatchingSelected: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { <> gargoyleData: GargoyleData _ NARROW[clientData]; sliceDescGen: SliceDescriptorGenerator _ GGSelect.SelectedSlices[gargoyleData.scene, normal]; sliceDesc: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen]; IF sliceDesc=NIL OR sliceDesc.slice.class.type#$Text OR GGSelect.NextSliceDescriptor[sliceDescGen]#NIL THEN { GGError.AppendHerald[gargoyleData.feedback, "Select a single text slice for font matching", oneLiner]; GGError.Blink[gargoyleData.feedback]; } ELSE { -- select all the text slices with matching fonts prefix, family, face: Rope.ROPE; transform: ImagerTransformation.Transformation; preferredSize: REAL _ -1.0; [prefix, family, face, transform, preferredSize] _ GGSlice.GetFontValues[sliceDesc.slice]; SelectMatchingFonts[prefix, family, face, transform, preferredSize, GGSlice.GetFontValuesRope[sliceDesc.slice], gargoyleData]; }; }; FindTextMatchingValues: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { <> gargoyleData: GargoyleData _ NARROW[clientData]; matchRope: Rope.ROPE _ NARROW[event.rest.first]; IF Rope.Equal[matchRope, ""] THEN { GGError.AppendHerald[gargoyleData.feedback, "Select font values for matching", oneLiner]; } ELSE { prefix, family, face: Rope.ROPE; transform: ImagerTransformation.Transformation; preferredSize: REAL _ -1.0; fail: BOOL; [fail, prefix, family, face, transform, preferredSize] _ GGUtility.ParseFontData[IO.RIS[matchRope], TRUE, TRUE, TRUE, TRUE, TRUE]; -- parse the match rope into values IF fail THEN GGError.AppendHerald[gargoyleData.feedback, "Ill formed font values for matching", oneLiner] ELSE SelectMatchingFonts[prefix, family, face, transform, preferredSize, matchRope, gargoyleData]; }; }; SelectMatchingFonts: PROC [prefix, family, face: Rope.ROPE, transform: ImagerTransformation.Transformation, preferredSize: REAL, fontRope: Rope.ROPE, gargoyleData: GargoyleData] = { maxPixels: REAL _ 10000.0; sliceGen: SliceGenerator _ GGObjects.SlicesInScene[gargoyleData.scene]; GGSelect.DeselectAll[gargoyleData.scene, normal]; FOR slice: Slice _ GGObjects.NextSlice[sliceGen], GGObjects.NextSlice[sliceGen] UNTIL slice=NIL DO prefixS, familyS, faceS: Rope.ROPE; transformS: ImagerTransformation.Transformation; preferredSizeS: REAL; [prefixS, familyS, faceS, transformS, preferredSizeS] _ GGSlice.GetFontValues[slice]; IF Rope.Equal[prefix, prefixS, FALSE] AND Rope.Equal[family, familyS, FALSE] AND Rope.Equal[face, faceS, FALSE] AND RealFns.AlmostEqual[preferredSize, preferredSizeS, -9] AND --ImagerTransformation.--CloseToTranslation[transform, transformS, maxPixels] THEN GGSelect.SelectSlice[slice: slice, parts: slice.class.newParts[slice, NIL, topLevel], scene: gargoyleData.scene, selectClass: normal]; ENDLOOP; GGError.PutFHerald[gargoyleData.feedback, oneLiner, "Text slices with font %g selected", [rope[fontRope]] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; FindTextMatchingFamily: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { <> gargoyleData: GargoyleData _ NARROW[clientData]; matchRope: Rope.ROPE _ NARROW[event.rest.first]; IF Rope.Equal[matchRope, ""] THEN { GGError.AppendHerald[gargoyleData.feedback, "Select font family for matching", oneLiner]; RETURN; } ELSE { sliceGen: SliceGenerator _ GGObjects.SlicesInScene[gargoyleData.scene]; GGSelect.DeselectAll[gargoyleData.scene, normal]; FOR slice: Slice _ GGObjects.NextSlice[sliceGen], GGObjects.NextSlice[sliceGen] UNTIL slice=NIL DO IF Rope.Equal[matchRope, GGSlice.GetFontValues[slice].family, FALSE] THEN GGSelect.SelectSlice[slice: slice, parts: slice.class.newParts[slice, NIL, topLevel], scene: gargoyleData.scene, selectClass: normal]; ENDLOOP; GGError.PutFHerald[gargoyleData.feedback, oneLiner, "Text slices with font %g selected", [rope[matchRope]] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; }; <> ReadIP: PROC [ipName: Rope.ROPE, clientData: REF ANY, opName: Rope.ROPE] RETURNS [scene: Scene _ NIL] = { ReadMaster: PROC [context: Imager.Context] = { Imager.ScaleT[context, 2834.646]; -- pointsPerMeter=2834.646 Interpress.DoPage[master: ipmaster, page: 1, context: context, log: NIL]; }; gargoyleData: GargoyleData _ NARROW[clientData]; ipmaster: Interpress.Master _ NIL; fullName: Rope.ROPE; startTime, endTime: BasicTime.GMT; totalTime: INT; success: BOOL _ FALSE; [fullName, success] _ GGUtility.GetInterpressFileName[ipName, gargoyleData.currentWDir, gargoyleData.feedback]; IF NOT success THEN RETURN; [ipmaster, success] _ GGUtility.OpenInterpressOrComplain[gargoyleData.feedback, fullName]; IF NOT success THEN RETURN; GGError.PutF[gargoyleData.feedback, begin, "%g %g . . . ", [rope[opName]], [rope[fullName]]]; startTime _ BasicTime.Now[]; scene _ GGFromImager.Capture[action: ReadMaster ! GGFromImager.Warning => { GGError.Append[gargoyleData.feedback, message, oneLiner]; RESUME; };]; endTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[startTime, endTime]; GGError.PutF[gargoyleData.feedback, end, " Done in time (%r)", [integer[totalTime]]]; }; MergeIPEditable: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; ipName: Rope.ROPE _ NARROW[event.rest.first]; scene: Scene _ ReadIP[ipName, clientData, "MergeIPEditable"]; IF scene = NIL THEN RETURN; gargoyleData.scene _ GGObjects.MergeScenes[back: gargoyleData.scene, front: scene]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: FALSE]; }; MergeIPSlice: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { slice: Slice; gargoyleData: GargoyleData _ NARROW[clientData]; shortName, fullName: Rope.ROPE; startTime, endTime: BasicTime.GMT; totalTime: INT; ipMaster: Interpress.Master; success: BOOL; shortName _ NARROW[event.rest.first]; [fullName, success] _ GGUtility.GetInterpressFileName[shortName, gargoyleData.currentWDir, gargoyleData.feedback]; IF NOT success THEN RETURN; [ipMaster, success] _ GGUtility.OpenInterpressOrComplain[gargoyleData.feedback, fullName]; IF NOT success THEN RETURN; GGError.PutF[gargoyleData.feedback, begin, "MergeIPSlice %g . . . ", [rope[fullName]]]; startTime _ BasicTime.Now[]; slice _ GGSlice.MakeIPSliceFromMaster[ipMaster, 2834.646, fullName, gargoyleData.feedback, NIL, NIL, FALSE]; IF slice = NIL THEN RETURN; GGObjects.AddSlice[gargoyleData.scene, slice, -1]; endTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[startTime, endTime]; GGError.PutF[gargoyleData.feedback, end, " Done in time (%r)", [integer[totalTime]]]; gargoyleData.refresh.startBoundBox^ _ slice.boundBox^; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, gargoyleData: gargoyleData, remake: sceneBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: FALSE]; }; -- end MergeIPSlice IncludeIPByReference: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { <> gargoyleData: GargoyleData _ NARROW[clientData]; sliceDescGen: GGSelect.SliceDescriptorGenerator; sliceDescGen _ GGSelect.SelectedSlices[gargoyleData.scene, normal]; FOR sliceD: GGSelect.SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen], GGSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD = NIL DO IF sliceD.slice.class.type = $IP THEN GGSlice.SetIncludeByValue[sliceD.slice, FALSE]; ENDLOOP; }; IncludeIPByValue: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { <> gargoyleData: GargoyleData _ NARROW[clientData]; sliceDescGen: GGSelect.SliceDescriptorGenerator; sliceDescGen _ GGSelect.SelectedSlices[gargoyleData.scene, normal]; FOR sliceD: GGSelect.SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen], GGSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD = NIL DO IF sliceD.slice.class.type = $IP THEN GGSlice.SetIncludeByValue[sliceD.slice, TRUE]; ENDLOOP; }; ShowIPIncludeMode: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { <> gargoyleData: GargoyleData _ NARROW[clientData]; sliceDescGen: GGSelect.SliceDescriptorGenerator; includeByValue: BOOL; sliceDescGen _ GGSelect.SelectedSlices[gargoyleData.scene, normal]; FOR sliceD: GGSelect.SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen], GGSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD = NIL DO IF sliceD.slice.class.type = $IP THEN { includeByValue _ GGSlice.GetIncludeByValue[sliceD.slice]; IF includeByValue THEN GGError.Append[gargoyleData.feedback, "include by value", oneLiner] ELSE GGError.Append[gargoyleData.feedback, "include by reference", oneLiner]; RETURN; }; ENDLOOP; GGError.Append[gargoyleData.feedback, "ShowIPIncludeMode: No IP Slices selected", oneLiner]; GGError.Blink[gargoyleData.feedback]; }; ToIPAux: PROC [gargoyleData: GargoyleData, ipName: Rope.ROPE, actionAtom: ATOM, makeInterpress: PROC [dc: Imager.Context]] = { ipRef: ImagerInterpress.Ref; fullName: Rope.ROPE; success: BOOL; <> startTime: BasicTime.GMT; endTime: BasicTime.GMT; totalTime: INT; msgRope: Rope.ROPE; [fullName, success] _ GGUtility.GetInterpressFileName[ipName, gargoyleData.currentWDir, gargoyleData.feedback]; IF NOT success THEN RETURN; ipRef _ ImagerInterpress.Create[fullName]; [fullName] _ FS.FileInfo[fullName]; -- append the version number msgRope _ IO.PutFR["%g %g . . . ", [rope[Atom.GetPName[actionAtom]]], [rope[fullName]]]; GGError.Append[gargoyleData.feedback, msgRope, begin]; <> startTime _ BasicTime.Now[]; ImagerInterpress.DoPage[ipRef, makeInterpress, 1.0]; ImagerInterpress.Close[ipRef]; endTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[startTime, endTime]; msgRope _ IO.PutFR[" Done in time (%r)", [integer[totalTime]]]; GGError.Append[gargoyleData.feedback, msgRope, end]; GGEvent.SawTextFinish[NIL, gargoyleData]; }; ToIP: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { DoMakeInterpress: PROC [dc: Imager.Context] = { tempQuality: GGInterfaceTypes.QualityMode; tempStyle: GGInterfaceTypes.DisplayStyle; pixelsPerMeter: REAL = 0.0254/72.0; tempQuality _ gargoyleData.camera.quality; gargoyleData.camera.quality _ quality; tempStyle _ gargoyleData.camera.displayStyle; gargoyleData.camera.displayStyle _ print; Imager.ScaleT[dc, pixelsPerMeter]; GGRefresh.InterpressEntireScene[dc, gargoyleData]; gargoyleData.camera.quality _ tempQuality; gargoyleData.camera.displayStyle _ tempStyle; }; gargoyleData: GargoyleData _ NARROW[clientData]; ipName: Rope.ROPE _ NARROW[event.rest.first]; ToIPAux[gargoyleData, ipName, NARROW[event.first], DoMakeInterpress]; }; ToIPTestGravity: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { DoMakeInterpress: PROC [dc: Imager.Context] = { tempQuality: GGInterfaceTypes.QualityMode; tempStyle: GGInterfaceTypes.DisplayStyle; pixelsPerMeter: REAL = 0.0254/72.0; tempQuality _ gargoyleData.camera.quality; gargoyleData.camera.quality _ quality; tempStyle _ gargoyleData.camera.displayStyle; gargoyleData.camera.displayStyle _ print; Imager.ScaleT[dc, pixelsPerMeter]; TestGravity2[dc, gargoyleData]; gargoyleData.camera.quality _ tempQuality; gargoyleData.camera.displayStyle _ tempStyle; }; gargoyleData: GargoyleData _ NARROW[clientData]; ipName: Rope.ROPE _ NARROW[event.rest.first]; ToIPAux[gargoyleData, ipName, NARROW[event.first], DoMakeInterpress]; }; ToIPScreen: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { DoMakeInterpress: PROC [dc: Imager.Context] = { tempQuality: GGInterfaceTypes.QualityMode; tempStyle: GGInterfaceTypes.DisplayStyle; pixelsPerMeter: REAL = 0.0254/72.0; tempQuality _ gargoyleData.camera.quality; gargoyleData.camera.quality _ quality; tempStyle _ gargoyleData.camera.displayStyle; gargoyleData.camera.displayStyle _ screen; Imager.ScaleT[dc, pixelsPerMeter]; GGRefresh.InterpressEntireScene[dc, gargoyleData]; gargoyleData.camera.quality _ tempQuality; gargoyleData.camera.displayStyle _ tempStyle; }; gargoyleData: GargoyleData _ NARROW[clientData]; ipName: Rope.ROPE _ NARROW[event.rest.first]; ToIPAux[gargoyleData, ipName, NARROW[event.first], DoMakeInterpress]; }; ToIPLit: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { DoMakeInterpress: PROC [dc: Imager.Context] = { switched: BOOL _ FALSE; tempQuality _ gargoyleData.camera.quality; gargoyleData.camera.quality _ showall; tempStyle _ gargoyleData.camera.displayStyle; gargoyleData.camera.displayStyle _ print; IF AtomButtons.GetButtonState[gargoyleData.refresh.showColors] = off THEN { GGEvent.ToggleShowColors[NIL, gargoyleData]; switched _ TRUE; }; Imager.ScaleT[dc, pixelsPerMeter]; GGRefresh.PaintEntireScene[dc, gargoyleData]; gargoyleData.camera.quality _ tempQuality; gargoyleData.camera.displayStyle _ tempStyle; IF switched THEN GGEvent.ToggleShowColors[NIL, gargoyleData]; }; gargoyleData: GargoyleData _ NARROW[clientData]; ipRef: ImagerInterpress.Ref; fullName: Rope.ROPE; success: BOOL; pixelsPerMeter: REAL = 0.0254/72.0; <> startTime: BasicTime.GMT; endTime: BasicTime.GMT; totalTime: INT; msgRope: Rope.ROPE; tempQuality: GGInterfaceTypes.QualityMode; tempStyle: GGInterfaceTypes.DisplayStyle; ipName: Rope.ROPE _ "litshot.ip"; [fullName, success] _ GGUtility.GetInterpressFileName[ipName, gargoyleData.currentWDir, gargoyleData.feedback]; IF NOT success THEN RETURN; ipRef _ ImagerInterpress.Create[fullName]; msgRope _ IO.PutFR["Writing to IP file: %g . . . ", [rope[fullName]]]; GGError.Append[gargoyleData.feedback, msgRope, begin]; <> startTime _ BasicTime.Now[]; ImagerInterpress.DoPage[ipRef, DoMakeInterpress, 1.0]; ImagerInterpress.Close[ipRef]; endTime _ BasicTime.Now[]; totalTime _ BasicTime.Period[startTime, endTime]; msgRope _ IO.PutFR[" Done in time (%r)", [integer[totalTime]]]; GGError.Append[gargoyleData.feedback, msgRope, end]; GGEvent.SawTextFinish[NIL, gargoyleData]; }; <<>> <> TestGravity2: PUBLIC PROC [dc: Imager.Context, gargoyleData: GargoyleData] = { <> xRandomStream, yRandomStream: Random.RandomStream; testPoint: Point; x, y: INT; totalCount, multiHitCount, uniHitCount, diffCount: NAT _ 0; uniPoint, multiPoint: Point; uniFeature, multiFeature: FeatureData; currentObjects: ObjectBag; sceneObjects: TriggerBag; xRandomStream _ Random.Create[gargoyleData.actionArea.cw]; yRandomStream _ Random.Create[gargoyleData.actionArea.ch]; GGAlign.SetBagsForAction[gargoyleData, $CaretPos]; gargoyleData.aborted[gravitytest] _ FALSE; -- in case there was one left over from prior abort UNTIL totalCount > 1000 DO IF gargoyleData.aborted[gravitytest] THEN { gargoyleData.aborted[gravitytest] _ FALSE; EXIT; }; x _ Random.NextInt[xRandomStream]; y _ Random.NextInt[yRandomStream]; testPoint _ [x, y]; testPoint _ GGWindow.ViewerToWorld[viewerPoint: testPoint, gargoyleData: gargoyleData]; gargoyleData.refresh.spotPoint _ testPoint; currentObjects _ gargoyleData.hitTest.currentObjectBag; sceneObjects _ gargoyleData.hitTest.sceneTriggerBag; [uniPoint, uniFeature] _ GGGravity.UniMap[testPoint, gargoyleData.hitTest.tolerance, currentObjects, sceneObjects, gargoyleData, TRUE]; [multiPoint, multiFeature] _ GGMultiGravity.Map[testPoint, gargoyleData.hitTest.tolerance, currentObjects, sceneObjects, gargoyleData, TRUE]; IF uniFeature = NIL AND multiFeature = NIL THEN { PaintSpot[dc, gargoyleData]; totalCount _ totalCount + 1; LOOP; }; IF uniFeature = NIL OR multiFeature = NIL OR uniFeature # multiFeature OR uniFeature.resultType # multiFeature.resultType OR uniPoint # multiPoint THEN { ReportResultsAndPaint2[dc, testPoint, uniPoint, uniFeature, multiPoint, multiFeature, gargoyleData]; totalCount _ totalCount + 1; diffCount _ diffCount + 1; IF multiFeature # NIL THEN multiHitCount _ multiHitCount + 1; IF uniFeature # NIL THEN uniHitCount _ uniHitCount + 1; } ELSE { multiHitCount _ multiHitCount + 1; uniHitCount _ uniHitCount + 1; totalCount _ totalCount + 1; gargoyleData.refresh.hitPoint _ multiPoint; PaintHitLine[dc, gargoyleData]; }; ENDLOOP; GGError.PutF[gargoyleData.feedback, oneLiner, "Tested %g total points. %g unihits. %g multihits. %g differences", [integer[totalCount]], [integer[uniHitCount]], [integer[multiHitCount]], [integer[diffCount]]]; }; -- end TestGravity2 PaintSpot: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = { Imager.SetColor[screen, Imager.black]; GGShapes.DrawSpot[screen, gargoyleData.refresh.spotPoint]; }; PaintOddHitLine: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = { Imager.SetColor[screen, Imager.black]; Imager.SetStrokeEnd[screen, round]; Imager.MaskVector[screen, [gargoyleData.refresh.spotPoint.x, gargoyleData.refresh.spotPoint.y], [gargoyleData.refresh.hitPoint.x, gargoyleData.refresh.hitPoint.y]]; GGShapes.DrawCP[screen, gargoyleData.refresh.spotPoint]; }; PaintHitLine: PROC [screen: Imager.Context, gargoyleData: GargoyleData] = { Imager.SetColor[screen, Imager.black]; Imager.SetStrokeEnd[screen, round]; Imager.MaskVector[screen, [gargoyleData.refresh.spotPoint.x, gargoyleData.refresh.spotPoint.y], [gargoyleData.refresh.hitPoint.x, gargoyleData.refresh.hitPoint.y]]; GGShapes.DrawFilledRect[screen, gargoyleData.refresh.spotPoint, 3.0]; }; ReportResultsAndPaint2: PROC [dc: Imager.Context, testPoint: Point, uniPoint: Point, uniFeature: FeatureData, multiPoint: Point, multiFeature: FeatureData, gargoyleData: GargoyleData] = { IF uniFeature = NIL THEN { gargoyleData.refresh.hitPoint _ multiPoint; } ELSE IF multiFeature = NIL THEN { gargoyleData.refresh.hitPoint _ uniPoint; } ELSE IF uniFeature # multiFeature THEN { gargoyleData.refresh.hitPoint _ multiPoint; } ELSE IF uniFeature.resultType # multiFeature.resultType THEN { gargoyleData.refresh.hitPoint _ multiPoint; } ELSE IF uniPoint # multiPoint THEN { gargoyleData.refresh.hitPoint _ uniPoint; PaintOddHitLine[dc, gargoyleData]; gargoyleData.refresh.hitPoint _ multiPoint; } ELSE ERROR; PaintOddHitLine[dc, gargoyleData]; }; <> <> <> <> <> <<];>> <> <> <<};>> <> <> <<};>> <<>> <> <> <> <> <<};>> <<>> UnionCombine: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; <> <> <> <> <> <> <> <> <> <> <> <> <> <<}>> <> <> <> <<};>> GGError.AppendHerald[gargoyleData.feedback, "UnionCombine not implemented", oneLiner]; GGError.Blink[gargoyleData.feedback]; }; -- end UnionCombine <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<[] _ DeleteAllSelected[gargoyleData];>> <> <> <> <> <> <> <> <> <> <> <> <> < {>> <> <> <<};>> <> <> <> <> <<};>> <<>> AddHoles: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; seqGen: SequenceGenerator _ GGSelect.SelectedSequences[gargoyleData.scene, normal]; fenceSeq, firstHoleSeq: Sequence; fence, hole: Traj; outline: Outline; bBox: BoundBox _ GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, normal]; fenceSeq _ GGSequence.NextSequence[seqGen]; IF fenceSeq = NIL OR fenceSeq.traj.role#fence THEN { GGError.AppendHerald[gargoyleData.feedback, "Select a closed trajectory to add holes to.", oneLiner]; GOTO Abort; }; fence _ fenceSeq.traj; outline _ GGOutline.OutlineOfTraj[fence]; firstHoleSeq _ GGSequence.NextSequence[seqGen]; IF firstHoleSeq = NIL THEN { GGError.AppendHerald[gargoyleData.feedback, "Extend your selection to some closed trajectories to make holes.", oneLiner]; GOTO Abort; }; FOR holeSeq: Sequence _ firstHoleSeq, GGSequence.NextSequence[seqGen] UNTIL holeSeq = NIL DO hole _ holeSeq.traj; IF NOT GGObjects.IsTopLevel[hole] THEN LOOP; IF holeSeq.traj.role#fence THEN { GGError.AppendHerald[gargoyleData.feedback, "Select only CLOSED trajectories as holes.", oneLiner]; LOOP; }; outline _ GGInterface.AddHole[outline, hole, gargoyleData.scene]; ENDLOOP; GGBoundBox.EnlargeByBox[bBox: bBox, by: outline.boundBox]; -- boundBox of old shape and new shape gargoyleData.refresh.startBoundBox^ _ bBox^; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: FALSE]; EXITS Abort => GGError.Blink[NARROW[clientData, GargoyleData].feedback]; }; -- end AddHoles <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <<[oldOutline,----] _ GGInterface.DeleteSequence[holeSeq, gargoyleData.scene];>> <> <> <> <> <> <<[oldOutline,----] _ GGInterface.DeleteSequence[fenceSeq, gargoyleData.scene];>> <> <> <> <<}>> <> <> <> <<};>> <> <<};>> <> < {>> <> <<};>> <> <<>> <> <<};>> <<>> DeleteAllSelected: PROC [gargoyleData: GargoyleData] RETURNS [bBox: BoundBox] = { DeleteRun: GGSelect.RunProc = { traj _ NIL; }; sliceDescGen: SliceDescriptorGenerator; thisBox: BoundBox; bBox _ GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, normal]; <> sliceDescGen _ GGSelect.SelectedSlices[gargoyleData.scene, normal]; FOR sliceD: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDescGen], GGSelect.NextSliceDescriptor[sliceDescGen] UNTIL sliceD = NIL DO GGSelect.DeselectEntityAllClasses[sliceD.slice, gargoyleData.scene]; GGSlice.DeleteSlice[gargoyleData.scene, sliceD.slice]; ENDLOOP; GGCaret.NoAttractor[gargoyleData.caret]; <> thisBox _ GGSelect.ForEachOutlineRun[gargoyleData.scene, gargoyleData.caret, normal, DeleteRun, FALSE]; GGBoundBox.EnlargeByBox[bBox: bBox, by: thisBox]; }; Delete: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; bBoxOfSelected: BoundBox; GGStatistics.StartInterval[$Delete, GGStatistics.GlobalTable[]]; bBoxOfSelected _ GGBoundBox.BoundBoxOfSelected[gargoyleData.scene, normal]; IF bBoxOfSelected=NIL THEN RETURN; -- nothing selected GGObjects.PushScene[gargoyleData.scene]; -- save for Undelete gargoyleData.refresh.startBoundBox^ _ DeleteAllSelected[gargoyleData]^; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; GGStatistics.StopInterval[$Delete, GGStatistics.GlobalTable[]]; }; -- end Delete Undelete: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; IF GGObjects.EmptySceneStack[gargoyleData.scene] OR NOT MessageWindow.Confirm["UNDELETE WILL LOSE MOST EDITS performed since last Delete"] THEN RETURN; GGSelect.DeselectAllAllClasses[gargoyleData.scene]; GGObjects.PopScene[gargoyleData.scene]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; }; SelectAll: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; GGStatistics.StartInterval[$SelectAll, GGStatistics.GlobalTable[]]; GGSelect.DeselectAll[gargoyleData.scene, normal]; GGSelect.SelectAll[gargoyleData.scene, normal]; GGEvent.SawTextFinish[NIL, gargoyleData]; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: TRUE]; GGStatistics.StopInterval[$SelectAll, GGStatistics.GlobalTable[]]; }; <> gScale: REAL _ 0.33; gAngle: REAL _ 33; MakeCurveProc: TYPE = PROC [lo, hi: Point, props: LIST OF REF ANY] RETURNS [seg: Segment]; GetPt: PROC[p0, dir: Point] RETURNS [pt: Point] = { pt _ GGVector.Add[GGVector.Scale[GGVector.VectorPlusAngle[dir,gAngle], gScale*GGVector.Magnitude[dir] ], p0]; }; SetStraight: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { MakeStraightAux: MakeCurveProc = { seg _ GGSegment.MakeLine[lo, hi, props]; }; gargoyleData: GargoyleData _ NARROW[clientData]; SetCurveAux[gargoyleData, MakeStraightAux, $Line]; }; -- end SetStraight SetArc: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { MakeArcAux: MakeCurveProc = { p1: Point; p1 _ GGVector.Add[GGVector.Scale[GGVector.Sub[hi,lo], 0.5], lo]; seg _ GGSegment.MakeArc[lo, p1, hi, props]; }; gargoyleData: GargoyleData _ NARROW[clientData]; SetCurveAux[gargoyleData, MakeArcAux, $Arc]; }; -- end SetArc SetSnowflake: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { OPEN GGVector; MakeSnowflakeAux: PROC [seg: Segment, traj: Traj] RETURNS [patternTraj: Traj] = { length: REAL; p1, p2, p3: Point; sideVec, dir, x: Vector; seg1, seg2, seg3, seg4: Segment; lo: Point _ seg.lo; hi: Point _ seg.hi; success: BOOL; length _ GGVector.Distance[lo,hi]; dir _ Sub[hi,lo]; x _ Scale[dir, 1.0/3.0]; p1 _ Add[lo, x]; p3 _ Add[lo, Scale[dir, 2.0/3.0]]; sideVec _ Scale[VectorPlusAngle[dir, 90], length*RealFns.SqRt[3]/6.0]; p2 _ Add[lo, GGVector.Add[Scale[dir, 0.5], sideVec]]; patternTraj _ traj; seg1 _ GGSegment.MakeLine[p0: lo, p1: p1, props: seg.props]; seg2 _ GGSegment.MakeLine[p0: p1, p1: p2, props: seg.props]; seg3 _ GGSegment.MakeLine[p0: p2, p1: p3, props: seg.props]; seg4 _ GGSegment.MakeLine[p0: p3, p1: hi, props: seg.props]; success _ GGTraj.AddSegment[patternTraj, hi, seg1, lo]; success _ GGTraj.AddSegment[patternTraj, hi, seg2, lo]; success _ GGTraj.AddSegment[patternTraj, hi, seg3, lo]; success _ GGTraj.AddSegment[patternTraj, hi, seg4, lo]; }; gargoyleData: GargoyleData _ NARROW[clientData]; SetPatternAux[gargoyleData, MakeSnowflakeAux]; }; SetConic: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { MakeConicAux: MakeCurveProc = { p1: Point; p1 _ GGVector.Add[GGVector.Scale[GGVector.Sub[hi,lo], 0.5], lo]; seg _ GGSegment.MakeConic[lo, p1, hi, 0.7, props]; }; gargoyleData: GargoyleData _ NARROW[clientData]; SetCurveAux[gargoyleData, MakeConicAux, $Conic]; }; -- end SetConic SetBezier: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { MakeBezierAux: MakeCurveProc = { length: REAL; dir: Point; p1, p2: Point; length _ GGVector.Distance[lo, hi]; dir _ GGVector.Sub[hi,lo]; p1 _ GetPt[lo, dir]; p2 _ GetPt[hi, [-dir.x, -dir.y] ]; seg _ GGSegment.MakeBezier[lo, p1, p2, hi, props]; }; gargoyleData: GargoyleData _ NARROW[clientData]; SetCurveAux[gargoyleData, MakeBezierAux, $Bezier]; }; -- end SetBezier SegsToSegsMatchCp: PROC [seg: Segment, traj: Traj, makeCurve: MakeCurveProc, type: ATOM] = { <> tSeg: Segment; success: BOOL; IF seg.class.type = type THEN -- if seg is already the right type, then we don't change it success _ GGTraj.AddSegment[traj, hi, GGSegment.CopySegment[seg], lo] ELSE IF type = $Arc AND seg.class.controlPointCount[seg] = 1 THEN { -- if old and new segment types have single control points, keep the control points the same tSeg _ GGSegment.MakeArc[seg.lo, seg.class.controlPointGet[seg, 0], seg.hi, seg.props]; tSeg.color _ seg.color; tSeg.strokeWidth _ seg.strokeWidth; success _ GGTraj.AddSegment[traj, hi, tSeg , lo] } ELSE IF type = $Conic AND seg.class.controlPointCount[seg] = 1 THEN { -- if old and new segment types have single control points, keep the control points the same tSeg _ GGSegment.MakeConic[seg.lo, seg.class.controlPointGet[seg, 0], seg.hi, .7, seg.props]; tSeg.color _ seg.color; tSeg.strokeWidth _ seg.strokeWidth; success _ GGTraj.AddSegment[traj, hi, tSeg, lo] } ELSE { -- make segment of new type with old endpoint info tSeg _ makeCurve[seg.lo, seg.hi, seg.props]; tSeg.color _ seg.color; tSeg.strokeWidth _ seg.strokeWidth; success _ GGTraj.AddSegment[traj, hi, tSeg, lo]; }; IF NOT success THEN ERROR; }; SegsAndCpsToSegs: PROC [seg: Segment, traj: Traj, makeCurve: MakeCurveProc, type: ATOM] = { <> success: BOOL; IF seg.class.type = type THEN -- if seg is already the right type, then we don't change it success _ GGTraj.AddSegment[traj, hi, GGSegment.CopySegment[seg], lo] ELSE { -- seg isn't the right type, so we convert all of its point/controlpoint spans tSeg: Segment; last, next: Point _ seg.lo; FOR i:INT IN [0..seg.class.controlPointCount[seg]) DO next _ seg.class.controlPointGet[seg, i]; tSeg _ makeCurve[last, next, seg.props]; tSeg.color _ seg.color; tSeg.strokeWidth _ seg.strokeWidth; success _ GGTraj.AddSegment[traj, hi, tSeg, lo]; IF NOT success THEN ERROR; last _ next; ENDLOOP; tSeg _ makeCurve[last, seg.hi, seg.props]; tSeg.color _ seg.color; tSeg.strokeWidth _ seg.strokeWidth; success _ GGTraj.AddSegment[traj, hi, tSeg, lo]; IF NOT success THEN ERROR; }; }; SetCurveAux: PROC [gargoyleData: GargoyleData, makeCurve: MakeCurveProc, type: ATOM] = { <> <> RunOfSegs: GGSelect.RunProc = { <<[run: GGModelTypes.Sequence] RETURNS [traj: GGModelTypes.Traj]>> segGen: GGSequence.SegmentGenerator _ GGSequence.SegmentsInSequence[run]; initialSeg: Segment _ GGSequence.NextSegment[segGen]; IF initialSeg = NIL THEN RETURN[NIL]; -- the run is a single vertex traj _ GGTraj.CreateTraj[initialSeg.lo]; FOR seg: Segment _ initialSeg, GGSequence.NextSegment[segGen] UNTIL seg = NIL DO SELECT seg.class.type FROM -- choose from old segment type $Line, $Arc, $Conic, $Bezier => SegsToSegsMatchCp[seg, traj, makeCurve, type]; -- modify traj $CubicSpline => { IF type=$Line OR (run.traj.segCount=1 AND run.traj.role#open) THEN SegsAndCpsToSegs[seg, traj, makeCurve, type] -- Splines are changed to multiple lines...(or multiple segs if spline was cyclic) ELSE SegsToSegsMatchCp[seg, traj, makeCurve, type]; -- ...but single everything else }; ENDCASE => ERROR; ENDLOOP; }; bBox: BoundBox; bBox _ GGSelect.ForEachOutlineRun[gargoyleData.scene, gargoyleData.caret, normal, RunOfSegs, TRUE, TRUE]; gargoyleData.refresh.startBoundBox^ _ bBox^; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; }; PatternProc: TYPE = PROC [seg: Segment, traj: Traj] RETURNS [patternTraj: Traj]; SetPatternAux: PROC [gargoyleData: GargoyleData, pattern: PatternProc] = { <> <> RunOfSegs: GGSelect.RunProc = { <<[run: GGModelTypes.Sequence] RETURNS [traj: GGModelTypes.Traj]>> segGen: GGSequence.SegmentGenerator _ GGSequence.SegmentsInSequence[run]; initialSeg: Segment _ GGSequence.NextSegment[segGen]; IF initialSeg = NIL THEN RETURN[NIL]; -- the run is a single vertex traj _ GGTraj.CreateTraj[initialSeg.lo]; FOR seg: Segment _ initialSeg, GGSequence.NextSegment[segGen] UNTIL seg = NIL DO SELECT seg.class.type FROM -- choose from old segment type $Line => traj _ pattern[seg, traj]; ENDCASE => NULL; ENDLOOP; }; bBox: BoundBox; bBox _ GGSelect.ForEachOutlineRun[gargoyleData.scene, gargoyleData.caret, normal, RunOfSegs, TRUE, TRUE]; gargoyleData.refresh.startBoundBox^ _ bBox^; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; }; SetNaturalSpline: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; SetSpline[splineType: naturalAL, gargoyleData: gargoyleData]; }; SetBSpline: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; SetSpline[splineType: bspline, gargoyleData: gargoyleData]; }; SetSpline: PROC [splineType: CubicSplines.SplineType, gargoyleData: GargoyleData] = { RunToSpline: GGSelect.RunProc = { <<[run: GGModelTypes.Sequence] RETURNS [traj: GGModelTypes.Traj]>> X: NAT = CubicSplines.X; Y: NAT = CubicSplines.Y; tSeg: Segment; controlPoint: Point; cyclic: BOOL _ run.traj.role#open AND GGSequence.IsComplete[run]; cps: CubicSplines.KnotSequence _ NEW[CubicSplines.KnotSequenceRec[IF cyclic THEN run.jointCount+run.controlPointCount+1 ELSE run.jointCount+run.controlPointCount]]; segGen: GGSequence.SegmentGenerator _ GGSequence.OrderedSegmentsInSequence[run]; initialSeg: Segment _ GGSequence.NextSegment[segGen]; success: BOOL; cpCount: NAT _ 0; IF initialSeg = NIL THEN RETURN[NIL]; IF cyclic AND splineType = naturalAL THEN splineType _ cyclicAL; traj _ GGTraj.CreateTraj[initialSeg.lo]; cps[cpCount] _ [initialSeg.lo.x, initialSeg.lo.y]; cpCount _ cpCount + 1; FOR seg: Segment _ initialSeg, GGSequence.NextSegment[segGen] UNTIL seg = NIL DO FOR i:INT IN [0..seg.class.controlPointCount[seg]) DO controlPoint _ seg.class.controlPointGet[seg, i]; cps[cpCount] _ [controlPoint.x, controlPoint.y]; cpCount _ cpCount + 1; ENDLOOP; cps[cpCount] _ [seg.hi.x, seg.hi.y]; cpCount _ cpCount + 1; ENDLOOP; IF cyclic THEN cps[cps.length-1] _ cps[0]; -- cumulative error sometimes causes small differences. DJK. tSeg _ GGSegment.MakeCubicSpline[cps, splineType, NIL]; tSeg.color _ initialSeg.color; tSeg.strokeWidth _ initialSeg.strokeWidth; success _ GGTraj.AddSegment[traj, hi, tSeg, lo]; IF NOT success THEN ERROR; }; gargoyleData.refresh.startBoundBox^ _ GGSelect.ForEachOutlineRun[gargoyleData.scene, gargoyleData.caret, normal, RunToSpline, TRUE, TRUE]^; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE] }; <<>> SelectMatchingCurve: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; name: Rope.ROPE _ IF event.rest = NIL THEN ViewerTools.GetSelectionContents[] ELSE NARROW[event.rest.first]; trajGen: TrajGenerator _ GGObjects.TrajsInScene[gargoyleData.scene]; GGSelect.DeselectAll[gargoyleData.scene, normal]; FOR traj: Traj _ GGObjects.NextTraj[trajGen], GGObjects.NextTraj[trajGen] UNTIL traj = NIL DO segGen: SegmentGenerator _ GGSequence.SegmentsInTraj[traj]; FOR segAndIndex: SegAndIndex _ GGSequence.NextSegmentAndIndex[segGen], GGSequence.NextSegmentAndIndex[segGen] UNTIL segAndIndex.seg = NIL DO IF Rope.Equal[segAndIndex.seg.class.describe[segAndIndex.seg, TRUE, TRUE, TRUE, NIL], name, FALSE] THEN { seq: Sequence _ GGSequence.CreateFromSegment[traj, segAndIndex.index]; GGSelect.SelectSequence[seq, gargoyleData.scene, normal]; }; ENDLOOP; ENDLOOP; GGError.PutFHerald[gargoyleData.feedback, oneLiner, "Curves of type %g selected", [rope[name]] ]; GGWindow.RestoreScreenAndInvariants[paintAction: $SelectionChanged, gargoyleData: gargoyleData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; <> Close: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; chair: REF ANY; traj: Traj; firstPoint, lastPoint: Point; seg: Segment; success: BOOL; chair _ GGCaret.GetChair[gargoyleData.caret]; BEGIN IF chair = NIL THEN GOTO NoCaretTraj; WITH chair SELECT FROM oD: OutlineDescriptor => { [success, ----, traj] _ GGOutline.UnpackSimpleDescriptorOld[oD]; IF NOT success THEN ERROR; }; sD: SliceDescriptor => { IF sD.slice.class.type # $Outline THEN GOTO NoCaretTraj; [success, ----, traj] _ GGOutline.UnpackSimpleDescriptor[sD]; IF NOT success THEN GOTO NoCaretTraj; }; ENDCASE => ERROR; IF traj.role = fence OR traj.role = hole THEN GOTO AlreadyClosed; GGError.AppendHerald[gargoyleData.feedback, "The caret trajectory will be closed.", oneLiner]; firstPoint _ GGTraj.FetchJointPos[traj, 0]; lastPoint _ GGTraj.LastJointPos[traj]; IF firstPoint # lastPoint THEN { seg _ GGSegment.MakeLine[lastPoint, firstPoint, NIL]; GGTraj.CloseWithSegment[traj, seg, lo]; GGSelect.ReselectTraj[traj, hi, gargoyleData.scene, TRUE]; } ELSE { GGOutline.SaveSelectionsInOutline[traj.parent, gargoyleData.scene]; GGSelect.DeselectEntityAllClasses[traj.parent, gargoyleData.scene]; GGTraj.CloseByDistorting[traj, hi]; GGOutline.RemakeSelectionsFromOutline[traj.parent, gargoyleData.scene]; }; GGOutline.OutlineOfTraj[traj].class.setFillColor[GGOutline.OutlineOfTraj[traj], GGObjects.fillColor]; GGSelect.SelectTraj[traj, gargoyleData.scene, normal]; GGCaret.SitOn[gargoyleData.caret, NIL]; GGCaret.NoAttractor[caret: gargoyleData.caret]; gargoyleData.refresh.startBoundBox^ _ traj.boundBox^; GGWindow.RestoreScreenAndInvariants[paintAction: $ObjectChangedBoundBoxProvided, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: FALSE]; <> EXITS NoCaretTraj => { GGError.AppendHerald[gargoyleData.feedback, "There is no caret trajectory to close.", oneLiner]; GGError.Blink[gargoyleData.feedback]; }; AlreadyClosed => { GGError.AppendHerald[gargoyleData.feedback, "That trajectory is already closed.", oneLiner]; GGError.Blink[gargoyleData.feedback]; }; END; }; -- end Close <> <> <> <> <> <> <<};>> <<>> <> <> <> <> <> <> <<};>> <<>> <> Refresh: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; doNotClear: BOOL _ event#NIL AND event.rest#NIL AND event.rest.first=$DoNotClearFeedback; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, gargoyleData: gargoyleData, remake: triggerBag, backgndOK: FALSE, edited: FALSE, okToClearFeedback: NOT doNotClear]; }; DisableRefresh: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; gargoyleData.refresh.suppressRefresh _ TRUE; }; EnableRefresh: PUBLIC PROC [event: LIST OF REF ANY, clientData: REF ANY] = { gargoyleData: GargoyleData _ NARROW[clientData]; gargoyleData.refresh.suppressRefresh _ FALSE; }; <> <<>> <> CloseToTranslation: PROC [s, t: ImagerTransformation.Transformation, range: REAL] RETURNS [BOOL] ~ { OPEN ImagerTransformation; WithinQuarterPixel: PROC [p, q: VEC] RETURNS [BOOL] ~ { RETURN [ABS[p.x-q.x] <= 0.25 AND ABS[p.y-q.y] <= 0.25] }; p10: VEC _ TransformVec[s, InverseTransformVec[t, [range, 0]]]; p01: VEC _ TransformVec[s, InverseTransformVec[t, [0, range]]]; RETURN [ WithinQuarterPixel[p10, [range, 0]] AND WithinQuarterPixel[p01, [0, range]] ] }; defaultPrefix: Rope.ROPE; defaultFamily: Rope.ROPE; defaultFace: Rope.ROPE; defaultTransform: ImagerTransformation.Transformation; defaultPreferredSize: REAL; Init: PROC [] = { defaultPrefix _ "xerox/pressfonts/"; defaultFamily _ "Helvetica"; defaultFace _ ""; defaultTransform _ ImagerTransformation.Scale[s: 10.0]; defaultPreferredSize _ 1.0; GGStatistics.AddInterval[GGStatistics.CreateInterval[$SelectAll, NIL], GGStatistics.GlobalTable[]]; GGStatistics.AddInterval[GGStatistics.CreateInterval[$Delete, NIL], GGStatistics.GlobalTable[]]; }; Init[]; END.