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 <SetCursor bullseye>)) 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]; }; <<SetPalette: PUBLIC PROC [ggData: GGData, paletteOn: BOOL] = { 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 <SetCursor bullseye>) 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; }; 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; }; GetDefaultDashPattern: PUBLIC PROC [ggData: GGData] RETURNS [dashed: BOOL, pattern: SequenceOfReal, offset: REAL, length: REAL] = { dashed _ ggData.defaults.dashed; pattern _ ggData.defaults.pattern; offset _ ggData.defaults.offset; length _ ggData.defaults.length; }; SetDefaultDashPattern: PUBLIC PROC [ggData: GGData, dashed: BOOL, pattern: SequenceOfReal, offset: REAL, length: REAL] = { ggData.defaults.dashed _ dashed; ggData.defaults.pattern _ pattern; ggData.defaults.offset _ offset; ggData.defaults.length _ length; }; GetDefaultFillColor: PUBLIC PROC [ggData: GGData] RETURNS [fillColor: Imager.Color] = { fillColor _ ggData.defaults.fillColor; }; SetDefaultFillColor: PUBLIC PROC [ggData: GGData, fillColor: Imager.Color] = { ggData.defaults.fillColor _ fillColor; }; GetDefaultStrokeColor: PUBLIC PROC [ggData: GGData] RETURNS [strokeColor: Imager.Color] = { strokeColor _ ggData.defaults.strokeColor; }; SetDefaultStrokeColor: PUBLIC PROC [ggData: GGData, strokeColor: Imager.Color] = { ggData.defaults.strokeColor _ strokeColor; }; GetDefaultStrokeJoint: PUBLIC PROC [ggData: GGData] RETURNS [strokeJoint: StrokeJoint] = { strokeJoint _ ggData.defaults.strokeJoint; }; SetDefaultStrokeJoint: PUBLIC PROC [ggData: GGData, strokeJoint: StrokeJoint] = { ggData.defaults.strokeJoint _ strokeJoint; }; GetDefaultStrokeEnd: PUBLIC PROC [ggData: GGData] RETURNS [strokeEnd: StrokeEnd] = { strokeEnd _ ggData.defaults.strokeEnd; }; SetDefaultStrokeEnd: PUBLIC PROC [ggData: GGData, strokeEnd: StrokeEnd] = { ggData.defaults.strokeEnd _ strokeEnd; }; GetDefaultDropShadows: PUBLIC PROC [ggData: GGData] RETURNS [dropShadowOn: BOOL, dropShadowOffset: Vector, dropShadowColor: Imager.Color] = { dropShadowOn _ ggData.defaults.dropShadowOn; dropShadowOffset _ ggData.defaults.dropShadowOffset; dropShadowColor _ ggData.defaults.dropShadowColor; }; SetDefaultDropShadows: PUBLIC PROC [ggData: GGData, dropShadowOn: BOOL, dropShadowOffset: Vector, dropShadowColor: Imager.Color] = { ggData.defaults.dropShadowOn _ dropShadowOn; ggData.defaults.dropShadowOffset _ dropShadowOffset; ggData.defaults.dropShadowColor _ dropShadowColor; }; GetDefaultFont: PUBLIC PROC [ggData: GGData] RETURNS [fontData: FontData] = { fontData _ ggData.defaults.font; }; SetDefaultFont: PUBLIC PROC [ggData: GGData, fontData: FontData] = { ggData.defaults.font _ fontData; }; GetGravity: PUBLIC PROC [ggData: GGData] RETURNS [BOOL] = { IF ggData.controls = NIL OR ggData.controls.controlPanel = NIL THEN RETURN[TRUE] ELSE { val: REF _ EmbeddedButtons.GetValue[$Gravity, ggData.controls.controlPanel]; trueOrFalse: REF BOOL; IF val = NIL THEN RETURN[TRUE]; -- no button so use a default value trueOrFalse _ NARROW[val]; RETURN[trueOrFalse^]; }; }; SetGravity: PUBLIC PROC [ggData: GGData, gravityOn: BOOL] = { IF ggData.controls = NIL OR ggData.controls.controlPanel = NIL THEN RETURN; EmbeddedButtons.SetValue[$Gravity, IF gravityOn THEN true ELSE false, ggData.controls.controlPanel]; UpdateCursorLooks[ggData]; }; GetGravityExtent: PUBLIC PROC [ggData: GGData] RETURNS [inches: REAL] = { screenDots: REAL; IF ggData.controls = NIL OR ggData.controls.controlPanel = NIL THEN screenDots _ GGUserProfile.GetDefaultGravityExtent[] ELSE { val: REF _ EmbeddedButtons.GetValue[$GravityExtent, ggData.controls.controlPanel]; IF val = NIL THEN screenDots _ GGUserProfile.GetDefaultGravityExtent[] ELSE { screenDots _ NARROW[val, REF REAL]^; }; }; inches _ screenDots/72.0; }; SetGravityExtent: PUBLIC PROC [ggData: GGData, inches: REAL] = { screenDots: REAL; refReal: REF REAL; IF ggData.controls = NIL OR ggData.controls.controlPanel = NIL THEN RETURN; screenDots _ inches*72.0; refReal _ NEW[REAL _ screenDots]; EmbeddedButtons.SetValue[$GravityExtent, refReal, ggData.controls.controlPanel]; ggData.hitTest.t _ screenDots; }; GravityTypeFromAtom: PROC [atom: ATOM] RETURNS [gravityType: GravityType] = { gravityType _ SELECT TRUE FROM atom = $PreferPoints => pointsPreferred, atom = $PreferLines => linesPreferred, ENDCASE => pointsPreferred; }; AtomFromGravityType: PROC [gravityType: GravityType] RETURNS [atom: ATOM] = { atom _ SELECT gravityType FROM pointsPreferred => $PreferPoints, linesPreferred, facesPreferred => $PreferLines, ENDCASE => ERROR; }; GetGravityType: PUBLIC PROC [ggData: GGData] RETURNS [gravityType: GravityType] = { IF ggData.controls = NIL OR ggData.controls.controlPanel = NIL THEN RETURN[pointsPreferred] ELSE { val: REF _ EmbeddedButtons.GetValue[$GravityType, ggData.controls.controlPanel]; atom: ATOM; IF val = NIL THEN RETURN[pointsPreferred]; -- no button so use a default value atom _ NARROW[val]; RETURN[GravityTypeFromAtom[atom]]; }; }; SetGravityType: PUBLIC PROC [ggData: GGData, gravityType: GravityType] = { atom: ATOM; IF ggData.controls = NIL OR ggData.controls.controlPanel = NIL THEN RETURN; atom _ AtomFromGravityType[gravityType]; EmbeddedButtons.SetValue[$GravityType, atom, ggData.controls.controlPanel]; ggData.hitTest.gravityType _ gravityType; UpdateCursorLooks[ggData]; }; CycleGravityType: PUBLIC PROC [ggData: GGData, forward: BOOL] = { gravityType: GravityType; IF ggData.controls = NIL OR ggData.controls.controlPanel = NIL THEN RETURN; gravityType _ GetGravityType[ggData]; gravityType _ IF gravityType = pointsPreferred THEN linesPreferred ELSE pointsPreferred; SetGravityType[ggData, gravityType]; ggData.hitTest.gravityType _ gravityType; UpdateCursorLooks[ggData]; }; 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]; }; 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. ���#î��GGStateImpl.mesa Contents: Routines for getting and setting values in the Gargoyle user interface state. Copyright Ó 1986, 1988, 1989 by Xerox Corporation. All rights reserved. Bier, March 5, 1992 2:37 pm PST Pier, December 2, 1991 5:49 pm PST Doug Wyatt, December 18, 1989 4:17:24 pm PST PROC [ggData: GGData, clientData: REF _ NIL] RETURNS [rect: Imager.Rectangle]; Gets the viewport size from the BiScroller need to repaint the topper caption because viewer is no longer edited Changes the gargoyle icon to $clear or $clean Finds the rectangle representing the bounds of the current action area. pp: PreservationPair ~ bs.class.common.preserve; cv _ [v.cw*pp[X], v.ch*pp[Y]]; Extracted from BiScrollersButtonned.ChangeTransform. IF offsetsMustBeIntegers THEN new _ new.TranslateTo[[Real.Round[new.c], Real.Round[new.f]]]; The larger of the two scaling components of clientToViewer. Alignment Menus Returns the values, and state booleans in proper order. Only positive slopes, please. Return the most accurate value we have. name _ IF names = NIL THEN NIL ELSE names.first; -- why did this replace the line above? Destructive merge of the two lists, removing duplicates, where the element that is removed, when there is a choice, is the one without a name. Take the first element of list off of list and add it to mergedList, updating pointers. Put the most accurate value we have into variable angle Returns the names, values, and state booleans in proper order. Put the most accurate value we have into variable radius Returns the names, values, and state booleans in proper order. Put the most accurate value we have into variable distance Strip off trailing zeroes Strip off trailing decimal point GetMidpoints: PUBLIC PROC [ggData: GGData] RETURNS [BOOL] = { IF ggData.controls.midpointButton = NIL THEN RETURN[TRUE] ELSE RETURN[AtomButtons.GetBinaryState[ggData.controls.midpointButton]]; }; SetMidpoints: PUBLIC PROC [ggData: GGData, midpointsOn: BOOL] = { IF ggData.controls.midpointButton # NIL THEN AtomButtons.SetBinaryState[ggData.controls.midpointButton, midpointsOn]; }; GetShowAlignments: PUBLIC PROC [ggData: GGData] RETURNS [BOOL] = { IF ggData.controls.alignments = NIL THEN RETURN[TRUE] ELSE RETURN[AtomButtons.GetBinaryState[ggData.controls.alignments]]; }; SetShowAlignments: PUBLIC PROC [ggData: GGData, showAlignments: BOOL] = { IF ggData.controls.alignments = NIL THEN RETURN; AtomButtons.SetBinaryState[ggData.controls.alignments, showAlignments]; ggData.camera.hideAlignments _ NOT showAlignments; }; GetDoubleBuffer: PUBLIC PROC [ggData: GGData] RETURNS [BOOL] = { IF ggData.controls = NIL OR ggData.controls.bufferButton = NIL THEN RETURN[TRUE] ELSE RETURN[AtomButtons.GetBinaryState[ggData.controls.bufferButton]]; }; SetDoubleBuffer: PUBLIC PROC [ggData: GGData, doubleBuffer: BOOL] = { IF ggData.controls = NIL OR ggData.controls.bufferButton = NIL THEN RETURN; AtomButtons.SetBinaryState[ggData.controls.bufferButton, doubleBuffer]; IF doubleBuffer THEN { GGRefresh.InvalidateBackground[ggData]; GGRefresh.InvalidateForeground[ggData]; }; }; Gargoyle Behaviors Update the "Palette" button and make sure that the ButtonData property of the root node is correct Update control panel. Check the root node. GetPalette: PUBLIC PROC [ggData: GGData] RETURNS [BOOL] = { IF ggData.controls.paletteButton = NIL THEN RETURN[ggData.controls.palette] ELSE RETURN[AtomButtons.GetBinaryState[ggData.controls.paletteButton]]; }; Update the "Palette" button and make sure that the ButtonData property of the root node is correct Graphical Style GetDisplayStyle: PUBLIC PROC [ggData: GGData] RETURNS [DisplayStyle] = { RETURN[ggData.camera.displayStyle]; }; SetDisplayStyle: PUBLIC PROC [ggData: GGData, displayStyle: DisplayStyle] = { wantName: Rope.ROPE; wantName _ SELECT displayStyle FROM print => "SpecifiedFonts", screen => "AlternateFonts", ENDCASE => ERROR; EmbeddedButtons.SetValue[$ScreenStyle, wantName, ggData.controls.controlPanel]; ggData.camera.displayStyle _ displayStyle; }; Not very useful because DisplayStyle doesn't include WYSIWYG. Not very useful because DisplayStyle doesn't include WYSIWYG. SetDisplayStyle: PUBLIC PROC [ggData: GGData, displayStyle: DisplayStyle] = { NEED TO GOOSE THE MENU BUTTON HERE info: AtomButtons.EnumTypeRef _ ggData.controls.screenStyle; isName, wantName: Rope.ROPE; wantName _ SELECT displayStyle FROM print => "SpecifiedFonts", screen => "AlternateFonts", ENDCASE => ERROR; isName _ info.flipLabel.name; UNTIL Rope.Equal[isName, wantName, TRUE] DO AtomButtons.TimeToFlipThru[LIST[$FlipForward, info]]; isName _ info.flipLabel.name; ENDLOOP; ggData.camera.displayStyle _ displayStyle; }; CycleDisplayStyle: PUBLIC PROC [ggData: GGData, forward: BOOL] = { name: Rope.ROPE; info: AtomButtons.EnumTypeRef _ ggData.controls.screenStyle; camera: Camera _ ggData.camera; IF forward THEN AtomButtons.TimeToFlipThru[LIST[$FlipForward, info]] ELSE AtomButtons.TimeToFlipThru[LIST[$FlipBackward, info]]; name _ info.flipLabel.name; SELECT TRUE FROM Rope.Equal[name, "SpecifiedFonts", TRUE] => { camera.quality _ fast; camera.displayStyle _ print; }; Rope.Equal[name, "AlternateFonts", TRUE] => { camera.quality _ fast; camera.displayStyle _ screen; }; Rope.Equal[name, "WYSIWYG", TRUE] => { camera.quality _ quality; camera.displayStyle _ print; }; ENDCASE => ERROR; }; Gravity GetGravity: PUBLIC PROC [ggData: GGData] RETURNS [BOOL] = { IF ggData.controls.gravButton = NIL THEN RETURN[TRUE] ELSE RETURN[AtomButtons.GetBinaryState[ggData.controls.gravButton]]; }; SetGravity: PUBLIC PROC [ggData: GGData, gravityOn: BOOL] = { IF ggData.controls.gravButton = NIL THEN RETURN; AtomButtons.SetBinaryState[ggData.controls.gravButton, gravityOn]; UpdateCursorLooks[ggData]; }; GetGravityExtent: PUBLIC PROC [ggData: GGData] RETURNS [inches: REAL] = { screenDots: REAL; graphicsState: AtomButtonsTypes.GraphicsState _ ggData.controls.gravityExtentButton; IF graphicsState = NIL THEN screenDots _ GGUserProfile.GetDefaultGravityExtent[] ELSE { ged: GGInterfaceTypes.GravityExtentData; ged _ NARROW[GraphicsButton.GetValue[graphicsState].buttonData]; screenDots _ ged.extent; }; inches _ screenDots/72.0; }; SetGravityExtent: PUBLIC PROC [ggData: GGData, inches: REAL] = { screenDots: REAL; graphicsState: AtomButtonsTypes.GraphicsState _ ggData.controls.gravityExtentButton; ged: GGInterfaceTypes.GravityExtentData; IF graphicsState = NIL THEN RETURN; screenDots _ inches*72.0; ged _ NEW[GGInterfaceTypes.GravityExtentDataObj _ [extent: screenDots]]; GraphicsButton.SetButtonValueAndPaint[graphicsState, ggData, ged]; ggData.hitTest.t _ screenDots; }; CycleGravityType: PUBLIC PROC [ggData: GGData, forward: BOOL] = { info: AtomButtons.EnumTypeRef _ ggData.controls.gravityTypeMenu; IF info # NIL THEN { IF forward THEN AtomButtons.TimeToFlipThru[LIST[$FlipForward, info]] ELSE AtomButtons.TimeToFlipThru[LIST[$FlipBackward, info]]; }; ggData.hitTest.gravityType _ SELECT TRUE FROM Rope.Equal[info.flipLabel.name, "PreferPoints", TRUE] => pointsPreferred, Rope.Equal[info.flipLabel.name, "PreferLines", TRUE] => linesPreferred, ENDCASE => ERROR; UpdateCursorLooks[ggData]; }; GetGravityType: PUBLIC PROC [ggData: GGData] RETURNS [gravityType: GravityType] = { RETURN[ggData.hitTest.gravityType]; }; SetGravityType: PUBLIC PROC [ggData: GGData, gravityType: GravityType] = { NEED TO GOOSE THE MENU BUTTON HERE info: AtomButtons.EnumTypeRef _ ggData.controls.gravityTypeMenu; isName, wantName: Rope.ROPE; wantName _ SELECT gravityType FROM pointsPreferred => "PreferPoints", linesPreferred, facesPreferred => "PreferLines", ENDCASE => ERROR; IF info # NIL THEN { isName _ info.flipLabel.name; UNTIL Rope.Equal[isName, wantName, TRUE] DO AtomButtons.TimeToFlipThru[LIST[$FlipForward, info]]; isName _ info.flipLabel.name; ENDLOOP; }; ggData.hitTest.gravityType _ gravityType; UpdateCursorLooks[ggData]; }; GetHeuristics: PUBLIC PROC [ggData: GGData] RETURNS [BOOL] = { IF ggData.controls.heuristicsButton = NIL THEN RETURN[FALSE] ELSE RETURN[AtomButtons.GetBinaryState[ggData.controls.heuristicsButton]]; }; SetHeuristics: PUBLIC PROC [ggData: GGData, heuristicsOn: BOOL] = { IF ggData.controls.heuristicsButton = NIL THEN RETURN; AtomButtons.SetBinaryState[ggData.controls.heuristicsButton, heuristicsOn]; }; GGHistoryTypes.HistoryProc This proc is called by the Undo mechanism. It is called with a history event (currentEvent) which it passes on to record its undo operations, making undo an event (and thus undoable) in itself. [] _ SetScaleUnit[stateData.ggData, oldValue^, currentEvent]; -- restore old value Other Hidden State (yuk) Debugging and Experiments precomputeMidpoints: BOOL _ FALSE; PrecomputeMidpoints: PUBLIC PROC [] RETURNS [BOOL] = { RETURN[precomputeMidpoints]; }; Names, files, windows file name like /net/server/user/gargoyle/Foo.gargoyle or /GargoylePics/MyPics/Foo.gargoyle!3 is restore possible?? removed use of originalWDir removed use of originalWDir tableName _ Rope.Concat[ggData.originalWDir, "Gargoyle.tip"]; ggData.controls.actionArea.tipTable _ newTable; -- this TIP table is now the Transparent TIP table at all times Picture just became edited (dirty). Change the icon. �ÊCC��•NewlineDelimiter – "cedar" style˜�Icodešœ™šÏnœP™XKšœH™HKšœ™K™"K™,—K™�šÏk ˜ Jšœ€Ïbœæžœf˜Ï—K˜�šœžœž˜Jšžœ‰žœP˜âKšžœJž˜V—˜�KšœžœÏc˜EKšœ žœ$ ˜[Kšœžœžœ ˜VKšœžœžœ ˜VKšœ žœžœ ˜SK˜�Kšœžœ˜#Kšœžœ˜%Kšœ žœ˜-Kšœžœ˜/Kšœžœ˜+Kšœžœ"˜5Kšœ žœ˜!Kšœžœ˜'Kšœ žœ ˜1Kšœžœ˜1Kšžœžœžœ˜Kšœžœ˜(Kšœžœ˜.Kšœ žœžœ ˜FKšœžœ'˜?Kšœžœ'˜?Kšœžœ˜+Kšœžœ˜2Kšœžœ ˜5Kšœ žœ˜'Kšœžœ˜#Kšœžœ'˜;Kšœžœ˜#Kšœžœ˜$Kšœžœ˜0K˜�—Kšœžœ ˜K˜�š œžœžœ2žœžœ˜aKšœ!˜!Kšœ'˜'K˜K™�—šœžœ˜(Kšžœžœžœžœ™NKšœ*™*Kšžœžœžœžœ˜?Kšœ;˜;K˜K™�—š œžœžœ˜9KšœE™EKšžœžœžœžœžœžœžœžœ˜dKšœ#žœ .˜XKšœ$žœ˜*šœžœž˜,Kšœ)˜)Kšœ(˜(Kšžœžœ˜—Kšœ.Ÿœ˜7Kšžœ-žœ.Ÿœ˜kKšœ˜K˜�—š œžœžœžœ˜6K™-Kšžœžœžœžœžœžœ˜Ešœžœž˜,Kšœ)˜)Kšœ(˜(Kšžœžœ˜—Kšœ.Ÿœ˜7Kšœ˜K™�K˜�—š œžœžœžœžœ˜IKš žœžœžœžœžœ˜CKšœw˜wK˜K˜�—šœžœžœžœ˜NK™GKšžœžœžœžœ˜HKšžœžœ@˜KK˜K˜�—š œžœžœžœžœ˜BKšœ˜K˜:Kšžœžœžœžœžœžœ˜:K˜Kšžœ&žœ žœžœ5˜”K˜K˜�—š œžœžœžœ˜;Kšžœ˜Kšœ˜—K˜�Kšœ;˜;šœžœžœžœ%˜bKšžœžœžœžœ$˜SKšžœb˜fK˜K˜�—šžœžœžœžœ˜0šœžœž˜K˜ K˜K˜Kšžœžœ˜K˜�——šœžœžœžœ˜CKšœ0™0K™Kšœ ˜Kšœ˜K˜�—š œžœžœžœžœ˜0Kšœžœ žœžœ˜"K˜�—Kšœžœžœ˜šœžœžœ*˜Gšžœžœžœ˜*Kšœžœ˜)KšœA˜AKšœ-˜-šžœžœž˜šœ ˜ K˜+Kšœžœ!˜)Kšœžœ˜%šœ˜Kšœ žœžœžœ˜5Kšœ˜—Kšœ˜—Kšœ"˜"Kšœžœžœžœ˜TKšžœžœ˜—Kšœ˜Kšœ%˜%K˜—šžœ˜šžœžœž˜KšœQžœ˜XKšœTžœ˜[KšœSžœ˜ZKšžœžœ˜—K˜—K˜K˜�—šœžœžœ(˜IKšœA˜AKšœ˜šžœžœžœ˜*Kšœ%˜%K˜—šžœ˜KšœZžœ˜aK˜—K˜K˜�—šœžœžœžœ˜@šžœžœžœ˜*KšœA˜AKšœ-˜-Kšœ%˜%K˜—Kšžœ7žœ˜BK˜K˜�—Kšœžœ˜!Kšœžœ'˜6šœžœ3˜HKšœ4™4K˜Kšžœžœ?™\Kšžœžœžœ %˜SKšœ˜šžœž˜šœ ˜ KšœP˜PKšœP˜PKšœ˜—Kšœ žœ˜Kšžœžœ˜—KšœS˜SKšžœ˜K˜�—š œžœžœžœžœ˜GKšœ;™;KšœA˜AKšœ:˜:K˜K˜�—šœžœžœžœ5˜sKšžœžœžœžœH˜wKšžœe˜iK˜K˜�—šœžœžœ5˜YKšœ8˜8šžœžœžœ˜*Kšœ4˜4KšœQ˜QKšžœ˜K˜—Kšœfžœ˜mKšœLžœžœ +˜…K˜—K™�K™K™�Kšœ žœžœ˜'Kšœžœ˜.šœžœžœ˜Sšœžœ žœ žœ žœžœžœžœžœžœžœ˜yšžœžœ˜Kš œžœžœžœžœ˜&Kšœžœ1˜LK˜—K˜—šœžœ žœ žœ žœžœžœžœžœžœžœ˜zšžœžœ˜Kš œžœžœžœžœ˜&Kšœžœ˜6K˜—K˜—šœžœ žœ žœ žœžœžœžœžœžœžœ˜yšžœžœ˜Kš œžœžœžœžœ˜&Kšœžœ˜8K˜—K˜—šœžœ žœ žœ žœžœžœžœžœžœžœ˜|šžœžœ˜Kš œžœžœžœžœ˜&Kšœžœ ˜>K˜—K˜—Kšœžœžœžœžœžœ˜9šžœž˜"KšžœL˜P—šžœž˜#KšžœN˜R—šžœ ž˜%KšžœR˜V—šžœž˜"KšžœL˜P—Kšœ1˜1K˜—K˜�Kšœžœ˜,šœžœžœ.žœ˜Yšžœž˜Kšœ žœžœžœL˜~Kšœ žœžœžœL˜~Kšœ žœ žœžœM˜Kšœžœ"žœžœO˜‹Kšžœ˜—K˜K˜�—šœžœžœ*˜Ošœžœ žœ žœ žœžœžœžœžœ žœžœžœ˜†Kšœ˜K˜—KšœA˜AKšœ@˜@K˜K˜�—šœžœ'žœ!˜jšœ žœž˜Kšœ%˜%Kšœ%˜%Kšœ'˜'Kšœ/˜/Kšžœžœ˜—K˜K˜�—šœžœžœžœžœ žœžœžœ˜“š œžœ žœ žœ žœžœžœžœžœžœžœžœžœžœžœžœ˜ºKš œžœžœžœžœ˜&Kšœ žœ ˜šžœžœžœ˜&Kšœžœ˜Kšœ˜Kšœ˜Kšœžœ˜K˜—Kšžœ˜Kšœ˜K˜—KšœA˜AK˜�Kšœ;˜;K˜K˜�—šœžœžœžœ žœžœžœžœžœžœ˜eK™7šœžœ žœ žœ žœžœžœžœžœžœžœ˜sKš œžœžœžœžœ˜&Kšœ?˜?Kšœ6˜6K˜—Kšœ žœžœžœ˜Kšœ žœžœžœ˜Kšœ/˜/Kšœ*˜*KšžœžœžœF˜oKšœ˜K˜�K˜�—š œžœžœžœžœžœžœ˜]Kš žœžœžœžœžœ˜;Kšœ Ÿœ8˜Mšžœžœ˜&K•StartOfExpansionB[gargoyleData: REF ANY, msg: ROPE, msgType: GGError.MsgType]šœ[˜[Kšœ˜Kšœ žœ˜Kšžœ˜K˜—Kšœ&˜&KšŸ™Kšžœ žœ˜,Kšžœžœ˜$KšŸ'™'KšžœBžœ)žœ)˜žKšœ˜K˜�—š œžœžœžœ˜>Kšœ(˜(KšžœžœžœB˜iK˜K˜�—š œžœžœžœžœ˜LKšžœžœžœž˜5Kšžœ5˜9K˜K˜�—šœžœžœžœžœžœžœžœ˜gKšœ/˜/Kš žœžœžœžœžœ˜7KšœSžœžœžœžœžœ˜›Kšœ žœ˜$K˜K˜�—š"œžœžœ žœžœžœžœ žœžœžœžœžœžœžœžœžœžœ˜¡Kšœžœžœ˜Kšœžœ˜Kšœžœ˜Kšœ6˜6šžœžœ žœž˜6Kš œžœ žœžœžœ ˜GKšœžœ žœžœžœžœ5™XKšœ žœžœžœžœžœ ˜.Kš œCžœžœžœžœ.˜‰Kšžœ žœžœ˜'Kšžœžœžœ˜Kšžœ˜—K˜K˜�—šœžœžœžœžœžœžœžœž œ˜]Kšœžœžœ˜*Kšœžœžœžœ˜Kšœžœžœžœ˜Kšžœžœžœžœ˜1Kšœ-žœ˜?Kšœ0˜0Kšœ*žœ˜AKšœ9žœ˜@Kšœ]žœ˜nK˜K˜�—šœžœžœžœžœžœžœžœžœžœ˜]Kšœžœžœ˜!Kšžœžœžœžœ˜1Kšœ-žœ˜?Kšœ]žœ˜nK˜—K˜�šœžœžœžœžœžœžœžœžœžœ˜ŽK™ŽKšœžœžœžœ˜ Kšœžœžœ˜Kšœ˜šž˜Kšœ9˜9Kšžœžœžœ˜šžœ ž˜KšœH˜HKšœK˜K˜ Kšœžœžœ˜/šžœžœžœ˜ Kšœ@˜@K˜K˜—šžœ˜Kšœ@˜@K˜K˜—Kšœ˜K˜—Kšžœžœ˜—Kšžœžœžœ0˜LKšžœ˜—K˜K˜�—š œžœžœžœžœžœžœ$žœžœ˜Kšœ žœ ˜šžœ žœžœ˜Kš žœ žœžœ žœžœ˜9Kšžœžœ˜ K˜—Kšžœ žœžœžœ˜-šžœžœ˜Kšžœ1žœ˜FKšžœžœ1žœ˜NKšžœ˜K˜—šžœ˜Kšžœ1žœ˜IKšžœžœ1žœ˜KKšžœ˜K˜—K˜K˜�—šœžœžœžœžœ"žœžœ˜ƒK™WKšœ ˜,Kšœžœ ˜#Kšžœžœžœ'žœ˜GKšœ˜Kšœ !˜2Kšœ ˜)K˜K˜�—šœžœžœžœ žœžœžœžœžœžœ˜ešœžœ žœ žœ žœžœžœžœžœžœžœ˜sKš œžœžœžœžœ˜&Kšœ?˜?Kšœ6˜6K˜—Kšœ žœžœžœ˜Kšœ žœžœžœ˜Kšœ/˜/Kšœ*˜*KšžœžœžœF˜oKšœ˜K˜�—š œžœžœžœžœžœžœ˜]Kš žœžœžœžœžœ˜;KšœM˜Mšžœžœ˜K–B[gargoyleData: REF ANY, msg: ROPE, msgType: GGError.MsgType]šœ[˜[Kšœ˜Kšœ žœ˜Kšžœ˜K˜—Kšœ&˜&Kšžœžœ˜$KšŸ7™7KšžœBžœ)žœ)˜žKšœ˜K˜�—š œžœžœžœ˜>Kšœ(˜(KšžœžœžœB˜iK˜K˜�—š œžœžœžœžœ˜LKšžœžœžœž˜5Kšžœ5˜9K˜K˜�—šœžœžœžœžœžœžœžœ˜gKšœ/˜/Kš žœžœžœžœžœ˜7Kšœožœžœžœžœžœ!˜¾Kšœ žœ˜$K˜K˜�—šœžœžœžœžœžœžœžœžœžœ˜]Kšœžœžœ˜*Kšœžœžœžœ˜Kšœžœžœžœ˜Kšžœžœžœžœ˜1Kšœ-žœ˜?Kšœ0˜0Kšœ*žœ˜AKšœ9žœ˜@Kšœ]žœ˜nK˜K˜�—šœžœžœžœžœžœžœžœžœžœ˜]Kšœžœžœ˜!Kšžœžœžœžœ˜1Kšœ-žœ˜?Kšœ]žœ˜nK˜—K˜�šœžœžœžœ žœžœžœ žœžœžœžœžœžœ˜€K™>š œžœ žœ žœ žœžœžœžœžœžœžœ˜tKš œžœžœžœžœ˜&Kšœ&˜&Kšœ?˜?Kšœ6˜6K˜—K˜Kšœ žœžœžœ˜Kšœ žœžœžœ˜Kšœ%˜%Kšœ/˜/Kšœ*˜*Kšžœ žœžœH˜rKšœ˜Kšœ˜K˜�—šœžœžœžœ žœžœžœ˜]Kš žœžœžœžœžœ˜<KšœU˜Ušžœžœ˜K–B[gargoyleData: REF ANY, msg: ROPE, msgType: GGError.MsgType]šœ\˜\Kšœ ˜ Kšœ žœ˜Kšžœ˜K˜—KšŸ8™8KšžœBžœ)žœ)˜žKšœ˜K˜�—šœžœžœžœ˜>Kšœ(˜(KšžœžœžœB˜jK˜K˜�—š œžœžœžœžœ˜MKšžœžœžœž˜6Kšžœ6˜:K˜K˜�—š œžœžœžœ žœžœžœžœžœ˜xKšœ/˜/Kš žœ žœžœžœžœ˜8Kš œ~žœžœžœžœ ˜¿Kšœ žœ˜$K˜K˜�—š œžœžœžœžœžœ žœžœžœžœžœžœžœ˜vKšœžœžœ˜*Kšœ žœžœžœ˜Kšœžœžœžœ˜Kšœžœžœžœ˜Kšžœ žœžœžœ˜2Kšœ@˜@Kšœ;˜;KšœG˜GKšœ9žœ˜?Kšœ^žœ˜oK˜K˜�—š œžœžœžœžœžœ žœžœžœžœžœžœžœ˜vKšœžœžœ˜!Kšžœ žœžœžœ˜2Kšœ@˜@Kšœ^žœ˜oK˜—K˜�šœžœžœžœ žœžœžœ žœžœžœžœžœžœ˜†K™>šœžœ žœ žœ žœžœžœžœžœžœžœ˜vKš œžœžœžœžœ˜&Kšœ&˜&Kšœ?˜?Kšœ6˜6K˜—K˜Kšœ žœžœžœ˜Kšœ žœžœžœ˜Kšœ%˜%Kšœ/˜/Kšœ*˜*Kšžœ"žœžœL˜xKšœ˜Kšœ˜K˜�—šœžœžœžœžœžœžœ˜eKš žœ žœžœžœžœ˜>KšœQ˜Qšžœžœ˜ K–B[gargoyleData: REF ANY, msg: ROPE, msgType: GGError.MsgType]šœc˜cKšœ˜Kšœ žœ˜Kšžœ˜K˜—KšŸ:™:KšžœFžœ-žœ-˜ªKšœ˜K˜�—šœžœžœžœ˜FKšœ,˜,Kšžœ žœžœF˜pK˜K˜�—š œžœžœžœžœ˜SKšžœžœžœž˜8Kšžœ8˜<K˜K˜�—šœžœžœžœžœžœžœžœžœ˜€Kšœ/˜/Kš žœ"žœžœžœžœ˜:Kš œ‚žœžœžœžœ"˜ÇKšœ žœ˜$K˜K˜�—šœžœžœžœžœžœ žœžœžœžœžœžœžœ˜€Kšœžœžœ˜*Kšœ žœžœžœ˜Kšœžœžœžœ˜Kšœžœžœžœ˜Kšžœ"žœžœžœ˜4KšœF˜FKšœA˜AKšœI˜IKšœ9žœ˜?Kšœ`žœ˜qK˜K˜�—šœžœžœžœžœžœ žœžœžœžœžœžœžœ˜€Kšœžœžœ˜!Kšžœ"žœžœžœ˜4KšœF˜FKšœ`žœ˜qK˜—K˜�š œžœ žœžœ žœ˜?Kšœžœ˜Kšœžœ ˜)Kšœ$ ˜?K–9[base: ROPE, start: INT _ 0, len: INT _ 2147483647]šŸ™Kšžœ8žœEžœ˜ŒKšŸ ™ Kšžœ9žœD˜ƒK˜K˜�—š œžœžœžœžœ™=Kš žœ"žœžœžœžœ™9Kšžœžœ=™HK™K™�—šœžœžœžœ™AKšžœ"žœžœI™uK™K˜�—š œžœžœžœžœ˜=Kšžœžœžœ žœžœžœžœ˜Pšžœž˜KšœžœF˜NKšœ žœž˜Kšžœžœžœžœžœ #˜CKšœžœ˜Kšžœ˜K˜—K˜K˜�—šœžœžœžœ˜AKš žœžœžœžœžœ˜KKšœ%žœ žœžœ&˜hK˜K˜�—š œžœžœžœžœ˜DKšžœ˜K˜—šœžœžœžœ˜FKšœ˜K˜—K˜�š œžœžœžœžœ™BKš žœžœžœžœžœ™5Kšžœžœ9™DK™K™�—šœžœžœ"žœ™IKšžœžœžœžœ™0KšœG™GKšœžœ™2K™K™�—š œžœžœžœžœ˜BKšžœžœžœ žœžœžœžœ˜Pšžœž˜KšœžœK˜SKšœ žœž˜Kšžœžœžœžœžœ #˜CKšœžœ˜Kšžœ˜K˜—K˜K˜�—šœžœžœ"žœ˜IKš žœžœžœžœžœ˜KKšœ*žœžœžœ&˜pKšœžœ˜2K˜K˜�—Kšœžœžœžœžœžœ˜"Kšœžœžœžœžœžœ˜$K˜�š œžœžœžœžœ˜@Kšžœžœžœ žœžœžœ"˜lšžœž˜KšœžœI˜QKšœ žœž˜Kšžœžœžœžœžœ #˜CKšœžœ˜Kšžœ˜K˜—K˜K˜�—šœžœžœ žœ˜Ešžœžœžœžœ˜EKšœ0˜0Kšžœ˜K˜—Kšœ(žœžœžœ&˜lšžœžœ˜Kšœ'˜'Kšœ'˜'K˜—K˜K˜�—š œžœžœžœžœ™@Kšžœžœžœ žœžœžœžœ™PKšžœžœ;™FK™K™�—šœžœžœ žœ™EKš žœžœžœžœžœ™KKšœG™Gšžœžœ™Kšœ'™'Kšœ'™'K™—K™K˜�—K™�K™K™�š œžœžœžœžœ˜:Kšžœžœžœžœžœž˜+Kšžœ žœžœžœ˜Išžœž˜KšœžœC˜KKšœ žœž˜Kš žœžœžœžœžœ˜šžœ˜Kšœžœ˜Kšžœ˜K˜—K˜—K˜K˜�—š œžœžœžœ˜;Kšžœžœžœžœ˜%Kšžœ žœžœ"˜LKšžœ#žœ žœžœ&˜gK˜K˜�—š œžœžœžœžœ˜<Kšžœžœžœ žœžœžœ˜hšžœž˜Kšœ žœžœ˜KšœžœE˜MKšžœžœžœžœ˜7Kšœžœ˜Kšžœžœ˜K˜—K˜K˜�—šœžœžœžœ˜=Kšœ(˜(Kšžœžœžœ žœžœžœ˜KKšœ$žœ žœžœ%˜dK˜—K˜�š œžœžœžœžœ˜;Kš žœžœžœžœžœ˜,Kšžœ žœžœžœ˜Jšžœž˜KšœžœD˜LKšœ žœž˜Kš žœžœžœžœžœ˜ Kšœžœ˜Kšžœ˜K˜—K˜K˜�—š œžœžœžœ˜=K™bKšœžœ˜ Kšœ žœžœ˜K™Kšžœžœžœžœ˜%Kšžœ žœžœ$˜NKšžœ$žœžœžœ&˜iK™šžœžœ˜KšœžœŽ˜§Kšœžœ>˜_K˜—šžœ˜Kšœ0žœ˜BKšžœžœžœ$žœ˜GK˜—Kšžœžœžœ˜*K˜K˜�—š œžœžœžœžœ™;Kšžœ!žœžœžœ™KKšžœžœ<™GK™K™�—šœžœžœžœ˜?K™bKšœžœ˜ Kšœ žœžœ˜Kšžœ!žœžœ$˜OKšžœF˜Jšžœžœ˜KšœžœŠ˜£Kšœžœ>˜_K˜—šžœ˜Kšœ0žœ˜BKšžœžœžœ$žœ˜GK˜—K˜Kš˜—K˜�K™K™�šœžœžœžœ˜CKšžœ˜Kšœ˜K˜�—šœžœžœ,˜DKšœ˜Kšœ˜K˜�—šœžœžœžœ™HKšžœ™#Kšœ™K™�—šœžœžœ1™MKšœžœ™šœžœž™#Kšœ™Kšœ™Kšžœžœ™—KšœO™OKšœ*™*Kšœ™K™�—šœžœžœžœ˜Išœžœž˜Kšœ˜Kšœ˜Kšœ˜Kšžœ ˜—K˜K˜�—šœžœžœžœ˜Išœžœž˜Kšœ˜Kšœ˜Kšžœžœ˜—K˜K˜�—šœžœžœžœ˜HKšœ=™=Kšžœžœžœ žœžœžœ˜Qšžœž˜KšœžœH˜PKšœžœ˜Kš žœžœžœžœ #˜DKšœžœ˜Kšžœ˜#K˜—Kšœ˜K˜�—šœžœžœ1˜MKšœ=™=Kšœ žœ˜Kšœ.˜.KšœO˜OKšœ*˜*Kšœ˜K˜�—šœžœžœžœ˜BKšœžœ˜Kšœ˜Kšœžœ˜ KšœK˜KKšœ žœ˜šžœ žœ˜šœžœž˜Kšœ#˜#Kšœ˜Kšœ˜Kšžœ˜—K˜—šžœ˜šœžœž˜Kšœ˜Kšœ#˜#Kšœ˜Kšžœ˜—K˜—KšœO˜Ošžœ ž˜šœ˜Kšœ˜Kšœ˜Kšœ˜—šœ˜Kšœ˜Kšœ˜Kšœ˜—šœ ˜ Kšœ˜Kšœ˜Kšœ˜—Kšžœžœ˜—K˜K˜�—šœžœžœ1™MKš ÐbkŸ¡Ÿ¡Ÿ¡Ÿ¡Ÿ¡Ÿ¡™"Kšœ<™<Kšœžœ™šœžœž™#Kšœ™Kšœ™Kšžœžœ™—Kšœ™šžœžœž™+Kšœžœ™5Kšœ™Kšžœ™—Kšœ*™*Kšœ™K™�—šœžœžœžœ™BKšœžœ™Kšœ<™<Kšœ™Kšžœ žœžœ™DKšžœžœ™;Kšœ™šžœžœž™šœ#žœ™-Kšœ™Kšœ™Kšœ™—šœ#žœ™-Kšœ™Kšœ™Kšœ™—šœžœ™&Kšœ™Kšœ™Kšœ™—Kšžœžœ™—K™K˜�—šœžœžœžœ žœ#žœ žœ˜ƒKšœ ˜ Kšœ"˜"Kšœ ˜ Kšœ ˜ K˜—šœžœžœžœ#žœ žœ˜zKšœ ˜ Kšœ"˜"Kšœ ˜ Kšœ ˜ K˜—šœžœžœžœ˜WKšœ&˜&K˜—šœžœžœ.˜NKšœ&˜&K˜—šœžœžœžœ ˜[Kšœ*˜*K˜—šœžœžœ0˜RKšœ*˜*K˜—šœžœžœžœ˜ZKšœ*˜*K˜—šœžœžœ/˜QKšœ*˜*K˜—šœžœžœžœ˜TKšœ&˜&K˜—šœžœžœ+˜KKšœ&˜&K˜—š œžœžœžœžœ>˜Kšœ,˜,Kšœ4˜4Kšœ2˜2K˜—šœžœžœ žœ>˜„Kšœ,˜,Kšœ4˜4Kšœ2˜2K˜—šœžœžœžœ˜MKšœ ˜ K˜—šœžœžœ)˜DKšœ ˜ K˜—K˜�K™K™�š œžœžœžœžœ˜;Kšžœžœžœ žœžœžœžœ˜Pšžœž˜KšœžœD˜LKšœ žœž˜Kšžœžœžœžœžœ #˜CKšœžœ˜Kšžœ˜K˜—K˜K˜�—š œžœžœžœ˜=Kš žœžœžœžœžœ˜KKšœ#žœžœžœ&˜dKšœ˜K˜K˜�—š œžœžœžœžœ™;Kš žœžœžœžœžœ™5Kšžœžœ9™DK™K™�—š œžœžœžœ™=Kšžœžœžœžœ™0KšœB™BKšœ™K™K™�—š œžœžœžœ žœ˜IKšœžœ˜Kš žœžœžœ žœžœ5˜xšžœž˜KšœžœJ˜RKšžœžœžœ5˜Fšžœ˜Kšœ žœžœžœ˜$Kšœ˜—K˜—Kšœ˜K˜K˜�—šœžœžœžœ˜@Kšœžœ˜Kšœ žœžœ˜K˜�Kš žœžœžœžœžœ˜KKšœ˜Kšœ žœžœ˜!KšœP˜PK˜�Kšœ˜K˜K˜�—š œžœžœžœ žœ™IKšœžœ™KšœT™TK™�Kšžœžœžœ5™Pšžœ™Kšœ(™(Kšœžœ4™@Kšœ™K™—Kšœ™K™K™�—šœžœžœžœ™@Kšœžœ™KšœT™TK™(K™�Kšžœžœžœžœ™#Kšœ™Kšœžœ?™HKšœB™BKšœ™K™K˜�—K˜�šœžœžœžœ˜Mšœžœžœž˜Kšœ(˜(Kšœ&˜&Kšžœ˜—K˜K˜�—šœžœžœžœ˜Mšœžœ ž˜Kšœ!˜!Kšœ/˜/Kšžœžœ˜—K˜K˜�—šœžœžœžœ˜SKšžœžœžœ žœžœžœ˜[šžœž˜KšœžœH˜PKšœžœ˜Kš žœžœžœžœ #˜NKšœžœ˜Kšžœ˜"K˜—K˜K˜�—šœžœžœ/˜JKšœž˜Kš žœžœžœžœžœ˜KKšœ(˜(KšœK˜KKšœ)˜)Kšœ˜K˜K˜�—šœžœžœžœ˜AKšœ˜Kš žœžœžœžœžœ˜KKšœ%˜%Kšœžœžœžœ˜XKšœ$˜$Kšœ)˜)Kšœ˜K˜K˜�—šœžœžœžœ™AKšœ@™@šžœžœžœ™Kšžœ žœžœ™DKšžœžœ™;K™—šœ™šžœžœž™Kšœ0žœ™IKšœ/žœ™GKšžœžœ™——Kšœ™K™K™�—šœžœžœžœ™SKšžœ™#K™K™�—šœžœžœ/™JKš ¡Ÿ¡Ÿ¡Ÿ¡Ÿ¡Ÿ¡Ÿ¡™"Kšœ@™@Kšœžœ™šœžœ ž™"Kšœ"™"Kšœ0™0Kšžœžœ™—šžœžœžœ™Kšœ™šžœžœž™+Kšœžœ™5Kšœ™Kšžœ™—K™—Kšœ)™)Kšœ™K™K™�—š œžœžœžœžœ˜>Kšžœžœžœ žœžœžœžœ˜Qšžœž˜KšœžœA˜IKšœ žœž˜Kšžœžœžœžœžœ #˜DKšœžœ˜Kšžœ˜K˜—K˜K˜�—š œžœžœ žœ˜CKš žœžœžœžœžœ˜KKšœ žœžœžœ&˜dK˜K˜�—š œžœžœžœžœ™>Kš žœ$žœžœžœžœ™<Kšžœžœ?™JK™K™�—š œžœžœ žœ™CKšžœ$žœžœžœ™6KšœK™KK™K˜�—š œžœžœžœžœ˜=Kšžœ˜!Kšœ˜K˜�—šœžœžœžœ˜Qšžœžœ˜Kš œ žœžœžœžœ˜6Kšœ! ˜2šžœ žœžœ˜K–?[slice: GGModelTypes.Slice, parts: GGModelTypes.SliceParts]šœžœžœR˜{Kšœ œ ˜.K˜—Kšœ˜—Kšœ˜K™�—š œžœžœ(˜IKšœ™KšœÂ™ÂKšœžœžœ˜:šžœž˜šœŸœ˜Kšœ žœžœžœ˜0Kšœ> ™RK˜—Kšžœ˜—K˜—K˜�šœžœ˜,šžœž˜šžœžœž˜*KšœD˜DKšœR˜RKšžœžœ˜—Kšžœ5žœ ˜TKšžœ˜—K˜—K˜�K™K˜�šœžœžœžœ˜TKšžœ˜"K˜—šœžœžœ.˜KKšœ#˜#K˜—K™�K™K˜�š œžœžœžœ˜PKšžœ˜ K˜K˜�—š œžœžœ-˜GKšœ%˜%K˜K˜�—š œžœžœžœ˜PKšžœ˜K˜K˜�—š œžœžœ-˜GKšœ$˜$K˜K˜�—š œžœžœžœžœ˜5Kšžœ˜K˜K˜�—šœžœžœžœ˜-Kšœ˜K˜—K˜�Kšœžœžœ ˜=K˜�šœžœžœžœ#˜[Kšœ4˜4K˜K˜�—šœžœžœ3˜RKšœ4˜4K˜K˜�—K™K˜�Kšœžœžœ™"š œžœžœžœžœ™6Kšžœ™K™—K˜�K™šœžœžœžœ˜FK™5K™&Kš œžœžœžœžœ˜oK˜K˜�—š œžœžœžœžœ˜WKšœžœ*˜:Kšœžœžœ žœ;˜zK˜K˜�—š œžœžœžœžœ˜UKš œ%˜2K˜K˜�—š œžœžœ˜/Kšœžœ˜%Kšœžœžœžœ˜(KšœB˜BKšœ*˜*KšœH˜HK˜K˜�—š œžœžœžœžœžœ˜JKšœ™Kšœžœžœžœžœžœ˜qKšžœ"žœm˜•Kšžœžœžœžœn˜Kšžœžœ˜K˜K˜�—šœžœ%žœ˜DKšœ_˜_Kšœ_˜_Kšœc˜cK˜K˜�—š œžœžœ"˜UKšœ ˜ K˜K˜�—šœžœ˜0Kšœ:˜:K˜K˜�—š œžœžœ žœ "˜bKšœ&˜&K˜K˜�—š œžœžœ žœ "˜dKšœ'˜'K˜K™�—šœžœžœžœ˜:Kšœžœ˜Kšœ ˜ Kšœžœ˜šžœ ž˜Kšœ;˜;Kšœ;˜;Kšœ7˜7Kšžœ3˜:—šžœ˜ K™Kšžœ>žœžœ ˜cKšžœžœ%˜>K˜—šžœ˜Kšœ<žœ1žœ˜xK™Kšœ\˜\K˜—Kšœ@˜@Kšœ'žœ žœ ˜WKšœ)žœ˜0Kšœ ˜7KšœC˜CK˜K˜�—š œžœžœžœžœ˜OKšœ˜K˜Kšœžœ˜Kšœ=™=KšœG˜GKšœc˜cšœ3˜3šœžœ˜Kšœ žœ˜Kšœ=˜=Kšžœ˜ —šœ˜Kšœ žœ˜KšœC˜CKšžœ˜——šžœ žœ˜Kšžœžœžœžœ˜Kšœ7˜7Kšœo™oKšœ&˜&Kšœ˜—Kšžœ;˜?K˜K˜�—šœžœ˜1šœ˜Kšœ#˜#Kšœ ˜ Kšœ˜Kšœ žœ˜—K˜K˜�—š œžœ˜,Kšœžœ˜Kšœ˜Kšœg˜gKš žœžœ3žœ žœ žœ˜jKšœI˜IK˜—K˜�šœžœžœ˜;šžœœžœ˜,KšœL˜Lšžœ$žœžœ?˜tKšœd˜d—K˜—Kšžœžœžœžœžœžœžœžœ˜dšžœžœ#žœ˜/KšŸ4™4Kšœ/˜/KšœQ˜QKš œžœžœžœžœ˜gKšœ#žœ *˜SKšœ$žœ˜)šžœ!žœžœ ˜?Kšœ.Ÿœ˜7—šžœ-žœ˜6šžœ žœžœ ˜>Kšœ-Ÿœ˜6—K˜—K˜—K˜K˜�—Kšžœ˜K˜�J˜�—�…—����Ê„��1µ�