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]; }; <) 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šœ(˜(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šœ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šœ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š žœ$žœžœžœžœ™ ™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΅