<> <> <> <> <> <> <<>> DIRECTORY Angles2d, AtomButtons, AtomButtonsTypes, Basics, BiScrollers, ColorTool, EmbeddedButtons, Feedback, FeedbackOps, FileNames, FS, Geom2D, GGBasicTypes, GGControlPanelTypes, GGCoreOps, GGCoreTypes, GGDragTypes, GGEmbedTypes, GGFont, GGHistory, GGHistoryTypes, GGInterfaceTypes, GGModelTypes, GGProps, GGRefresh, GGSceneType, GGSessionLog, GGState, GGStateExtras, GGStateTypes, GGUIUtility, GGUserInput, GGUserProfile, GGViewerOps, GGWindow, Icons, Imager, ImagerTransformation, InputFocus, IO, PBasics, Real, RealFns, Rope, TiogaMenuOps, TIPUser, Vector2, ViewerClasses, ViewerOps, ViewerTools; GGStateImpl: CEDAR PROGRAM IMPORTS Angles2d, AtomButtons, BiScrollers, ColorTool, EmbeddedButtons, Feedback, FeedbackOps, FileNames, FS, Geom2D, GGCoreOps, GGHistory, GGProps, GGRefresh, GGSessionLog, GGUIUtility, GGUserInput, GGUserProfile, GGViewerOps, GGWindow, ImagerTransformation, InputFocus, IO, PBasics, RealFns, Rope, TiogaMenuOps, TIPUser, Vector2, ViewerOps, ViewerTools EXPORTS GGState, GGStateExtras, GGHistoryTypes, GGInterfaceTypes, GGModelTypes = BEGIN Change: PUBLIC TYPE = GGHistory.Change; -- exported to GGHistoryTypes ControlsObj: PUBLIC TYPE = GGControlPanelTypes.ControlsObj; -- exported to GGInterfaceTypes EmbedDataObj: PUBLIC TYPE = GGEmbedTypes.EmbedDataObj; -- exported to GGInterfaceTypes StateDataObj: PUBLIC TYPE = GGStateTypes.StateDataObj; -- exported to GGInterfaceTypes DragDataObj: PUBLIC TYPE = GGDragTypes.DragDataObj; -- exported to GGInterfaceTypes Camera: TYPE = GGModelTypes.Camera; Caret: TYPE = GGInterfaceTypes.Caret; DefaultData: TYPE = GGModelTypes.DefaultData; DisplayStyle: TYPE = GGModelTypes.DisplayStyle; ExtendMode: TYPE = GGModelTypes.ExtendMode; FeatureCycler: TYPE = GGInterfaceTypes.FeatureCycler; FontData: TYPE = GGFont.FontData; GGData: TYPE = GGInterfaceTypes.GGData; GravityType: TYPE = GGInterfaceTypes.GravityType; HistoryEvent: TYPE = GGHistoryTypes.HistoryEvent; ROPE: TYPE = Rope.ROPE; RopeListt: TYPE = GGCoreTypes.RopeListt; ScalarButton: TYPE = AtomButtons.ScalarButton; SceneObj: PUBLIC TYPE = GGSceneType.SceneObj; -- export of opaque type SortedButtonClient: TYPE = AtomButtonsTypes.SortedButtonClient; SortedButtonHandle: TYPE = AtomButtonsTypes.SortedButtonHandle; SelectMode: TYPE = GGModelTypes.SelectMode; SequenceOfReal: TYPE = GGCoreTypes.SequenceOfReal; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; StrokeJoint: TYPE = Imager.StrokeJoint; StrokeEnd: TYPE = Imager.StrokeEnd; Transformation: TYPE = ImagerTransformation.Transformation; Vector: TYPE = GGBasicTypes.Vector; Viewer: TYPE = ViewerClasses.Viewer; ViewportProc: TYPE = GGStateExtras.ViewportProc; reallyBigReal: REAL = 1.0e37; RegisterViewportProc: PUBLIC PROC [ggData: GGData, proc: ViewportProc, clientData: REF _ NIL] = { ggData.embed.viewportProc _ proc; ggData.embed.viewportData _ clientData; }; <<>> DefaultViewport: PUBLIC ViewportProc = { <> <> IF ggData.controls.biScroller = NIL THEN RETURN[[0,0,100,100]]; rect _ BiScrollers.ViewportBox[ggData.controls.biScroller]; }; <<>> NotNewVersion: PUBLIC PROC [ggData: GGData, op: ATOM] = { <> IF ggData.controls = NIL OR ggData.controls.panel = NIL OR ggData.controls.topper = NIL THEN RETURN; ggData.controls.panel.newVersion _ FALSE; -- guard the destroy button. KAP. June 1, 1988 ggData.controls.topper.newVersion _ FALSE; ggData.controls.topper.icon _ SELECT op FROM $clear => GGWindow.GetIcons[].noNameIcon, $clean => GGWindow.GetIcons[].cleanIcon, ENDCASE => ERROR; ViewerOps.PaintViewer[ggData.controls.topper, caption]; IF ggData.controls.topper#ggData.controls.panel THEN ViewerOps.PaintViewer[ggData.controls.panel, caption]; }; ChangeIcon: PUBLIC PROC [ggData: GGData, op: ATOM] = { <> IF ggData.controls = NIL OR ggData.controls.topper = NIL THEN RETURN; ggData.controls.topper.icon _ SELECT op FROM $clear => GGWindow.GetIcons[].noNameIcon, $clean => GGWindow.GetIcons[].cleanIcon, ENDCASE => ERROR; ViewerOps.PaintViewer[ggData.controls.topper, caption]; }; <<>> ColorToolIsBound: PUBLIC PROC [ggData: GGData] RETURNS [BOOL _ FALSE] ~ { IF PBasics.IsBound[LOOPHOLE[ColorTool.GetColor]] THEN RETURN[TRUE]; Feedback.Append[ggData.router, oneLiner, $Complaint, "ColorTool operation failed: please install ColorTool and retry"]; }; GetViewport: PUBLIC PROC [ggData: GGData] RETURNS [rect: Imager.Rectangle] = { <> IF ggData.embed.viewportProc = NIL THEN RETURN [DefaultViewport[ggData]] ELSE RETURN [ggData.embed.viewportProc[ggData, ggData.embed.viewportData]]; }; GetGGInputFocus: PUBLIC PROC RETURNS [focusData: GGData _ NIL] = { theirViewer: Viewer; inputFocus: InputFocus.Focus _ InputFocus.GetInputFocus[]; IF inputFocus = NIL OR inputFocus.owner = NIL THEN RETURN; theirViewer _ inputFocus.owner; IF theirViewer.class.flavor=$ActionArea THEN focusData _ NARROW[BiScrollers.ClientDataOf[NARROW[theirViewer.data, BiScrollers.BiScroller]], GGData]; }; GetAnchor: PUBLIC PROC [ggData: GGData] RETURNS [Caret] = { RETURN[ggData.anchor]; }; identity: Transformation = ImagerTransformation.Scale[1.0]; GetBiScrollersTransform: PUBLIC PROC [ggData: GGData] RETURNS [clientToViewer: Transformation] = { IF ggData.controls.biScroller = NIL THEN RETURN[ggData.controlState.clientToViewer] ELSE clientToViewer _ BiScrollers.GetStyle[].GetTransforms[ggData.controls.biScroller].clientToViewer; }; SGN: PROC [r: REAL] RETURNS [sgn: [-1 .. 1]] = { sgn _ SELECT r FROM <0 => -1, =0 => 0, >0 => 1, ENDCASE => ERROR}; ConstantVector: PROC [ggData: GGData] RETURNS [cv: Vector2.VEC] = { <> <> cv _ [100, 100]; -- for now }; ZeroProtect: PROC [r: REAL] RETURNS [r0: REAL] = {r0 _ IF r = 0.0 THEN 1.0 ELSE r}; mayStretch: BOOL = TRUE; BiScrollersScale: PUBLIC PROC [ggData: GGData, op: GGState.ScaleOp] = { IF ggData.controls.biScroller = NIL THEN { cv: Vector2.VEC ~ ConstantVector[ggData]; old: Transform ~ GetBiScrollersTransforms[ggData].clientToViewer; new: Transform _ old.PostTranslate[cv.Neg[]]; WITH op SELECT FROM reset => { v: Geom2D.Trans _ Geom2D.ToTrans[identity]; vd: REAL _ v.dxdx*v.dydy - v.dydx*v.dxdy; od: REAL _ old.a*old.e - old.d*old.b; new _ new.PostScale[ RealFns.SqRt[ABS[vd/ZeroProtect[od]]]*SGN[vd]*SGN[od] ]; }; byArg => new _ new.PostScale[arg]; diff => IF mayStretch THEN new _ new.PostScale2[[x, y]] ELSE new _ new.PostScale[x]; ENDCASE => ERROR; new _ new.PostTranslate[cv]; ChangeTransform[ggData, new, ignore]; } ELSE { WITH op SELECT FROM reset => BiScrollers.Scale[bs: ggData.controls.biScroller, op: [reset[]], paint: FALSE]; byArg => BiScrollers.Scale[bs: ggData.controls.biScroller, op: [byArg[arg]], paint: FALSE]; diff => BiScrollers.Scale[bs: ggData.controls.biScroller, op: [diff[x, y]], paint: FALSE]; ENDCASE => ERROR; }; }; BiScrollersTransform: PUBLIC PROC [ggData: GGData, t: Transformation] = { old: Transform ~ GetBiScrollersTransforms[ggData].clientToViewer; new: Transform ~ old.Concat[t]; IF ggData.controls.biScroller = NIL THEN { ChangeTransform[ggData, new, ignore]; } ELSE { ggData.controls.biScroller.style.ChangeTransform[ggData.controls.biScroller, new, ignore, FALSE]; }; }; BiScrollersShift: PUBLIC PROC [ggData: GGData, dx, dy: REAL] = { IF ggData.controls.biScroller = NIL THEN { old: Transform ~ GetBiScrollersTransforms[ggData].clientToViewer; new: Transform ~ old.PostTranslate[[dx, dy]]; ChangeTransform[ggData, new, ignore]; } ELSE BiScrollers.Shift[ggData.controls.biScroller, dx, dy, FALSE]; }; AgeOp: TYPE = {remember, ignore}; Transform: TYPE = ImagerTransformation.Transformation; ChangeTransform: PROC [ggData: GGData, new: Transform, ageOp: AgeOp] = { <> inv: Transform; <> IF new.a*new.e - new.b*new.d = 0 THEN RETURN; -- change is degenerate. Don't do it inv _ new.Invert[]; SELECT ageOp FROM remember => { ggData.controlState.viewerToClientPrevious _ ggData.controlState.viewerToClient; ggData.controlState.clientToViewerPrevious _ ggData.controlState.clientToViewer; }; ignore => NULL; ENDCASE => ERROR; ggData.controlState.viewerToClient _ inv; ggData.controlState.clientToViewer _ new; }; GetBiScrollersScale: PUBLIC PROC [ggData: GGData] RETURNS [s: REAL] = { <> clientToViewer: Transformation _ GetBiScrollersTransform[ggData]; s _ ImagerTransformation.SingularValues[clientToViewer].x; }; GetBiScrollersTransforms: PUBLIC PROC [ggData: GGData] RETURNS [clientToViewer, viewerToClient: Transformation] = { IF ggData.controls.biScroller = NIL THEN RETURN[ggData.controlState.clientToViewer, ggData.controlState.viewerToClient] ELSE [clientToViewer, viewerToClient] _ BiScrollers.GetStyle[].GetTransforms[ggData.controls.biScroller]; }; SetBiScrollersTransform: PUBLIC PROC [ggData: GGData, clientToViewer: Transformation] = { bs: BiScrollers.BiScroller = ggData.controls.biScroller; IF ggData.controls.biScroller = NIL THEN { ggData.controlState.clientToViewer _ clientToViewer; ggData.controlState.viewerToClient _ ImagerTransformation.Invert[clientToViewer]; RETURN; }; bs.style.ChangeTransform[bs: ggData.controls.biScroller, new: clientToViewer, ageOp: remember, paint: FALSE]; GGWindow.RestoreScreenAndInvariants[$ViewersPaintEntireScene, ggData, none, FALSE, TRUE]; -- explicit call to avoid clearing to white }; <<>> <> <<>> FilterLists: TYPE = REF FilterListsObj; FilterListsObj: TYPE = GGState.FilterListsObj; GetFilterLists: PUBLIC PROC [ggData: GGData] RETURNS [filterLists: FilterLists] = { AddSlopeFilter: PROC [state: BOOL, name: Rope.ROPE, value: REF ANY, clientData: REF ANY] RETURNS [done: BOOL _ FALSE] = { IF state THEN { real: REAL _ NARROW[value, REF REAL]^; filterLists.onSlopes _ CONS[Angles2d.Normalize[real], filterLists.onSlopes]; }; }; AddRadiusFilter: PROC [state: BOOL, name: Rope.ROPE, value: REF ANY, clientData: REF ANY] RETURNS [done: BOOL _ FALSE] = { IF state THEN { real: REAL _ NARROW[value, REF REAL]^; filterLists.onRadii _ CONS[real, filterLists.onRadii]; }; }; AddAngleFilter: PROC [state: BOOL, name: Rope.ROPE, value: REF ANY, clientData: REF ANY] RETURNS [done: BOOL _ FALSE] = { IF state THEN { real: REAL _ NARROW[value, REF REAL]^; filterLists.onAngles _ CONS[real, filterLists.onAngles]; }; }; AddDistanceFilter: PROC [state: BOOL, name: Rope.ROPE, value: REF ANY, clientData: REF ANY] RETURNS [done: BOOL _ FALSE] = { IF state THEN { real: REAL _ NARROW[value, REF REAL]^; filterLists.onDistances _ CONS[real, filterLists.onDistances]; }; }; filterLists _ NEW[FilterListsObj _ [NIL, NIL, NIL, NIL]]; IF ggData.controls.slopeHandle#NIL THEN AtomButtons.ReadSortedButtons[ggData.controls.slopeHandle, AddSlopeFilter]; IF ggData.controls.radiusHandle#NIL THEN AtomButtons.ReadSortedButtons[ggData.controls.radiusHandle, AddRadiusFilter]; IF ggData.controls.distanceHandle#NIL THEN AtomButtons.ReadSortedButtons[ggData.controls.distanceHandle, AddDistanceFilter]; IF ggData.controls.angleHandle#NIL THEN AtomButtons.ReadSortedButtons[ggData.controls.angleHandle, AddAngleFilter]; filterLists.scaleUnit _ ggData.hitTest.scaleUnit; }; AlignmentType: TYPE = GGState.AlignmentType; SetAllAlignmentStates: PUBLIC PROC [ggData: GGData, type: AlignmentType, state: BOOL] = { SELECT type FROM slope => IF ggData.controls.slopeHandle # NIL THEN AtomButtons.SetAllScalarStates[ggData, ggData.controls.slopeHandle, state]; angle => IF ggData.controls.angleHandle # NIL THEN AtomButtons.SetAllScalarStates[ggData, ggData.controls.angleHandle, state]; radius => IF ggData.controls.radiusHandle # NIL THEN AtomButtons.SetAllScalarStates[ggData, ggData.controls.radiusHandle, state]; lineDistance => IF ggData.controls.distanceHandle # NIL THEN AtomButtons.SetAllScalarStates[ggData, ggData.controls.distanceHandle, state]; ENDCASE; }; DeleteSelectedAlignments: PUBLIC PROC [ggData: GGData, type: AlignmentType] = { DeleteSelected: PROC [state: BOOL, name: Rope.ROPE, value: REF ANY, clientData: REF ANY] RETURNS [found: BOOL, done: BOOL _ FALSE] = { found _ state; }; handle: SortedButtonHandle _ GetSortedButtonHandle[ggData, type]; AtomButtons.DeleteSortedButtons[ggData, handle, DeleteSelected]; }; GetSortedButtonHandle: PROC [ggData: GGData, type: AlignmentType] RETURNS [handle: SortedButtonHandle] = { handle _ SELECT type FROM slope => ggData.controls.slopeHandle, angle => ggData.controls.angleHandle, radius => ggData.controls.radiusHandle, lineDistance => ggData.controls.distanceHandle, ENDCASE => NIL; }; ToggleAlignment: PUBLIC PROC [ggData: GGData, alignVal: REAL, type: AlignmentType] RETURNS [menuValue: REAL _ 777.0, changedToOn: BOOL _ FALSE] = { FindAndToggleValue: PROC [state: BOOL, name: Rope.ROPE, value: REF ANY, clientData: REF ANY] RETURNS [newState: BOOL, newName: Rope.ROPE _ NIL, newValue: REF ANY, done: BOOL _ FALSE] = { real: REAL _ NARROW[value, REF REAL]^; epsilon: REAL = 0.001; IF ABS[real-alignVal] < epsilon THEN { newState _ NOT state; changedToOn _ newState; menuValue _ real; done _ TRUE; } ELSE newState _ state; newValue _ value; }; handle: SortedButtonHandle _ GetSortedButtonHandle[ggData, type]; AtomButtons.WriteSortedButtons[handle, FindAndToggleValue]; }; GetSlopeAlignments: PUBLIC PROC [ggData: GGData] RETURNS [values: LIST OF REAL, on: LIST OF BOOL] = { <> AddSlope: PROC [state: BOOL, name: Rope.ROPE, value: REF ANY, clientData: REF ANY] RETURNS [done: BOOL _ FALSE] = { real: REAL _ NARROW[value, REF REAL]^; [values, valuePtr] _ GGCoreOps.AddReal[real, values, valuePtr]; [on, boolPtr] _ GGCoreOps.AddBool[state, on, boolPtr]; }; valuePtr: LIST OF REAL; boolPtr: LIST OF BOOL; [values, valuePtr] _ GGCoreOps.StartRealList[]; [on, boolPtr] _ GGCoreOps.StartBoolList[]; IF ggData.controls.slopeHandle # NIL THEN AtomButtons.ReadSortedButtons[ggData.controls.slopeHandle, AddSlope]; }; GetSlopeValue: PUBLIC PROC [ggData: GGData] RETURNS [degrees: REAL, success: BOOL _ TRUE] = { IF ggData.controls.slopeView = NIL THEN RETURN[0.0, FALSE]; degrees _ GGViewerOps.GetReal[ggData.controls.slopeView, Real.LargestNumber]; IF degrees = Real.LargestNumber THEN { Feedback.Append[ggData.router, oneLiner, $Complaint, "Attempt to use illegal slope value"]; degrees _ 0.0; success _ FALSE; RETURN; }; degrees _ Angles2d.Normalize[degrees]; <> IF degrees<0.0 THEN degrees _ degrees+180.0; IF degrees=360.0 THEN degrees _ 0.0; <> IF RealFns.AlmostEqual[degrees, ggData.measure.slopeViewValue, -10] THEN degrees _ ggData.measure.slopeViewValue ELSE ggData.measure.slopeViewValue _ degrees; }; SetSlopeValue: PUBLIC PROC [ggData: GGData, degrees: REAL] = { ggData.measure.slopeViewValue _ degrees; IF ggData.controls.slopeView # NIL THEN GGViewerOps.SetReal[ggData.controls.slopeView, degrees, "%6.5f"]; }; SelectSlope: PUBLIC PROC [ggData: GGData] RETURNS [success: BOOL _ TRUE] = { IF ggData.controls.slopeView=NIL THEN success _ FALSE ELSE ViewerTools.SetSelection[ggData.controls.slopeView]; }; AddSlope: PUBLIC PROC [ggData: GGData, degrees: REAL, on: BOOL _ TRUE] RETURNS [alreadyThere: BOOL] = { oldFoundButton: AtomButtons.SortedButtonClient; IF ggData.controls.slopeHandle = NIL THEN RETURN[TRUE]; oldFoundButton _ AtomButtons.AddScalarSorted[ggData, ggData.controls.slopeHandle, [NIL, degrees, LIST[LIST[$ToggleSlope, NEW[REAL _ degrees]]], on], decr]; alreadyThere _ oldFoundButton # NIL; }; ButtonsFromValues: PROC [atom: ATOM, names: LIST OF Rope.ROPE _ NIL, values: LIST OF REAL, on: LIST OF BOOL _ NIL] RETURNS [buttonList: LIST OF ScalarButton] = { ptr: LIST OF ScalarButton; name: Rope.ROPE; active: BOOL _ FALSE; [buttonList, ptr] _ GGCoreOps.StartScalarButtonList[]; FOR values _ values, values.rest UNTIL values = NIL DO name _ IF names = NIL THEN ScalarToRope[values.first] ELSE names.first; <> active _ IF on = NIL THEN FALSE ELSE on.first; [buttonList, ptr] _ GGCoreOps.AddScalarButton[[name, values.first, LIST[LIST[atom, NEW[REAL _ values.first]]], active], buttonList, ptr]; IF names # NIL THEN names _ names.rest; IF on # NIL THEN on _ on.rest; ENDLOOP; }; AddSlopeList: PUBLIC PROC [ggData: GGData, degrees: LIST OF REAL, on: LIST OF BOOL _ NIL] = { buttonList, oldList: LIST OF ScalarButton; oldValues: LIST OF REAL; oldOn: LIST OF BOOL; IF ggData.controls.slopeHandle = NIL THEN RETURN; buttonList _ ButtonsFromValues[$ToggleSlope, NIL, degrees, on]; [oldValues, oldOn] _ GetSlopeAlignments[ggData]; oldList _ ButtonsFromValues[$ToggleSlope, NIL, oldValues, oldOn]; buttonList _ MergeScalarButtonLists[buttonList, oldList, FALSE]; AtomButtons.BuildScalarButtons[ggData.controls.slopeHandle, ggData, GGUserInput.EventNotify, NIL, buttonList]; }; NewSlopeList: PUBLIC PROC [ggData: GGData, degrees: LIST OF REAL, on: LIST OF BOOL _ NIL] = { buttonList: LIST OF ScalarButton; IF ggData.controls.slopeHandle = NIL THEN RETURN; buttonList _ ButtonsFromValues[$ToggleSlope, NIL, degrees, on]; AtomButtons.BuildScalarButtons[ggData.controls.slopeHandle, ggData, GGUserInput.EventNotify, NIL, buttonList]; }; MergeScalarButtonLists: PROC [list1, list2: LIST OF ScalarButton, ascending: BOOL _ TRUE] RETURNS [mergedList: LIST OF ScalarButton _ NIL] = { <> ptr: LIST OF ScalarButton _ NIL; done: BOOL _ FALSE; list1Is: Basics.Comparison; DO [list1Is, done] _ CompareValues[list1, list2, ascending]; IF done THEN RETURN; SELECT list1Is FROM less => [list1, mergedList, ptr] _ SpliceToList[list1, mergedList, ptr]; greater => [list2, mergedList, ptr] _ SpliceToList[list2, mergedList, ptr]; equal => { state: BOOL _ list1.first.on OR list2.first.on; IF list1.first.name # NIL THEN { [list1, mergedList, ptr] _ SpliceToList[list1, mergedList, ptr]; list2 _ list2.rest; } ELSE { [list2, mergedList, ptr] _ SpliceToList[list2, mergedList, ptr]; list1 _ list1.rest; }; ptr.first.on _ state; }; ENDCASE => ERROR; IF ptr.first.name = NIL THEN ptr.first.name _ ScalarToRope[ptr.first.value]; ENDLOOP; }; CompareValues: PROC [list1, list2: LIST OF ScalarButton, ascending: BOOL _ TRUE] RETURNS [list1Is: Basics.Comparison, done: BOOL _ FALSE] = { epsilon: REAL = 0.001; IF list1 = NIL THEN { IF list2 = NIL THEN {done _ TRUE; list1Is _ less; RETURN} ELSE {list1Is _ greater; RETURN} }; IF list2 = NIL THEN {list1Is _ less; RETURN}; IF ascending THEN { IF list1.first.value + epsilon < list2.first.value THEN list1Is _ less ELSE IF list1.first.value - epsilon > list2.first.value THEN list1Is _ greater ELSE list1Is _ equal; } ELSE { IF list1.first.value + epsilon < list2.first.value THEN list1Is _ greater ELSE IF list1.first.value - epsilon > list2.first.value THEN list1Is _ less ELSE list1Is _ equal; }; }; SpliceToList: PROC [list, mergedList, ptr: LIST OF ScalarButton] RETURNS [newList, newMergedList, newPtr: LIST OF ScalarButton] = { <> newList _ list.rest; -- walk over the bridge list.rest _ NIL; -- burn the bridge IF mergedList = NIL THEN {newMergedList _ list; newPtr _ list; RETURN}; newMergedList _ mergedList; ptr.rest _ list; -- put the new element on the end newPtr _ list; -- update the tail pointer }; GetAngleAlignments: PUBLIC PROC [ggData: GGData] RETURNS [values: LIST OF REAL, on: LIST OF BOOL] = { AddAngle: PROC [state: BOOL, name: Rope.ROPE, value: REF ANY, clientData: REF ANY] RETURNS [done: BOOL _ FALSE] = { real: REAL _ NARROW[value, REF REAL]^; [values, valuePtr] _ GGCoreOps.AddReal[real, values, valuePtr]; [on, boolPtr] _ GGCoreOps.AddBool[state, on, boolPtr]; }; valuePtr: LIST OF REAL; boolPtr: LIST OF BOOL; [values, valuePtr] _ GGCoreOps.StartRealList[]; [on, boolPtr] _ GGCoreOps.StartBoolList[]; IF ggData.controls.angleHandle # NIL THEN AtomButtons.ReadSortedButtons[ggData.controls.angleHandle, AddAngle]; }; GetAngleValue: PUBLIC PROC [ggData: GGData] RETURNS [degrees: REAL, success: BOOL _ TRUE] = { IF ggData.controls.angleView = NIL THEN RETURN[0.0, FALSE]; degrees _ GGViewerOps.GetReal[ggData.controls.angleView, Real.LargestNumber]; IF degrees>reallyBigReal THEN { Feedback.Append[ggData.router, oneLiner, $Complaint, "Attempt to use illegal angle value"]; degrees _ 0.0; success _ FALSE; RETURN; }; degrees _ Angles2d.Normalize[degrees]; IF degrees=360.0 THEN degrees _ 0.0; <> IF RealFns.AlmostEqual[degrees, ggData.measure.angleViewValue, -10] THEN degrees _ ggData.measure.angleViewValue ELSE ggData.measure.angleViewValue _ degrees; }; SetAngleValue: PUBLIC PROC [ggData: GGData, degrees: REAL] = { ggData.measure.angleViewValue _ degrees; IF ggData.controls.angleView # NIL THEN GGViewerOps.SetReal[ggData.controls.angleView, degrees, "%6.5f"]; }; SelectAngle: PUBLIC PROC [ggData: GGData] RETURNS [success: BOOL _ TRUE] = { IF ggData.controls.angleView=NIL THEN success _ FALSE ELSE ViewerTools.SetSelection[ggData.controls.angleView]; }; AddAngle: PUBLIC PROC [ggData: GGData, degrees: REAL, on: BOOL _ TRUE] RETURNS [alreadyThere: BOOL] = { oldFoundButton: AtomButtons.SortedButtonClient; IF ggData.controls.angleHandle = NIL THEN RETURN[TRUE]; oldFoundButton _ AtomButtons.AddScalarSorted[clientData: ggData, handle: ggData.controls.angleHandle, button: [NIL, degrees, LIST[LIST[$ToggleAngle, NEW[REAL _ degrees]]], on], order: decr]; alreadyThere _ oldFoundButton # NIL; }; AddAngleList: PUBLIC PROC [ggData: GGData, degrees: LIST OF REAL, on: LIST OF BOOL _ NIL] = { buttonList, oldList: LIST OF ScalarButton; oldValues: LIST OF REAL; oldOn: LIST OF BOOL; IF ggData.controls.angleHandle = NIL THEN RETURN; buttonList _ ButtonsFromValues[$ToggleAngle, NIL, degrees, on]; [oldValues, oldOn] _ GetAngleAlignments[ggData]; oldList _ ButtonsFromValues[$ToggleAngle, NIL, oldValues, oldOn]; buttonList _ MergeScalarButtonLists[buttonList, oldList, FALSE]; AtomButtons.BuildScalarButtons[ggData.controls.angleHandle, ggData, GGUserInput.EventNotify, NIL, buttonList]; }; NewAngleList: PUBLIC PROC [ggData: GGData, degrees: LIST OF REAL, on: LIST OF BOOL _ NIL] = { buttonList: LIST OF ScalarButton; IF ggData.controls.angleHandle = NIL THEN RETURN; buttonList _ ButtonsFromValues[$ToggleAngle, NIL, degrees, on]; AtomButtons.BuildScalarButtons[ggData.controls.angleHandle, ggData, GGUserInput.EventNotify, NIL, buttonList]; }; GetRadiusAlignments: PUBLIC PROC [ggData: GGData] RETURNS [names: LIST OF Rope.ROPE, values: LIST OF REAL, on: LIST OF BOOL] = { <> AddRadius: PROC [state: BOOL, name: Rope.ROPE, value: REF ANY, clientData: REF ANY] RETURNS [done: BOOL _ FALSE] = { real: REAL _ NARROW[value, REF REAL]^; GGCoreOps.AppendRope[name, nameListt]; [values, valuePtr] _ GGCoreOps.AddReal[real, values, valuePtr]; [on, boolPtr] _ GGCoreOps.AddBool[state, on, boolPtr]; }; nameListt: RopeListt; valuePtr: LIST OF REAL; boolPtr: LIST OF BOOL; nameListt _ GGCoreOps.NewRopeListt[]; [values, valuePtr] _ GGCoreOps.StartRealList[]; [on, boolPtr] _ GGCoreOps.StartBoolList[]; IF ggData.controls.radiusHandle # NIL THEN AtomButtons.ReadSortedButtons[ggData.controls.radiusHandle, AddRadius]; names _ nameListt.list; }; GetRadiusValue: PUBLIC PROC [ggData: GGData] RETURNS [radius: REAL, success: BOOL _ TRUE] = { IF ggData.controls.radiusView = NIL THEN RETURN[0.0, FALSE]; radius _ GGViewerOps.GetPositiveReal[ggData.controls.radiusView, Real.LargestNumber]; IF radius>reallyBigReal THEN { Feedback.Append[ggData.router, oneLiner, $Complaint, "Attempt to use illegal radius value"]; radius _ 0.0; success _ FALSE; RETURN; }; <> IF RealFns.AlmostEqual[radius, ggData.measure.radiusViewValue, -10] THEN radius _ ggData.measure.radiusViewValue ELSE ggData.measure.radiusViewValue _ radius; }; SetRadiusValue: PUBLIC PROC [ggData: GGData, radius: REAL] = { ggData.measure.radiusViewValue _ radius; IF ggData.controls.radiusView # NIL THEN GGViewerOps.SetReal[ggData.controls.radiusView, radius, "%6.5f"]; }; SelectRadius: PUBLIC PROC [ggData: GGData] RETURNS [success: BOOL _ TRUE] = { IF ggData.controls.radiusView=NIL THEN success _ FALSE ELSE ViewerTools.SetSelection[ggData.controls.radiusView]; }; AddRadius: PUBLIC PROC [ggData: GGData, name: Rope.ROPE, radius: REAL, on: BOOL _ TRUE] RETURNS [alreadyThere: BOOL] = { oldFoundButton: AtomButtons.SortedButtonClient; IF ggData.controls.radiusHandle = NIL THEN RETURN[TRUE]; oldFoundButton _ AtomButtons.AddScalarSorted[clientData: ggData, handle: ggData.controls.radiusHandle, button: [name, radius, LIST[LIST[$ToggleRadius, NEW[REAL _ radius]]], on], order: incr]; alreadyThere _ oldFoundButton # NIL; }; AddRadiusList: PUBLIC PROC [ggData: GGData, names: LIST OF Rope.ROPE, radii: LIST OF REAL, on: LIST OF BOOL _ NIL] = { buttonList, oldList: LIST OF ScalarButton; oldNames: LIST OF Rope.ROPE; oldValues: LIST OF REAL; oldOn: LIST OF BOOL; IF ggData.controls.radiusHandle = NIL THEN RETURN; buttonList _ ButtonsFromValues[$ToggleRadius, names, radii, on]; [oldNames, oldValues, oldOn] _ GetRadiusAlignments[ggData]; oldList _ ButtonsFromValues[$ToggleRadius, oldNames, oldValues, oldOn]; buttonList _ MergeScalarButtonLists[buttonList, oldList, TRUE]; AtomButtons.BuildScalarButtons[ggData.controls.radiusHandle, ggData, GGUserInput.EventNotify, NIL, buttonList]; }; NewRadiusList: PUBLIC PROC [ggData: GGData, names: LIST OF Rope.ROPE, radii: LIST OF REAL, on: LIST OF BOOL _ NIL] = { buttonList: LIST OF ScalarButton; IF ggData.controls.radiusHandle = NIL THEN RETURN; buttonList _ ButtonsFromValues[$ToggleRadius, names, radii, on]; AtomButtons.BuildScalarButtons[ggData.controls.radiusHandle, ggData, GGUserInput.EventNotify, NIL, buttonList]; }; GetLineDistanceAlignments: PUBLIC PROC [ggData: GGData] RETURNS [names: LIST OF Rope.ROPE, values: LIST OF REAL, on: LIST OF BOOL] = { <> AddDistance: PROC [state: BOOL, name: Rope.ROPE, value: REF ANY, clientData: REF ANY] RETURNS [done: BOOL _ FALSE] = { real: REAL _ NARROW[value, REF REAL]^; GGCoreOps.AppendRope[name, nameListt]; [values, valuePtr] _ GGCoreOps.AddReal[real, values, valuePtr]; [on, boolPtr] _ GGCoreOps.AddBool[state, on, boolPtr]; }; nameListt: RopeListt; valuePtr: LIST OF REAL; boolPtr: LIST OF BOOL; nameListt _ GGCoreOps.NewRopeListt[]; [values, valuePtr] _ GGCoreOps.StartRealList[]; [on, boolPtr] _ GGCoreOps.StartBoolList[]; IF ggData.controls.distanceHandle # NIL THEN AtomButtons.ReadSortedButtons[ggData.controls.distanceHandle, AddDistance]; names _ nameListt.list; }; GetLineDistanceValue: PUBLIC PROC [ggData: GGData] RETURNS [distance: REAL, success: BOOL _ TRUE] = { IF ggData.controls.lineDistView = NIL THEN RETURN[0.0, FALSE]; distance _ GGViewerOps.GetReal[ggData.controls.lineDistView, Real.LargestNumber]; IF distance>reallyBigReal THEN { Feedback.Append[ggData.router, oneLiner, $Complaint, "Attempt to use illegal line distance value"]; distance _ 0.0; success _ FALSE; RETURN; }; <> IF RealFns.AlmostEqual[distance, ggData.measure.lineDistViewValue, -10] THEN distance _ ggData.measure.lineDistViewValue ELSE ggData.measure.lineDistViewValue _ distance; }; SetLineDistanceValue: PUBLIC PROC [ggData: GGData, distance: REAL] = { ggData.measure.lineDistViewValue _ distance; IF ggData.controls.lineDistView # NIL THEN GGViewerOps.SetReal[ggData.controls.lineDistView, distance, "%6.5f"]; }; SelectLineDistance: PUBLIC PROC [ggData: GGData] RETURNS [success: BOOL _ TRUE] = { IF ggData.controls.lineDistView=NIL THEN success _ FALSE ELSE ViewerTools.SetSelection[ggData.controls.lineDistView]; }; AddLineDistance: PUBLIC PROC [ggData: GGData, name: Rope.ROPE, distance: REAL, on: BOOL _ TRUE] RETURNS [alreadyThere: BOOL] = { oldFoundButton: AtomButtons.SortedButtonClient; IF ggData.controls.distanceHandle = NIL THEN RETURN[TRUE]; oldFoundButton _ AtomButtons.AddScalarSorted[clientData: ggData, handle: ggData.controls.distanceHandle, button: [name, distance, LIST[LIST[$ToggleDistance, NEW[REAL _ distance]]], on], order: incr]; alreadyThere _ oldFoundButton # NIL; }; AddLineDistanceList: PUBLIC PROC [ggData: GGData, names: LIST OF Rope.ROPE, distances: LIST OF REAL, on: LIST OF BOOL _ NIL] = { buttonList, oldList: LIST OF ScalarButton; oldNames: LIST OF Rope.ROPE; oldValues: LIST OF REAL; oldOn: LIST OF BOOL; IF ggData.controls.distanceHandle = NIL THEN RETURN; buttonList _ ButtonsFromValues[$ToggleDistance, names, distances, on]; [oldNames, oldValues, oldOn] _ GetLineDistanceAlignments[ggData]; oldList _ ButtonsFromValues[$ToggleDistance, oldNames, oldValues, oldOn]; buttonList _ MergeScalarButtonLists[buttonList, oldList, TRUE]; AtomButtons.BuildScalarButtons[ggData.controls.distanceHandle, ggData, GGUserInput.EventNotify, NIL, buttonList]; }; NewLineDistanceList: PUBLIC PROC [ggData: GGData, names: LIST OF Rope.ROPE, distances: LIST OF REAL, on: LIST OF BOOL _ NIL] = { buttonList: LIST OF ScalarButton; IF ggData.controls.distanceHandle = NIL THEN RETURN; buttonList _ ButtonsFromValues[$ToggleDistance, names, distances, on]; AtomButtons.BuildScalarButtons[ggData.controls.distanceHandle, ggData, GGUserInput.EventNotify, NIL, buttonList]; }; ScalarToRope: PROC [scalar: REAL] RETURNS [rope: Rope.ROPE] = { space: CHAR = ' ; rope _ IO.PutFR["%1.2f", [real[scalar]]]; rope _ FileNames.Tail[rope, space]; -- strip off leading spaces <> UNTIL Rope.Fetch[base: rope, index: Rope.Length[rope]-1]# '0 DO rope _ Rope.Substr[base: rope, start: 0, len: Rope.Length[rope]-1]; ENDLOOP; <> IF Rope.Fetch[base: rope, index: Rope.Length[rope]-1] = '. THEN rope _ Rope.Substr[base: rope, start: 0, len: Rope.Length[rope]-1]; }; <> <> <> <<};>> <<>> <> <> <<};>> GetMidpoints: PUBLIC PROC [ggData: GGData] RETURNS [BOOL] = { IF ggData.controls = NIL OR ggData.controls.controlPanel = NIL THEN RETURN[TRUE] ELSE { val: REF _ EmbeddedButtons.GetValue[$Midpoints, ggData.controls.controlPanel]; trueOrFalse: REF BOOL; IF val = NIL THEN RETURN[TRUE]; -- no button so use a default value trueOrFalse _ NARROW[val]; RETURN[trueOrFalse^]; }; }; SetMidpoints: PUBLIC PROC [ggData: GGData, midpointsOn: BOOL] = { IF ggData.controls = NIL OR ggData.controls.controlPanel = NIL THEN RETURN; EmbeddedButtons.SetValue[$Midpoints, IF midpointsOn THEN true ELSE false, ggData.controls.controlPanel]; }; GetWorkingDirectory: PUBLIC PROC [ggData: GGData] RETURNS [ROPE] = { RETURN[ggData.currentWDir]; }; SetWorkingDirectory: PUBLIC PROC [ggData: GGData, directory: ROPE] = { ggData.currentWDir _ directory; }; <> <> <> <<};>> <<>> <> <> <> <> <<};>> <<>> GetShowAlignments: PUBLIC PROC [ggData: GGData] RETURNS [BOOL] = { IF ggData.controls = NIL OR ggData.controls.controlPanel = NIL THEN RETURN[TRUE] ELSE { val: REF _ EmbeddedButtons.GetValue[$ShowAlignments, ggData.controls.controlPanel]; trueOrFalse: REF BOOL; IF val = NIL THEN RETURN[TRUE]; -- no button so use a default value trueOrFalse _ NARROW[val]; RETURN[trueOrFalse^]; }; }; SetShowAlignments: PUBLIC PROC [ggData: GGData, showAlignments: BOOL] = { IF ggData.controls = NIL OR ggData.controls.controlPanel = NIL THEN RETURN; EmbeddedButtons.SetValue[$ShowAlignments, IF showAlignments THEN true ELSE false, ggData.controls.controlPanel]; ggData.camera.hideAlignments _ NOT showAlignments; }; true: REF BOOL _ NEW[BOOL _ TRUE]; false: REF BOOL _ NEW[BOOL _ FALSE]; GetDoubleBuffer: PUBLIC PROC [ggData: GGData] RETURNS [BOOL] = { IF ggData.controls = NIL OR ggData.controls.controlPanel = NIL THEN RETURN[ggData.controlState.doubleBuffer] ELSE { val: REF _ EmbeddedButtons.GetValue[$DoubleBuffer, ggData.controls.controlPanel]; trueOrFalse: REF BOOL; IF val = NIL THEN RETURN[TRUE]; -- no button so use a default value trueOrFalse _ NARROW[val]; RETURN[trueOrFalse^]; }; }; SetDoubleBuffer: PUBLIC PROC [ggData: GGData, doubleBuffer: BOOL] = { IF ggData.controls = NIL OR ggData.controls.controlPanel = NIL THEN { ggData.controlState.doubleBuffer _ doubleBuffer; RETURN; }; EmbeddedButtons.SetValue[$DoubleBuffer, IF doubleBuffer THEN true ELSE false, ggData.controls.controlPanel]; IF doubleBuffer THEN { GGRefresh.InvalidateBackground[ggData]; GGRefresh.InvalidateForeground[ggData]; }; }; <> <> <> <<};>> <<>> <> <> <> <> <> <> <<};>> <<};>> <<>> <> <<>> GetActive: PUBLIC PROC [ggData: GGData] RETURNS [BOOL] = { IF ggData.controls = NIL THEN RETURN[TRUE]; IF ggData.controls.controlPanel = NIL THEN RETURN[ggData.controls.active] ELSE { val: REF _ EmbeddedButtons.GetValue[$Active, ggData.controls.controlPanel]; trueOrFalse: REF BOOL; IF val = NIL THEN RETURN[TRUE] ELSE { trueOrFalse _ NARROW[val]; RETURN[trueOrFalse^]; }; }; }; SetActive: PUBLIC PROC [ggData: GGData, activeOn: BOOL] = { IF ggData.controls = NIL THEN RETURN; IF ggData.controls.controlPanel = NIL THEN ggData.controls.active _ activeOn ELSE EmbeddedButtons.SetValue[$Active, IF activeOn THEN true ELSE false, ggData.controls.controlPanel]; }; GetReadOnly: PUBLIC PROC [ggData: GGData] RETURNS [BOOL] = { IF ggData.controls = NIL OR ggData.controls.controlPanel = NIL THEN RETURN[ggData.controlState.readOnly] ELSE { trueOrFalse: REF BOOL; val: REF _ EmbeddedButtons.GetValue[$Editable, ggData.controls.controlPanel]; IF val = NIL THEN RETURN[ggData.controlState.readOnly]; trueOrFalse _ NARROW[val]; RETURN[NOT trueOrFalse^]; }; }; SetReadOnly: PUBLIC PROC [ggData: GGData, readOnly: BOOL] = { ggData.controlState.readOnly _ readOnly; IF ggData.controls = NIL OR ggData.controls.controlPanel = NIL THEN RETURN; EmbeddedButtons.SetValue[$Editable, IF readOnly THEN false ELSE true, ggData.controls.controlPanel]; }; GetPalette: PUBLIC PROC [ggData: GGData] RETURNS [BOOL] = { IF ggData.controls = NIL THEN RETURN[FALSE]; IF ggData.controls.controlPanel = NIL THEN RETURN[ggData.controls.palette] ELSE { val: REF _ EmbeddedButtons.GetValue[$Palette, ggData.controls.controlPanel]; trueOrFalse: REF BOOL; IF val = NIL THEN RETURN[FALSE]; trueOrFalse _ NARROW[val]; RETURN[trueOrFalse^]; }; }; SetPalette: PUBLIC PROC [ggData: GGData, paletteOn: BOOL] = { <> val: REF; isUnique: BOOL _ TRUE; <> IF ggData.controls = NIL THEN RETURN; IF ggData.controls.controlPanel = NIL THEN ggData.controls.palette _ paletteOn ELSE EmbeddedButtons.SetValue[$Palette, IF paletteOn THEN true ELSE false, ggData.controls.controlPanel]; <> IF paletteOn THEN { buttonDataRope: Rope.ROPE _ "Poppy1 Class: PopUpButton Menu: ( ((TransferFillColor) \"TransferFillColor\" \"Transfer this button's fill color to selected objects in the input focus viewer\") ((TransferBothColors) \"TransferBothColors\" \"Transfer this button's fill and stroke colors to selected objects in the input focus viewer\") ((TransferStrokeColor) \"TransferStrokeColor\" \"Transfer this button's stroke color to selected objects in the input focus viewer\") ) Feedback: ( (MouseMoved )) MessageHandler: Palette"; GGProps.Put[ggData.rootSlice, NIL, $ButtonData, GGProps.FromRope[$ButtonData, buttonDataRope]]; } ELSE { [val, isUnique] _ GGProps.Get[ggData.rootSlice, NIL, $ButtonData]; IF val # NIL THEN [] _ GGProps.Rem[ggData.rootSlice, NIL, $ButtonData]; }; IF paletteOn THEN SetActive[ggData, TRUE]; }; <> <> <> <<};>> <<>> <> val: REF; isUnique: BOOL _ TRUE; IF ggData.controls.paletteButton = NIL THEN ggData.controls.palette _ paletteOn ELSE AtomButtons.SetBinaryState[ggData.controls.paletteButton, paletteOn]; IF paletteOn THEN { buttonDataRope: Rope.ROPE _ "Poppy1 Class: PopUpButton Menu: ( ((TransferFillColor) \"TransferFillColor\" \"Transfer this button's fill color to selected objects in the input focus viewer\") ((TransferBothColors) \"TransferBothColors\" \"Transfer this button's fill and stroke colors to selected objects in the input focus viewer\") ((TransferStrokeColor) \"TransferStrokeColor\" \"Transfer this button's stroke color to selected objects in the input focus viewer\") ) Feedback: (MouseMotion ) MessageHandler: Palette"; GGProps.Put[ggData.rootSlice, NIL, $ButtonData, GGProps.FromRope[$ButtonData, buttonDataRope]]; } ELSE { [val, isUnique] _ GGProps.Get[ggData.rootSlice, NIL, $ButtonData]; IF val # NIL THEN [] _ GGProps.Rem[ggData.rootSlice, NIL, $ButtonData]; }; }; >> <> <<>> GetDefaults: PUBLIC PROC [ggData: GGData] RETURNS [DefaultData] = { RETURN[ggData.defaults]; }; SetDefaults: PUBLIC PROC [ggData: GGData, defaults: DefaultData] = { ggData.defaults _ defaults; }; <> <> <<};>> <<>> <> <> <> < "SpecifiedFonts",>> < "AlternateFonts",>> < ERROR;>> <> <> <<};>> <<>> DisplayStyleFromAtom: PROC [atom: ATOM] RETURNS [style: DisplayStyle] = { style _ SELECT atom FROM $SpecifiedFonts => print, $AlternateFonts => screen, $WYSIWYG => print ENDCASE => print; }; AtomFromDisplayStyle: PROC [style: DisplayStyle] RETURNS [atom: ATOM] = { atom _ SELECT style FROM print => $SpecifiedFonts, screen => $AlternateFonts, ENDCASE => ERROR; }; GetDisplayStyle: PUBLIC PROC [ggData: GGData] RETURNS [DisplayStyle] = { <> IF ggData.controls = NIL OR ggData.controls.controlPanel = NIL THEN RETURN[print] ELSE { val: REF _ EmbeddedButtons.GetValue[$ScreenStyle, ggData.controls.controlPanel]; atom: ATOM; IF val = NIL THEN RETURN[print]; -- no button so use a default value atom _ NARROW[val]; RETURN[DisplayStyleFromAtom[atom]]; }; }; SetDisplayStyle: PUBLIC PROC [ggData: GGData, displayStyle: DisplayStyle] = { <> wantName: ATOM; wantName _ AtomFromDisplayStyle[displayStyle]; EmbeddedButtons.SetValue[$ScreenStyle, wantName, ggData.controls.controlPanel]; ggData.camera.displayStyle _ displayStyle; }; CycleDisplayStyle: PUBLIC PROC [ggData: GGData, forward: BOOL] = { wantName, isName: ATOM; camera: Camera _ ggData.camera; val: REF; val _ EmbeddedButtons.GetValue[$ScreenStyle, ggData.controls.controlPanel]; isName _ NARROW[val]; IF forward THEN { wantName _ SELECT isName FROM $SpecifiedFonts => $AlternateFonts, $AlternateFonts => $WYSIWYG, $WYSIWYG => $SpecifiedFonts, ENDCASE => $SpecifiedFonts; } ELSE { wantName _ SELECT isName FROM $SpecifiedFonts => $WYSIWYG, $AlternateFonts => $SpecifiedFonts, $WYSIWYG => $AlternateFonts, ENDCASE => $SpecifiedFonts; }; EmbeddedButtons.SetValue[$ScreenStyle, wantName, ggData.controls.controlPanel]; SELECT wantName FROM $SpecifiedFonts => { camera.quality _ fast; camera.displayStyle _ print; }; $AlternateFonts => { camera.quality _ fast; camera.displayStyle _ screen; }; $WYSIWYG => { camera.quality _ quality; camera.displayStyle _ print; }; ENDCASE => ERROR; }; <> <> <> <> <> < "SpecifiedFonts",>> < "AlternateFonts",>> < ERROR;>> <> <> <> <> <> <> <<};>> <<>> <> <> <> <> <> <> <> <> < pointsPreferred,>> < linesPreferred,>> < ERROR;>> <> <<};>> <<>> <> <> <<};>> <<>> <> <> <> <> <> < "PreferPoints",>> < "PreferLines",>> < ERROR;>> <> <> <> <> <> <> <<};>> <> <> <<};>> <<>> GetHeuristics: PUBLIC PROC [ggData: GGData] RETURNS [BOOL] = { IF ggData.controls = NIL OR ggData.controls.controlPanel = NIL THEN RETURN[FALSE] ELSE { val: REF _ EmbeddedButtons.GetValue[$Auto, ggData.controls.controlPanel]; trueOrFalse: REF BOOL; IF val = NIL THEN RETURN[FALSE]; -- no button so use a default value trueOrFalse _ NARROW[val]; RETURN[trueOrFalse^]; }; }; SetHeuristics: PUBLIC PROC [ggData: GGData, heuristicsOn: BOOL] = { IF ggData.controls = NIL OR ggData.controls.controlPanel = NIL THEN RETURN; EmbeddedButtons.SetValue[$Auto, IF heuristicsOn THEN true ELSE false, ggData.controls.controlPanel]; }; <> <> <> <<};>> <<>> <> <> <> <<};>> GetScaleUnit: PUBLIC PROC [ggData: GGData] RETURNS [REAL] = { RETURN[ggData.hitTest.scaleUnit]; }; SetScaleUnit: PUBLIC PROC [ggData: GGData, unit: REAL, history: HistoryEvent] = { IF unit >0.0 THEN { oldValue: REF REAL _ NEW[REAL _ GetScaleUnit[ggData]]; ggData.hitTest.scaleUnit _ unit; -- in screen dots IF history#NIL THEN { changeRef: REF Change.changingstate _ NEW[Change.changingstate _ [changingstate[$SetScaleUnit, ggData.scene, oldValue] ] ]; GGHistory.Note[history, UndoScale, changeRef]; }; }; }; <<>> UndoScale: PROC [historyData: REF Change, currentEvent: HistoryEvent] = { <> <> stateData: REF Change.changingstate _ NARROW[historyData]; SELECT stateData.op FROM $SetScaleUnit => { oldValue: REF REAL _ NARROW[stateData.oldValue]; <<[] _ SetScaleUnit[stateData.ggData, oldValue^, currentEvent]; -- restore old value>> }; ENDCASE; }; UpdateCursorLooks: PROC [ggData: GGData] = { SELECT GetGravity[ggData] FROM TRUE => SELECT GetGravityType[ggData] FROM pointsPreferred => GGWindow.SetCursorLooks[pointsPreferred, ggData]; linesPreferred, facesPreferred => GGWindow.SetCursorLooks[linesPreferred, ggData]; ENDCASE => ERROR; FALSE => GGWindow.SetCursorLooks[pointsPreferred, ggData, TRUE]; -- really means off ENDCASE; }; <> GetSliceToExtend: PUBLIC PROC [ggData: GGData] RETURNS [sliceD: SliceDescriptor] = { RETURN[ggData.drag.sliceToExtend]; }; SetSliceToExtend: PUBLIC PROC [ggData: GGData, sliceD: SliceDescriptor] = { ggData.drag.sliceToExtend _ sliceD; }; <<>> <> GetSelectMode: PUBLIC PROC [ggData: GGData] RETURNS [selectMode: SelectMode] = { RETURN[ggData.drag.selectState]; }; SetSelectMode: PUBLIC PROC [ggData: GGData, selectMode: SelectMode] = { ggData.drag.selectState _ selectMode; }; GetExtendMode: PUBLIC PROC [ggData: GGData] RETURNS [extendMode: ExtendMode] = { RETURN[ggData.drag.extendMode]; }; SetExtendMode: PUBLIC PROC [ggData: GGData, extendMode: ExtendMode] = { ggData.drag.extendMode _ extendMode; }; GetQuickClickMode: PUBLIC PROC RETURNS [on: BOOL] = { RETURN[quickClickMode]; }; SetQuickClickMode: PUBLIC PROC [on: BOOL] = { quickClickMode _ on; }; quickClickMode: BOOL _ FALSE; -- managed by GGUserProfileImpl GetSelectionCycler: PUBLIC PROC [ggData: GGData] RETURNS [featureCycler: FeatureCycler] = { featureCycler _ ggData.scene.selected.featureCycler; }; SetSelectionCycler: PUBLIC PROC [ggData: GGData, featureCycler: FeatureCycler] = { ggData.scene.selected.featureCycler _ featureCycler; }; <> <> <> <> <<};>> <> GetFullName: PUBLIC PROC [ggData: GGData] RETURNS [fullName: ROPE] = { <> <> fullName _ IF ggData.controls.topper.file#NIL THEN ggData.controls.topper.file ELSE ggData.controls.panel.file; }; StoreAdvisory: PUBLIC PROC [ggData: GGData, fullName: ROPE, versionSpecified: BOOL] = { nameNoBang: ROPE _ FileNames.StripVersionNumber[fullName]; SetNameFileLabel[ggData, IF versionSpecified THEN fullName ELSE nameNoBang, fullName, FileNames.GetShortName[nameNoBang]]; }; GetAdvisory: PUBLIC PROC [ggData: GGData, fullName: ROPE, versionSpecified: BOOL] = { StoreAdvisory[ggData, fullName, versionSpecified]; }; ClearAdvisory: PUBLIC PROC [ggData: GGData] = { panelPrefix: Rope.ROPE = "GGPanel: "; SetNameFileLabel[ggData, NIL, NIL, NIL]; ggData.controls.panel.name _ Rope.Concat[panelPrefix, "Gargoyle"]; ggData.controls.panel.label _ panelPrefix; ggData.controls.topper.name _ ggData.controls.topper.label _ "Gargoyle"; }; AdviseRestore: PUBLIC PROC [ggData: GGData] RETURNS [ok: BOOL _ FALSE] = { <> name: ROPE _ IF ggData.controls.topper.name#NIL THEN ggData.controls.topper.name ELSE ggData.controls.panel.name; IF ggData.controls.topper.destroyed THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Restore failed: picture destroyed; try Save or Store"] ELSE IF Rope.Equal[name, NIL] THEN Feedback.Append[ggData.router, oneLiner, $Complaint, "Restore failed: can't restore unnamed viewer; try Get"] ELSE ok _ TRUE; }; SetNameFileLabel: PROC [ggData: GGData, name, file, label: ROPE] = { ggData.controls.topper.name _ ggData.controls.panel.name _ ggData.controls.picture.name _ name; ggData.controls.topper.file _ ggData.controls.panel.file _ ggData.controls.picture.file _ file; ggData.controls.topper.label _ ggData.controls.panel.label _ ggData.controls.picture.label _ label; }; GetBiScroller: PUBLIC PROC [ggData: GGData] RETURNS [bs: BiScrollers.BiScroller] = { bs _ ggData.controls.biScroller; }; GrabInputFocus: PUBLIC PROC [ggData: GGData] = { [] _ InputFocus.SetInputFocus[ggData.controls.actionArea]; }; GetWidth: PUBLIC PROC [ggData: GGData] RETURNS [width: INT] = { -- drawing area, in "window" units width _ ggData.controls.actionArea.cw; }; GetHeight: PUBLIC PROC [ggData: GGData] RETURNS [height: INT] = { -- drawing area, in "window" units height _ ggData.controls.actionArea.ch; }; <<>> ShowHelp: PUBLIC PROC [ggData: GGData, category: ATOM] = { openHeight: INTEGER _ 140; help: Viewer; name: Rope.ROPE; SELECT category FROM $MouseActions => {name _ "GGHelp.tioga"; openHeight _ 140}; $Fonts => {name _ "GGFontSampler.tioga"; openHeight _ 210}; $Colors => {name _ "GGColors.tioga"; openHeight _ 210}; ENDCASE => {name _ "GargoyleDoc.tioga"; openHeight _ 115}; IF (help _ ViewerOps.FindViewer[ <> FS.ExpandName[name, GGUIUtility.GGHomeDirectory[] ].fullFName])#NIL THEN { -- viewer already exists IF help.column#right THEN ViewerOps.ChangeColumn[help, right]; } ELSE { help _ ViewerOps.CreateViewer[flavor: $Text, info: [iconic: TRUE, column: right, openHeight: openHeight], paint: FALSE]; <> TiogaMenuOps.Load[viewer: help, fileName: Rope.Concat[GGUIUtility.GGHomeDirectory[], name]]; }; ViewerOps.SetOpenHeight[viewer: help, clientHeight: openHeight]; ViewerOps.OpenIcon[icon: help, bottom: FALSE, paint: FALSE]; -- must do Open before Top ViewerOps.TopViewer[viewer: help, paint: FALSE]; ViewerOps.ComputeColumn[right]; -- repaint right column Feedback.Append[ggData.router, oneLiner, $Feedback, "Help opened"]; }; ReloadTipTable: PUBLIC PROC [ggData: GGData] RETURNS [success: BOOL _ TRUE] = { newTable: TIPUser.TIPTable; actionArea: Viewer; tableName, msg: Rope.ROPE; <> tableName _ Rope.Concat[GGUIUtility.GGHomeDirectory[], "Gargoyle.tip"]; Feedback.PutF[ggData.router, begin, $Feedback, "Reloading tip table %g. . . ", [rope[tableName]] ]; newTable _ TIPUser.InstantiateNewTIPTable[tableName ! FS.Error => { success _ FALSE; msg _ Rope.Concat["Cannot read TIP table file: ", tableName]; CONTINUE}; TIPUser.InvalidTable => { success _ FALSE; msg _ Rope.Concat["Error(s) saved on TIP.Errors for: ", tableName]; CONTINUE}]; IF success THEN { IF newTable = NIL THEN ERROR; Feedback.Append[ggData.router, end, $Feedback, "Done"]; <> ggData.parseInfo.tableHead _ newTable; } ELSE Feedback.Append[ggData.router, oneLiner, $Complaint, msg]; }; PaintActionArea: PUBLIC PROC [ggData: GGData] = { ViewerOps.PaintViewer[ viewer: ggData.controls.actionArea, hint: client, whatChanged: ggData, clearClient: FALSE]; }; Typescript: PUBLIC PROC [ggData: GGData] = { alreadyExists: BOOL _ FALSE; typescript: Viewer; [alreadyExists, typescript] _ FeedbackOps.CreateNamedTypescript["Gargoyle Typescript", $Gargoyle, 120]; IF alreadyExists THEN ViewerOps.OpenIcon[icon: typescript, closeOthers: FALSE, bottom: TRUE, paint: TRUE]; Feedback.Append[ggData.router, oneLiner, $Feedback, "Typescript opened"]; }; GGEdited: PUBLIC PROC [ggData: GGData, clientData: REF] = { IF GGUserProfile.GetAutoScriptingOn[] THEN { ggData.debug.autoScriptActionCount _ ggData.debug.autoScriptActionCount + 1; IF ggData.debug.autoScriptActionCount MOD 20 = 0 THEN [ggData.debug.autoScriptStream, ggData.debug.autoScriptName] _ GGSessionLog.FlushScript[ggData.debug.autoScriptStream, ggData.debug.autoScriptName, ggData.router]; }; IF ggData.controls = NIL OR ggData.controls.topper = NIL OR ggData.controls.panel = NIL THEN RETURN; IF NOT ggData.controls.topper.newVersion THEN { <> dirtyNoNameIconG, dirtyIconG: Icons.IconFlavor; [dirtyNoNameIcon: dirtyNoNameIconG, dirtyIcon: dirtyIconG] _ GGWindow.GetIcons[]; ggData.controls.topper.icon _ IF ggData.controls.topper.file=NIL THEN dirtyNoNameIconG ELSE dirtyIconG; ggData.controls.panel.newVersion _ TRUE; -- guard destroy button. KAP. June 1, 1988 ggData.controls.topper.newVersion _ TRUE; IF ggData.controls.topper.parent = NIL THEN -- top level viewer ViewerOps.PaintViewer[ggData.controls.topper, caption]; IF ggData.controls.topper#ggData.controls.panel THEN { IF ggData.controls.panel.parent = NIL THEN -- top level viewer ViewerOps.PaintViewer[ggData.controls.panel, caption]; }; }; }; END.