DIRECTORY AtomButtons, AtomButtonsTypes, Basics, BiScrollers, BufferedRefresh, Buttons, Commander, Containers, Feedback, FunctionCache, Geom2D, GGAlign, GGBasicTypes, GGBoundBox, GGCaret, GGContainer, GGFont, GGGravity, GGInterfaceTypes, GGMenu, GGModelTypes, GGMouseEvent, GGMultiGravity, GGOutline, GGRefresh, GGScene, GGSegmentTypes, GGSelect, GGSequence, GGShapes, GGSlice, GGTraj, GGUserInput, GGUtility, GGWindow, GraphicsButton, Icons, Imager, ImagerTransformation, InputFocus, IO, Labels, Match, MatchGrep, MatchViewer, Rope, SlackProcess, TIPUser, ViewerClasses, ViewerOps; MatchViewerImpl: CEDAR PROGRAM IMPORTS AtomButtons, Basics, BiScrollers, BufferedRefresh, Buttons, Commander, Containers, Feedback, FunctionCache, Geom2D, GGAlign, GGBoundBox, GGCaret, GGFont, GGGravity, GGMenu, GGMouseEvent, GGMultiGravity, GGOutline, GGRefresh, GGScene, GGSelect, GGSequence, GGSlice, GGShapes, GGTraj, GGUserInput, GGUtility, GGWindow, GraphicsButton, Icons, Imager, ImagerTransformation, InputFocus, IO, Labels, Match, MatchGrep, Rope, TIPUser, ViewerOps EXPORTS MatchViewer = BEGIN CameraObj: TYPE = GGModelTypes.CameraObj; Caret: TYPE = REF CaretObj; CaretObj: TYPE = GGInterfaceTypes.CaretObj; ChoiceDataObj: TYPE = MatchViewer.ChoiceDataObj; FeedbackData: TYPE = Feedback.FeedbackData; FiltersObj: TYPE = GGInterfaceTypes.FiltersObj; GGDataObj: TYPE = GGInterfaceTypes.GGDataObj; GGData: TYPE = GGInterfaceTypes.GGData; MatchData: TYPE = MatchViewer.MatchData; MatchDataObj: TYPE = MatchViewer.MatchDataObj; Point: TYPE = GGBasicTypes.Point; Sequence: TYPE = GGModelTypes.Sequence; Scene: TYPE = GGModelTypes.Scene; Slice: TYPE = GGModelTypes.Slice; SliceDescriptor: TYPE = GGModelTypes.SliceDescriptor; SliceDescriptorGenerator: TYPE = GGModelTypes.SliceDescriptorGenerator; Traj: TYPE = GGModelTypes.Traj; Viewer: TYPE = ViewerClasses.Viewer; actionAreaHeight: CARDINAL = 200; -- height of action area biscroller viewer actionAreaMargin: CARDINAL = 3; -- distance between two action areas actionAreaStartY: CARDINAL = entryHeight; buttonAlign: CARDINAL = 2; -- vertical alignment differential for the 2 kinds of buttons used entryHeight: CARDINAL = 15; -- height of a line of items entryHSpace: CARDINAL = 2; -- space between ButtonLines on same line entryVSpace: CARDINAL = 2; -- vertical leading between lines InitViewers: PROC [] = { matchContainerClass: ViewerClasses.ViewerClass _ NEW[ViewerClasses.ViewerClassRec _ [ init: MatchContainerInit, adjust: MatchContainerAdjust, topDownCoordSys: TRUE, icon: matchToolIcon ]]; ViewerOps.RegisterViewerClass[$MatchContainer, matchContainerClass]; -- plug in to Viewers [] _ ViewerOps.CreateViewer [flavor: $MatchContainer, info: [name: "MatchTool", menu: NIL, iconic: FALSE, column: right, scrollable: FALSE ], paint: TRUE]; }; fromViewer, toViewer: Viewer _ NIL; fromData, toData, grepData: GGData _ NIL; fromLine, toLine: Viewer _ NIL; MatchContainerInit: ViewerClasses.InitProc = { fromData _ BuildDefaultGGData[self]; toData _ BuildDefaultGGData[self]; grepData _ BuildDefaultGGData[self]; -- this data is used to search scenes during grep CreateFeedbackLine[toData, fromData, grepData]; fromViewer _ BuildActionArea[self, fromData]; toViewer _ BuildActionArea[self, toData]; fromLine _ BuildActionAreaLine[fromData, 0]; toLine _ BuildActionAreaLine[toData, 0]; InitControlPanel[self, actionAreaStartY + actionAreaHeight + entryHeight + upperMargin]; }; GetFromData: PUBLIC PROC RETURNS [GGData] = { RETURN[fromData]; }; GetToData: PUBLIC PROC RETURNS [GGData] = { RETURN[toData]; }; GetGrepData: PUBLIC PROC RETURNS [GGData] = { RETURN[grepData]; }; BuildDefaultGGData: PROC [outer: Viewer] RETURNS [ggData: GGData] = { ggData _ NEW[GGDataObj _ matchData.hostData^]; ggData.biScroller _ NIL; outer.data _ ggData; ggData.outer _ outer; ggData.hitTest _ NEW[FiltersObj _ matchData.hostData.hitTest^]; ggData.hitTest.triggerBag _ GGAlign.CreateTriggerBag[]; ggData.hitTest.sceneBag _ GGAlign.CreateTriggerBag[]; ggData.hitTest.alignBag _ GGAlign.CreateAlignBag[]; ggData.refresh.lineCache _ FunctionCache.Create[maxEntries: 200]; ggData.scene _ GGScene.CreateScene[]; ggData.caret _ NEW[CaretObj]; ggData.anchor _ NEW[CaretObj]; ggData.camera _ NEW[CameraObj]; GGMouseEvent.InitializeFSM[ggData]; ggData.drag.savedCaret _ NEW[CaretObj]; ggData.drag.selectState _ none; ggData.drag.extendMode _ none; ggData.refresh.startBoundBox _ GGBoundBox.NullBoundBox[]; ggData.refresh.sandwich _ GGRefresh.CreateSandwich[]; ggData.defaults _ NEW[GGInterfaceTypes.DefaultDataObj _ [strokeColor: Imager.black, fillColor: GGOutline.fillColor, font: GGFont.DefaultDefaultFontData[] ] ]; ggData.height _ 0; ggData.outer.newVersion _ FALSE; ggData.gravityPool _ GGGravity.NewGravityPool[]; ggData.multiGravityPool _ GGMultiGravity.NewMultiGravityPool[]; }; CreateFeedbackLine: PROC [data1, data2, grepData: GGData] = { GGMenu.BuildFeedbackLine[data1]; grepData.feedback _ data2.feedback _ data1.feedback; data2.height _ data2.height + entryHeight; -- data1 was incremented by BuildFeedbackLine }; MatchContainerAdjust: ViewerClasses.AdjustProc = { margin1: CARD _ (self.ww - actionAreaMargin) / 2; margin2: CARD _ (self.ww + actionAreaMargin) / 2; IF fromViewer # NIL THEN ViewerOps.MoveViewer[fromViewer, 0, fromViewer.wy, margin1, fromViewer.wh, FALSE]; IF toViewer # NIL THEN ViewerOps.MoveViewer[toViewer, margin2, toViewer.wy, margin1, toViewer.wh, FALSE]; IF fromLine # NIL THEN ViewerOps.MoveViewer[fromLine, fromLine.wx, fromLine.wy, margin1, fromLine.wh, FALSE]; IF toLine # NIL THEN ViewerOps.MoveViewer[toLine, margin2, toLine.wy, margin1, toLine.wh, FALSE]; }; BuildActionArea: PRIVATE PROC [outer: Viewer, ggData: GGData] RETURNS [Viewer] = { actionAreaClass: BiScrollers.BiScrollerClass _ BiScrollers.GetStyle[].NewBiScrollerClass[[ flavor: $ActionArea, extrema: GGExtremaProc, notify: GGUserInput.InputNotify, paint: GGActionAreaPaint, tipTable: TIPUser.InstantiateNewTIPTable["Gargoyle.TIP"], mayStretch: FALSE, -- NOT OK to scale X and Y differently offsetsMustBeIntegers: TRUE, preferIntegerCoefficients: FALSE, preserve: [X: 0.5, Y: 0.5] --this specifies point that stays fixed when viewer size changes ]]; bs: BiScrollers.BiScroller _ BiScrollers.GetStyle[].CreateBiScroller[ class: actionAreaClass, info: [ parent: ggData.outer, wx: 0, wy: actionAreaStartY, ww: 700, --ggData.outer.ww, wh: actionAreaHeight, --ggData.outer.wh, data: ggData, border: TRUE, scrollable: FALSE], paint: FALSE ]; ggData.actionArea _ bs.QuaViewer[inner: TRUE]; ggData.biScroller _ bs; GGWindow.SetCursorLooks[ggData.hitTest.gravityType, ggData]; -- assumes gravity is turned ON ggData.height _ ggData.height + actionAreaHeight; RETURN[bs.QuaViewer[inner: FALSE]]; }; GGExtremaProc: PROC [clientData: REF ANY, direction: Geom2D.Vec] RETURNS [min, max: Geom2D.Vec] --BiScrollers.ExtremaProc-- = { area: Geom2D.Rect; ggData: GGData _ NARROW[clientData]; bigBox: GGBoundBox.BoundBox _ GGBoundBox.BoundBoxOfBoxes[GGScene.BoundBoxesInScene[ggData.scene].list]; area _ IF bigBox#NIL THEN [x: bigBox.loX, y: bigBox.loY, w: bigBox.hiX-bigBox.loX, h: bigBox.hiY-bigBox.loY] ELSE [0.0, 0.0, 1.0, 1.0]; [min, max] _ Geom2D.ExtremaOfRect[r: area, n: direction]; }; GGActionAreaPaint: PROC [self: Viewer, context: Imager.Context, whatChanged: REF ANY, clear: BOOL] RETURNS [quit: BOOL _ FALSE] = { PaintEntireViewer: PROC = CHECKED { BufferedRefresh.FitSandwichToScreen[ggData.refresh.sandwich, self.cw, self.ch]; GGWindow.RestoreScreenAndInvariants[paintAction: $PaintEntireScene, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; clientToViewer: Imager.Transformation _ BiScrollers.GetStyle[].GetTransforms[BiScrollers.QuaBiScroller[self]].clientToViewer; ggData: GGData; IF whatChanged = NIL THEN { --we are being called by Window Manager ggData _ NARROW[BiScrollers.ClientDataOfViewer[self]]; BufferedRefresh.FitSandwichToScreen[ggData.refresh.sandwich, self.cw, self.ch]; IF ggData.refresh.clientToViewer#NIL AND ImagerTransformation.Equal[clientToViewer, ggData.refresh.clientToViewer] THEN { -- Window Motion GGWindow.RestoreScreenAndInvariants[paintAction: $ViewersPaintAllPlanes, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; } ELSE { -- Scrolling GGWindow.RestoreScreenAndInvariants[paintAction: $ViewersPaintEntireScene, ggData: ggData, remake: none, backgndOK: TRUE, edited: FALSE, okToClearFeedback: FALSE]; }; } ELSE { ggData _ NARROW[whatChanged]; IF ggData.refresh.paintAction=$PaintEntireViewer THEN PaintEntireViewer[] ELSE GGRefresh.ActionAreaPaint[context, ggData.refresh.paintAction, ggData]; }; ggData.refresh.clientToViewer _ clientToViewer; -- for next time around }; BuildActionAreaLine: PROC [ggData: GGData, startX: CARD] RETURNS [Viewer] = { height1: CARDINAL = buttonAlign; buttonHolder: Viewer _ GetButtonHolder[parent: ggData.outer, wx: startX, wy: ggData.height]; nextX: INTEGER _ AtomButtons.BuildButtonLine [buttonHolder, 0, 0, ggData, GGUserInput.EventNotify, LIST[[button["Fetch", LIST[LIST[$MatchFetch]], -1, FALSE, NIL]] ]]; tV: Viewer _ BiScrollers.CreateFit[ [parent: buttonHolder, wx: nextX+entryHSpace, wy: height1, border: FALSE], ggData.biScroller]; tV _ BiScrollers.CreateReset[ [parent: buttonHolder, wx: tV.wx+tV.ww+entryHSpace, wy: height1, border: FALSE], ggData.biScroller]; tV_ Buttons.Create[info: [parent: buttonHolder, name: "CenterSel", wx: tV.wx+tV.ww+entryHSpace, wy: 0, border: FALSE], proc: CenterSel, clientData: ggData, paint: TRUE]; RETURN[buttonHolder]; }; RegisterMatchActions: PROC = { GGUserInput.RegisterAction[atom: $MatchFetch, eventProc: Fetch, argType: none, ensureUnique: FALSE]; -- Fetch button GGUserInput.RegisterAction[atom: $MatchSetFrom, eventProc: SetFromColumn, argType: none, ensureUnique: FALSE]; GGUserInput.RegisterAction[atom: $MatchSetTo, eventProc: SetToColumn, argType: none, ensureUnique: FALSE]; GGUserInput.RegisterAction[atom: $MatchToggle, eventProc: ToggleFromOrTo, argType: none, ensureUnique: FALSE]; -- Toggle From/To buttons GGUserInput.RegisterAction[atom: $MatchSearch, eventProc: Match.SearchEvent, argType: none, ensureUnique: FALSE]; -- Search button GGUserInput.RegisterAction[atom: $MatchYes, eventProc: Match.YesEvent, argType: none, ensureUnique: FALSE]; -- Yes button GGUserInput.RegisterAction[atom: $MatchChangeAll, eventProc: Match.ChangeAll, argType: none, ensureUnique: FALSE]; -- ChangeAll button GGUserInput.RegisterAction[atom: $MatchActionChange, eventProc: MatchActionChange, argType: none, ensureUnique: FALSE]; -- Flip through action types GGUserInput.RegisterAction[atom: $MatchLevelChange, eventProc: MatchLevelChange, argType: none, ensureUnique: FALSE]; -- Flip through action types GGUserInput.RegisterAction[atom: $MatchSearchOpChange, eventProc: MatchSearchOpChange, argType: none, ensureUnique: FALSE]; -- Flip through SearchOps GGUserInput.RegisterAction[atom: $MatchToleranceChange, eventProc: MatchToleranceChange, argType: none, ensureUnique: FALSE]; -- Adjust match tolerance GGUserInput.RegisterAction[atom: $MatchExact, eventProc: MatchExact, argType: none, ensureUnique: FALSE]; -- Toggle the Exact Match button GGUserInput.RegisterAction[atom: $MatchStartOps, eventProc: Match.StartOps, argType: none, ensureUnique: FALSE]; -- Invoke a procedure to intitiate recording of To events GGUserInput.RegisterAction[atom: $MatchEndOps, eventProc: Match.EndOps, argType: none, ensureUnique: FALSE]; -- Invoke a procedure to terminate recording of To events GGUserInput.RegisterAction[atom: $MatchGrep, eventProc: MatchGrep.Grep, argType: rope, ensureUnique: FALSE]; -- Grep for the pattern in the From viewer GGUserInput.RegisterAction[atom: $MatchGrepListOnly, eventProc: MatchGrep.GrepListOnly, argType: rope, ensureUnique: FALSE]; -- Grep for the pattern in the From viewer GGUserInput.RegisterAction[atom: $MatchNextFile, eventProc: MatchGrep.NextFile, argType: none, ensureUnique: FALSE]; -- Edit the last gargoyle file found with grep }; GetButtonHolder: PROC [parent: Viewer, wx, wy, ww: CARD _ 0, wh: CARD _ entryHeight] RETURNS [Viewer] = { IF ww = 0 THEN ww _ parent.ww; RETURN[Containers.Create[info: [name: "holder", parent: parent, wx: wx, wy: wy, ww: ww, wh: wh, border: FALSE, scrollable: FALSE], paint: FALSE]]; }; CenterSel: PUBLIC Buttons.ButtonProc = { ggData: GGData _ NARROW[clientData]; caretPos: Point _ GGCaret.GetPoint[ggData.caret]; bBox: GGModelTypes.BoundBox _ GGScene.BoundBoxOfSelected[scene: ggData.scene, selectClass: normal]; IF bBox.null THEN BiScrollers.Align[bs: ggData.biScroller, client: [variant: coord[x: caretPos.x, y: caretPos.y]], viewer: [variant: fraction[fx: 0.5, fy: 0.5]], paint: TRUE] ELSE BiScrollers.Align[bs: ggData.biScroller, client: [variant: coord[x: (bBox.loX+bBox.hiX)/2.0, y: (bBox.loY+bBox.hiY)/2.0]], viewer: [variant: fraction[fx: 0.5, fy: 0.5]], paint: TRUE]; }; FitSel: Buttons.ButtonProc = { ggData: GGData _ NARROW[clientData]; tbBox, vBox, tvBox: Geom2D.Rect; cToV: ImagerTransformation.Transformation; bBox: GGModelTypes.BoundBox _ GGScene.BoundBoxOfSelected[scene: ggData.scene, selectClass: normal]; IF NOT bBox.null THEN { cToV _ BiScrollers.GetStyle[].GetTransforms[ggData.biScroller].clientToViewer; tbBox _ ImagerTransformation.TransformRectangle[cToV, GGBoundBox.RectangleFromBoundBox[bBox] ]; vBox _ BiScrollers.ViewportBox[ggData.biScroller]; tvBox _ ImagerTransformation.TransformRectangle[cToV, vBox]; BiScrollers.BoxScale[bs: ggData.biScroller, from: tbBox, to: tvBox]; }; }; SetFromColumn: GGUserInput.UserInputProc = { SetColumn[matchData.from, event.rest.first = $SetAll]; }; SetToColumn: GGUserInput.UserInputProc = { SetColumn[matchData.to, event.rest.first = $SetAll]; }; SetColumn: PROC [choice: MatchViewer.ChoiceData, state: BOOL] = { AtomButtons.SetBinaryState[choice.class, state]; AtomButtons.SetBinaryState[choice.type, state]; AtomButtons.SetBinaryState[choice.shape, state]; AtomButtons.SetBinaryState[choice.color, state]; AtomButtons.SetBinaryState[choice.fillColor, state]; AtomButtons.SetBinaryState[choice.string, state]; AtomButtons.SetBinaryState[choice.font, state]; AtomButtons.SetBinaryState[choice.fontTform, state]; AtomButtons.SetBinaryState[choice.dash, state]; AtomButtons.SetBinaryState[choice.joints, state]; AtomButtons.SetBinaryState[choice.ends, state]; AtomButtons.SetBinaryState[choice.width, state]; }; ToggleFromOrTo: GGUserInput.UserInputProc = { FlipThreeAsUnit: PROC = { AtomButtons.SwitchBinaryState[matchData.to.class]; AtomButtons.SwitchBinaryState[matchData.to.type]; AtomButtons.SwitchBinaryState[matchData.to.shape]; }; SELECT event.rest.first FROM $FromClass => AtomButtons.SwitchBinaryState[matchData.from.class]; $ToClass => FlipThreeAsUnit[]; $FromType => AtomButtons.SwitchBinaryState[matchData.from.type]; $ToType => FlipThreeAsUnit; $FromShape => AtomButtons.SwitchBinaryState[matchData.from.shape]; $ToShape => FlipThreeAsUnit; $FromColor => AtomButtons.SwitchBinaryState[matchData.from.color]; $ToColor => AtomButtons.SwitchBinaryState[matchData.to.color]; $FromFillColor => AtomButtons.SwitchBinaryState[matchData.from.fillColor]; $ToFillColor => AtomButtons.SwitchBinaryState[matchData.to.fillColor]; $FromString => AtomButtons.SwitchBinaryState[matchData.from.string]; $ToString => AtomButtons.SwitchBinaryState[matchData.to.string]; $FromFont => AtomButtons.SwitchBinaryState[matchData.from.font]; $ToFont => AtomButtons.SwitchBinaryState[matchData.to.font]; $FromFontTform => AtomButtons.SwitchBinaryState[matchData.from.fontTform]; $ToFontTform => AtomButtons.SwitchBinaryState[matchData.to.fontTform]; $FromDash => AtomButtons.SwitchBinaryState[matchData.from.dash]; $ToDash => AtomButtons.SwitchBinaryState[matchData.to.dash]; $FromJoints => AtomButtons.SwitchBinaryState[matchData.from.joints]; $ToJoints => AtomButtons.SwitchBinaryState[matchData.to.joints]; $FromEnds => AtomButtons.SwitchBinaryState[matchData.from.ends]; $ToEnds => AtomButtons.SwitchBinaryState[matchData.to.ends]; $FromWidth => AtomButtons.SwitchBinaryState[matchData.from.width]; $ToWidth => AtomButtons.SwitchBinaryState[matchData.to.width]; $RotationInv => AtomButtons.SwitchBinaryState[matchData.rotationInv]; $ScaleInv => AtomButtons.SwitchBinaryState[matchData.scaleInv]; $Polarity => AtomButtons.SwitchBinaryState[matchData.polarity]; $Structure => AtomButtons.SwitchBinaryState[matchData.structure]; $MatchNodes => AtomButtons.SwitchBinaryState[matchData.matchNodes]; $ContextSensitive => AtomButtons.SwitchBinaryState[matchData.contextSensitive]; ENDCASE; }; MatchActionChange: GGUserInput.UserInputProc = { name: Rope.ROPE; AtomButtons.TimeToFlipThru[LIST[$FlipForward, matchData.replaceOpButton]]; name _ matchData.replaceOpButton.flipLabel.name; SELECT TRUE FROM Rope.Equal[name, "Do Replace"] => {matchData.replaceOp _ doReplace;}; Rope.Equal[name, "Do Operations"] => {matchData.replaceOp _ doOperations;}; ENDCASE => ERROR; }; MatchLevelChange: GGUserInput.UserInputProc = { name: Rope.ROPE; AtomButtons.TimeToFlipThru[LIST[$FlipForward, matchData.levelButton]]; name _ matchData.levelButton.flipLabel.name; SELECT TRUE FROM Rope.Equal[name, "Anywhere"] => matchData.matchLevel _ anywhere; Rope.Equal[name, "Trajectory Level"] => matchData.matchLevel _ trajLevel; Rope.Equal[name, "Slice Level"] => matchData.matchLevel _ sliceLevel; ENDCASE => ERROR; }; MatchSearchOpChange: GGUserInput.UserInputProc = { name: Rope.ROPE; AtomButtons.TimeToFlipThru[LIST[$FlipForward, matchData.searchOpButton]]; name _ matchData.searchOpButton.flipLabel.name; SELECT TRUE FROM Rope.Equal[name, "Disjunction"] => matchData.searchOp _ disjunction; Rope.Equal[name, "Conjunction"] => matchData.searchOp _ conjunction; ENDCASE => ERROR; }; minMatchTol: REAL _ .02; MatchToleranceChange: GGUserInput.UserInputProc = { toleranceData: ToleranceData _ NARROW[GraphicsButton.GetValue[matchData.toleranceButton].buttonData]; IF AtomButtons.GetBinaryState[matchData.exactMatch] THEN { -- Exact button is on ErrorFeedback["First turn Exact match off."]; RETURN; }; SELECT event.rest.first FROM $ValueUp => toleranceData.current _ toleranceData.current + .1; $InitialValue => toleranceData.current _ initialTolerance; $ValueDown => toleranceData.current _ toleranceData.current - .1; ENDCASE => ERROR; toleranceData.current _ MAX[MIN[toleranceData.current, 1.0], minMatchTol]; GraphicsButton.SetButtonValueAndPaint[matchData.toleranceButton, ggData, toleranceData]; }; MatchExact: GGUserInput.UserInputProc = { toleranceData: ToleranceData _ NARROW[GraphicsButton.GetValue[matchData.toleranceButton].buttonData]; AtomButtons.SwitchBinaryState[matchData.exactMatch]; GraphicsButton.SetButtonValueAndPaint[matchData.toleranceButton, ggData, toleranceData]; }; GetMatchTolerance: PUBLIC PROC RETURNS [REAL] = { toleranceData: ToleranceData _ NARROW[GraphicsButton.GetValue[matchData.toleranceButton].buttonData]; IF AtomButtons.GetBinaryState[matchData.exactMatch] THEN RETURN[minMatchTol] -- Exact button is on, so it overrides tolerance value ELSE RETURN[toleranceData.current]; }; GetContextSensitive: PUBLIC PROC [matchData: MatchData] RETURNS [contextSensitive: BOOL] = { contextSensitive _ AtomButtons.GetBinaryState[matchData.contextSensitive]; }; Fetch: GGUserInput.UserInputProc = { SortNewEntities: PROC [entityList: LIST OF Slice] RETURNS [sorted: LIST OF Slice] = { CompareProc: GGUtility.SliceCompareProc = { priority1, priority2: INT; priority1 _ ref1.priority; priority2 _ ref2.priority; RETURN[Basics.CompareInt[priority1, priority2]]; }; sorted _ GGUtility.SortSliceList[entityList, CompareProc]; }; theirScene: Scene _ NIL; ourScene: Scene _ ggData.scene; feedback: FeedbackData _ ggData.feedback; sliceDGen: SliceDescriptorGenerator; outSeqGen: GGSelect.OutlineSequenceGenerator; newOutline, outline: Slice; newTraj: Traj; newSlice: Slice; newSlices: LIST OF Slice; theirData: GGData _ GetGGInputFocus[]; IF theirData = NIL THEN RETURN ELSE theirScene _ theirData.scene; sliceDGen _ GGSelect.SelectedSlices[theirScene, normal]; FOR sliceD: SliceDescriptor _ GGSelect.NextSliceDescriptor[sliceDGen], GGSelect.NextSliceDescriptor[sliceDGen] UNTIL sliceD = NIL DO IF sliceD.slice.class.type#$Outline THEN { -- outlines are handled separately, below newSlice _ GGSlice.CopySlice[sliceD.slice]; -- make the new one newSlice.priority _ GGScene.GetPriority[theirScene, sliceD.slice]; newSlices _ CONS[newSlice, newSlices]; }; ENDLOOP; BEGIN outSeqGen _ GGSelect.SelectedOutlineSequences[theirScene, normal]; FOR outSeq: GGSelect.OutlineSequence _ GGSelect.NextOutlineSequences[outSeqGen], GGSelect.NextOutlineSequences[outSeqGen] UNTIL outSeq = NIL DO outline _ outSeq.outline; IF outSeq.fenceSeq # NIL THEN { IF NOT GGSequence.ContainsSomeSegment[outSeq.fenceSeq] THEN GOTO NoSegmentsSelected; IF GGSelect.IsSelectedInFull[outline, theirScene, normal] THEN { newOutline _ outline.class.copy[outline]; newOutline.priority _ GGScene.GetPriority[theirScene, outline]; newSlices _ CONS[newOutline, newSlices]; LOOP; } ELSE { newTraj _ GGTraj.CopyTrajFromRun[outSeq.fenceSeq]; newOutline _ GGOutline.CreateOutline[newTraj, outline.class.getFillColor[outline]]; newOutline.priority _ GGScene.GetPriority[theirScene, outline]; newSlices _ CONS[newOutline, newSlices]; }; }; FOR holeSeq: Sequence _ GGSequence.NextSequence[outSeq.holeSeqs], GGSequence.NextSequence[outSeq.holeSeqs] UNTIL holeSeq = NIL DO IF NOT GGSequence.ContainsSomeSegment[holeSeq] THEN GOTO NoSegmentsSelected; newTraj _ GGTraj.CopyTrajFromRun[holeSeq]; newOutline _ GGOutline.CreateOutline[newTraj, outline.class.getFillColor[outline]]; newOutline.priority _ GGScene.GetPriority[theirScene, outline]; newSlices _ CONS[newOutline, newSlices]; ENDLOOP; ENDLOOP; newSlices _ SortNewEntities[newSlices]; FOR sliceList: LIST OF Slice _ newSlices, sliceList.rest UNTIL sliceList = NIL DO allParts: SliceDescriptor; GGScene.AddSlice[ourScene, sliceList.first, -1]; allParts _ sliceList.first.class.newParts[sliceList.first, NIL, slice]; GGSelect.SelectSlice[allParts, ourScene, normal]; ENDLOOP; GGAlign.UpdateBagsForNewSlices[newSlices, ggData]; ggData.refresh.startBoundBox _ GGScene.BoundBoxOfSelected[ggData.scene, normal]; GGWindow.RestoreScreenAndInvariants[paintAction: $FinishedDragging, ggData: ggData, remake: sceneBag, backgndOK: FALSE, edited: TRUE, okToClearFeedback: TRUE]; EXITS NoSegmentsSelected => { Feedback.AppendHerald[feedback, ". . . Cannot Copy Joints or CPs", begin]; Feedback.Blink[feedback]; GGSelect.DeselectAll[theirScene, normal]; }; END; }; column0: CARD = 0; -- x coordinate of Characteristics column column1: CARD = 135; -- x coordinate of From column column2: CARD = 195; -- x coordinate of To column column3: CARD = 245; -- x coordinate of Search button line upperMargin: CARD = 8; -- Vertical space between actionAreas and Characteristics line lowerMargin: CARD = 5; -- Extra space between Characteristics description line and FromTo entries fromBoxOffset: CARD = 14; -- column1 + fromBoxOffset = x location of From boxes toBoxOffset: CARD = 4; -- column2 + toBoxOffset = x location of To boxes matchData: MatchData _ NewMatchDataObj[]; NewMatchDataObj: PUBLIC PROC RETURNS [matchData: MatchData] = { matchData _ NEW[MatchDataObj]; matchData.from _ NEW[ChoiceDataObj]; matchData.to _ NEW[ChoiceDataObj]; }; InitControlPanel: PROC [parent: Viewer, startHeight: CARD] = { MakeFromToEntry: PROC [string: Rope.ROPE, parent: Viewer, height: CARD, fromAction: LIST OF REF ANY, toAction: LIST OF REF ANY] RETURNS [fromState, toState: AtomButtons.TwoState, newHeight: CARD] = { [] _ Labels.Create[[name: string, parent: parent, wx: column0, wy: height, border: FALSE]]; [] _ AtomButtons.BuildButtonLine[container: parent, x: column1 + fromBoxOffset, y: height, clientData: parent.data, handleProc: GGUserInput.EventNotify, entries: LIST [ [twoState[" ", fromAction, FALSE, FillGlobalTwoState]]]]; fromState _ globalTwoState; [] _ AtomButtons.BuildButtonLine[container: parent, x: column2 + toBoxOffset, y: height, clientData: parent.data, handleProc: GGUserInput.EventNotify, entries: LIST [ [twoState[" ", toAction, FALSE, FillGlobalTwoState]]]]; toState _ globalTwoState; newHeight _ height + entryHeight + entryVSpace; }; height: CARD _ startHeight; [] _ Labels.Create[[name: "CHARACTERISTICS", parent: parent, wx: column0, wy: height, border: FALSE]]; [] _ AtomButtons.BuildButtonLine[container: parent, x: column1, y: height, clientData: parent.data, handleProc: GGUserInput.EventNotify, entries: LIST[ [button["FROM", LIST[LIST[$MatchSetFrom, $ClearAll], LIST[$MatchSetFrom, $ClearAll], LIST[$MatchSetFrom, $SetAll]]]]]]; [] _ AtomButtons.BuildButtonLine[container: parent, x: column2, y: height, clientData: parent.data, handleProc: GGUserInput.EventNotify, entries: LIST[ [button["TO", LIST[LIST[$MatchSetTo, $ClearAll], LIST[$MatchSetTo, $ClearAll], LIST[$MatchSetTo, $SetAll]]]]]]; height _ height + entryHeight + lowerMargin; [matchData.from.class, matchData.to.class, height] _ MakeFromToEntry["Object class", parent, height, LIST[$MatchToggle, $FromClass], LIST[$MatchToggle, $ToClass]]; [matchData.from.type, matchData.to.type, height] _ MakeFromToEntry["Object type", parent, height, LIST[$MatchToggle, $FromType], LIST[$MatchToggle, $ToType]]; [matchData.from.shape, matchData.to.shape, height] _ MakeFromToEntry["Object shape", parent, height, LIST[$MatchToggle, $FromShape], LIST[$MatchToggle, $ToShape]]; [matchData.from.color, matchData.to.color, height] _ MakeFromToEntry["Object color", parent, height, LIST[$MatchToggle, $FromColor], LIST[$MatchToggle, $ToColor]]; [matchData.from.fillColor, matchData.to.fillColor, height] _ MakeFromToEntry["Object fill color", parent, height, LIST[$MatchToggle, $FromFillColor], LIST[$MatchToggle, $ToFillColor]]; [matchData.from.string, matchData.to.string, height] _ MakeFromToEntry["Text string", parent, height, LIST[$MatchToggle, $FromString], LIST[$MatchToggle, $ToString]]; [matchData.from.font, matchData.to.font, height] _ MakeFromToEntry["Text font", parent, height, LIST[$MatchToggle, $FromFont], LIST[$MatchToggle, $ToFont]]; [matchData.from.fontTform, matchData.to.fontTform, height] _ MakeFromToEntry["Text font & transform", parent, height, LIST[$MatchToggle, $FromFontTform], LIST[$MatchToggle, $ToFontTform]]; [matchData.from.dash, matchData.to.dash, height] _ MakeFromToEntry["Line dashes", parent, height, LIST[$MatchToggle, $FromDash], LIST[$MatchToggle, $ToDash]]; [matchData.from.joints, matchData.to.joints, height] _ MakeFromToEntry["Line joints", parent, height, LIST[$MatchToggle, $FromJoints], LIST[$MatchToggle, $ToJoints]]; [matchData.from.ends, matchData.to.ends, height] _ MakeFromToEntry["Line ends", parent, height, LIST[$MatchToggle, $FromEnds], LIST[$MatchToggle, $ToEnds]]; [matchData.from.width, matchData.to.width, height] _ MakeFromToEntry["Line width", parent, height, LIST[$MatchToggle, $FromWidth], LIST[$MatchToggle, $ToWidth]]; InitRightControlPanel[parent, startHeight]; }; InitRightControlPanel: PROC [parent: Viewer, startHeight: CARD] = { nextX: CARD; height: CARD _ startHeight - buttonAlign; [] _ AtomButtons.BuildButtonLine [parent, column3, height, parent.data, GGUserInput.UnQueuedEventNotify, LIST[ [button["Search", LIST[LIST[$MatchSearch, $SearchBelow], LIST[$MatchSearch, $SearchFromTop], LIST[$MatchSearch, $SearchAbove]]]], [button["Yes", LIST[LIST[$MatchYes, $SearchBelow], LIST[$MatchYes, $SearchFromTop], LIST[$MatchYes, $SearchAbove]]]], [button["No", LIST[LIST[$MatchSearch, $SearchBelow], LIST[$MatchSearch, $SearchFromTop], LIST[$MatchSearch, $SearchAbove]]]], [button["ChangeAll", LIST[LIST[$MatchChangeAll, $SearchBelow], LIST[$MatchChangeAll, $SearchFromTop], LIST[$MatchChangeAll, $SearchAbove]]]]]]; height _ height + entryHeight + entryVSpace; matchData.replaceOpButton _ AtomButtons.BuildEnumTypeSelection[viewer: parent, x: column3, y: height, maxWidth: 0, clientData: parent.data, handleProc: GGUserInput.EventNotify, title: "Action:", default: "Do Replace", borderOnButtons: TRUE, style: flipThru, allInOneRow: TRUE, buttonNames: LIST["Do Replace", "Do Operations"], atom: $MatchActionChange]; matchData.replaceOp _ doReplace; height _ height + entryHeight + entryVSpace; matchData.levelButton _ AtomButtons.BuildEnumTypeSelection[viewer: parent, x: column3, y: height, maxWidth: 0, clientData: parent.data, handleProc: GGUserInput.EventNotify, title: "Match:", default: "Slice Level", borderOnButtons: TRUE, style: flipThru, allInOneRow: TRUE, buttonNames: LIST["Anywhere", "Trajectory Level", "Slice Level"], atom: $MatchLevelChange]; matchData.matchLevel _ trajLevel; height _ height + entryHeight + entryVSpace; matchData.searchOpButton _ AtomButtons.BuildEnumTypeSelection[viewer: parent, x: column3, y: height, maxWidth: 0, clientData: parent.data, handleProc: GGUserInput.EventNotify, title: "SearchOp:", default: "Disjunction", borderOnButtons: TRUE, style: flipThru, allInOneRow: TRUE, buttonNames: LIST["Disjunction", "Conjunction"], atom: $MatchSearchOpChange]; matchData.searchOp _ disjunction; height _ height + entryHeight + entryVSpace; nextX _ AtomButtons.BuildButtonLine[container: parent, x: column3, y: height, clientData: parent.data, handleProc: GGUserInput.EventNotify, entries: LIST[ [twoState["Exact", LIST[$MatchExact], TRUE, FillExact]], [label["Tolerance:"]]]]; nextX _ GraphicsButton.BuildGraphicsButton[container: parent, x: nextX, y: height, w: 60, h: entryHeight, clientData: parent.data, choices: LIST[[LIST[$MatchToleranceChange, $ValueDown]], [LIST[$MatchToleranceChange, $InitialValue]], [LIST[$MatchToleranceChange, $ValueUp]]], handleProc: GGUserInput.EventNotify, repaintProc: ToleranceButtonRepaint, buttonData: NEW[ToleranceDataObj], updateProc: ToleranceButtonUpdate]; height _ height + entryHeight + entryVSpace; nextX _ AtomButtons.BuildButtonLine[container: parent, x: column3, y: height, clientData: parent.data, handleProc: GGUserInput.EventNotify, entries: LIST[ [twoState["RotationInv", LIST[$MatchToggle, $RotationInv], FALSE, FillRotationInv]], [twoState["ScaleInv", LIST[$MatchToggle, $ScaleInv], FALSE, FillScaleInv]]]]; height _ height + entryHeight + entryVSpace; nextX _ AtomButtons.BuildButtonLine[container: parent, x: column3, y: height, clientData: parent.data, handleProc: GGUserInput.EventNotify, entries: LIST[ [twoState["Polarity", LIST[$MatchToggle, $Polarity], TRUE, FillPolarity]], [twoState["ContextSensitive", LIST[$MatchToggle, $ContextSensitive], FALSE, FillContextSensitive]]]]; height _ height + entryHeight + entryVSpace; nextX _ AtomButtons.BuildButtonLine[container: parent, x: column3, y: height, clientData: parent.data, handleProc: GGUserInput.EventNotify, entries: LIST[ [button["StartOps", LIST[LIST[$MatchStartOps], LIST[$MatchStartOps], LIST[$MatchStartOps]]]], [button["EndOps", LIST[LIST[$MatchEndOps], LIST[$MatchEndOps], LIST[$MatchEndOps]]]]]]; height _ height + entryHeight + entryVSpace; nextX _ AtomButtons.BuildButtonLine[container: parent, x: column3, y: height, clientData: parent.data, handleProc: GGUserInput.EventNotify, entries: LIST [ [button["Grep", LIST[LIST[$MatchGrep], LIST[$MatchGrep], LIST[$MatchGrepListOnly]]]], [button["NextFile", LIST[LIST[$MatchNextFile], LIST[$MatchNextFile], LIST[$MatchNextFile]]]]]]; }; globalTwoState: AtomButtons.TwoState; FillGlobalTwoState: AtomButtons.InitTwoStateProc = {globalTwoState _ twoState;}; FillExact: AtomButtons.InitTwoStateProc = {matchData.exactMatch _ twoState;}; FillRotationInv: AtomButtons.InitTwoStateProc = {matchData.rotationInv _ twoState;}; FillScaleInv: AtomButtons.InitTwoStateProc = {matchData.scaleInv _ twoState;}; FillPolarity: AtomButtons.InitTwoStateProc = {matchData.polarity _ twoState;}; FillStructure: AtomButtons.InitTwoStateProc = {matchData.structure _ twoState;}; FillMatchNodes: AtomButtons.InitTwoStateProc = {matchData.matchNodes _ twoState;}; FillContextSensitive: AtomButtons.InitTwoStateProc = {matchData.contextSensitive _ twoState;}; initialTolerance: REAL = 0.2; ToleranceData: TYPE = REF ToleranceDataObj; ToleranceDataObj: TYPE = RECORD [ current: REAL _ initialTolerance ]; ToleranceButtonRepaint: PROC [dc: Imager.Context, clientData: REF ANY, buttonData: REF ANY, button: Viewer] = { caretPoint: Point; tol: REAL _ GetMatchTolerance[]; extent: REAL _ tol * button.ww; Imager.TranslateT[dc, [0, button.wh/2.0]]; caretPoint _ [extent, 0.0]; GGShapes.DrawCaret[dc, caretPoint, [0, -1]]; }; ToleranceButtonUpdate: AtomButtonsTypes.UpdateGraphicsButtonProc = { matchData.toleranceButton _ stateInfo; }; ErrorFeedback: PUBLIC PROC [message: Rope.ROPE] = { ggData: GGData _ GetToData[]; Feedback.PutFHerald[ggData.feedback, oneLiner, message]; Feedback.Blink[ggData.feedback]; }; GetGGInputFocus: PUBLIC PROC RETURNS [theirData: GGData _ NIL] = { inputFocus: InputFocus.Focus _ InputFocus.GetInputFocus[]; theirViewer: Viewer; IF inputFocus = NIL OR inputFocus.owner = NIL THEN RETURN; theirViewer _ inputFocus.owner; IF theirViewer.class.flavor # $ActionArea THEN ErrorFeedback["Place input focus in a Gargoyle viewer."] ELSE theirData _ NARROW[BiScrollers.ClientDataOf[NARROW[theirViewer.data, BiScrollers.BiScroller]], GGData]; }; GetMatchData: PUBLIC PROC RETURNS [MatchData] = { RETURN [matchData]; }; FindAGargoyleViewer: PROC RETURNS [ggData: GGData _ NIL] = { IsGargoyleViewer: ViewerOps.EnumProc = { IF Rope.Equal["Gargoyle", Rope.Substr[v.name, 0, 8]] AND ISTYPE[v.data, GGData] THEN { ggData _ NARROW[v.data]; RETURN[FALSE]; -- terminate enumeration } ELSE RETURN[TRUE]; -- continue enumerating }; ViewerOps.EnumerateViewers[IsGargoyleViewer]; -- look for a viewer whose name starts with "Gargoyle" }; MatchCommand: Commander.CommandProc = { matchData.commander _ cmd; matchData.hostData _ FindAGargoyleViewer[]; -- so we can leach on its menu and use its SlackProcess IF matchData.hostData = NIL THEN IO.PutRope[cmd.err, "Invoke a gargoyle viewer first.\n"] ELSE InitViewers[]; }; matchToolIcon: Icons.IconFlavor _ Icons.NewIconFromFile["Gargoyle.icons", 4]; -- shares Icon file with Gargoyle RegisterMatchActions[]; Commander.Register["MatchTool", MatchCommand]; END. pMatchViewerImpl.mesa Last edited by: David Kurlander - September 5, 1987 4:36:00 pm PDT Bier, September 5, 1987 1:26:38 am PDT Pier, September 8, 1987 3:16:38 pm PDT Building a MatchTool Viewer Builds the GGData for the MatchTool From and To viewers. outer is the MatchTool Container. [] _ SlackProcess.EnableAborts[handle: ggData.slackHandle]; Creates a single feedback line for two action areas (represented by data1 and data2) and the grepData Create an action area, complete with handy Viewer-Control line vanilla: GGBasicTransformProc, --proc which provides the vanilla transform for BiScrollers only initial values for ww and wh. They are constrained below This proc is required by BiScrollers to return the extremes of the displayed data ViewerClasses.PaintProc. whatChanged is a GGData. self is an ActionArea. We are called for one of two reasons: scrolling in an already open window, or reopening a window. If we are reopening we can take advantage of the fact that the sandwich may still be valid from when we closed the window. We detect this by comparing the new BiScrollers clientToViewer transform with the one we saved last time we came through here. If they are the same, we assume we can use the old sandwich. Implementations of Viewing Operations Change scale and offsets so that client data previously in `from' covers as much as possible of `to' (from and to in viewer coords). Handling Match Mode Buttons Presses Fetch Selected from Gargoyle Viewer Borrowed with modifications from GGMouseEventImplA (UpdateSceneForCopy) Sort back to front (in increasing order). [ref1: Slice, ref2: Slice] RETURNS [Basics.Comparison] Get Scene from InputFocus' Viewer Copy selected slices. GGSelect.DeselectSlice[sliceD.slice, sliceD.parts, theirScene, normal]; Copy selected outlines, or outline parts. If the whole outline is selected, copy it as a whole. GGSelect.DeselectEntireSlice[outline, theirScene, normal]; -- deselect the old one Otherwise, each piece becomes a new slice. GGSelect.DeselectSequence[outSeq.fenceSeq, theirScene, normal]; GGSelect.DeselectSequence[holeSeq, theirScene, normal]; Sort the new slices Add all the new slices to ourScene. We are about to self-abort. We deselect all so that we don't delete any of the original geometry (see AbortCopyAndDrag above). Building the MatchTool Menus CHARACTERISTICS FROM/TO control section [] _ Labels.Create[[name: "FROM", parent: parent, wx: column1, wy: height, border: FALSE]]; [] _ Labels.Create[[name: "TO", parent: parent, wx: column2, wy: height, border: FALSE]]; SEARCH/YES/NO/CHANGEALL, etc... Yes and ChangeAll must be unqueued so they don't cause SlackProcess monitor deadlock on doOps playback Various InitTwoStateProcs used in creating TwoStateButtons during control panel initialization Handling Presses Of The Tolerance Button. Essentially GGMenusImpl.GravityExtentRepain Miscellaneous Actions to perform on load. Ê#o˜code™KšœC™CK™&K™&—K˜šÏk ˜ KšœÛœ_˜¼K˜šÏnœœ˜Kšœÿœ4˜¼Kšœ˜——˜Kšœ œ˜)Kšœœœ ˜Kšœ œ˜+Kšœœ˜0Kšœœ˜+Kšœ œ˜/Kšœ œ˜-Kšœœ˜'Kšœ œ˜(Kšœœ˜.Kšœœ˜!Kšœ œ˜'Kšœœ˜!Kšœœ˜!Kšœœ ˜5Kšœœ)˜GKšœœ˜Kšœœ˜$K˜KšœœÏc*˜LKšœœŸ$˜DKšœœ˜)Kšœ œŸC˜^Kšœ œŸ˜8Kšœ œŸ)˜DKšœ œŸ!˜šœZ˜ZKšœ˜KšÐrt˜Kšœ ˜ Kšœ˜Kšœ9˜9Kšœ œŸ&˜9Kšœœ˜Kšœœ˜!KšœŸ;™ZKšœŸ@˜[Kšœ˜—šœE˜EKšœ˜šœ˜Kšœ˜Kšœ˜Kšœ Ÿ˜KšœŸ˜(Kšœ>™>Kšœ ˜ Kšœœ˜ Kšœ œ˜—Kšœ˜ Kšœ˜—Kšœ(œ˜.Kšœ˜Kšœ=Ÿ˜\K˜1Kšœœ˜#Kšœ˜K˜—š Ðbn œœœœœŸœ˜K™QKšœ˜Kšœœ ˜$Kšœg˜gKš œœœœTœ˜‡Kšœ9˜9K˜K˜—šžœœ6œœ œœœœ˜ƒKšœJ™Jšžœœœ˜#KšœO˜OKšœmœ œœ˜œK˜—Kšœ~˜~Kšœ˜šœœœŸ'˜CK™›K˜Kšœ œ'˜6KšœO˜Oš œœœKœŸ˜ŠKšœrœ œœ˜¡K˜—šœŸ ˜Kšœtœ œœ˜£Kšœ˜—Kšœ˜—šœ˜Kšœ œ˜Kšœ/œÏbœ˜NKšœG˜GKšœ˜—Kšœ0Ÿ˜Gšœ˜K˜——šžœœœœ ˜MKšœ œ˜ Kšœ\˜\š œœUœœœœœ˜¢K˜—Kšœgœ˜‚Kšœgœ˜‚Kšœoœ/œ˜©Kšœ˜K˜K˜—šžœœ˜Kšœ]œŸ˜tK–£[atom: ATOM, eventProc: GGUserInput.UserInputProc, argType: GGUserInput.ArgumentType, causeMouseEventsToComplete: BOOL _ TRUE, ensureUnique: BOOL _ TRUE]šœgœ˜nK–£[atom: ATOM, eventProc: GGUserInput.UserInputProc, argType: GGUserInput.ArgumentType, causeMouseEventsToComplete: BOOL _ TRUE, ensureUnique: BOOL _ TRUE]šœcœ˜jKšœgœŸ˜ˆKšœjœŸ˜‚KšœdœŸ ˜yKšœkœŸ˜†KšœpœŸ˜”KšœnœŸ˜’KšœtœŸ˜•K– [atom: ATOM, eventProc: SlackProcess.EventProc, argType: GGUserInput.ArgumentType, causeMouseEventsToComplete: BOOL _ TRUE, ensureUnique: BOOL _ TRUE]šœvœŸ˜—KšœbœŸ ˜ŠKšœiœŸ9˜ªKšœeœŸ9˜¦KšœeœŸ*˜—KšœuœŸ*˜§KšœmœŸ.˜£K˜K˜—š žœœœ œœ ˜iKšœœ˜Kšœbœœ œ˜’K˜K˜—K™K™%K™šž œœ˜(Kšœœ ˜$K–f[gargoyleData: GGInterfaceTypes.GargoyleData, selectClass: GGSegmentTypes.SelectionClass _ normal]šœ1˜1Kšœc˜cK–œ[bs: BiScrollers.BiScroller, client: BiScrollers.Location, viewer: BiScrollers.Location, doX: BOOL _ TRUE, doY: BOOL _ TRUE, paint: BOOL _ TRUE]šœ œ˜œ˜®Kšœ²œ˜¼K˜K˜—šžœ˜Kšœœ ˜$K–f[gargoyleData: GGInterfaceTypes.GargoyleData, selectClass: GGSegmentTypes.SelectionClass _ normal]šœ ˜ Kšœ*˜*Kšœc˜cšœœ œ˜KšœN˜NK–O[m: ImagerTransformation.Transformation, r: ImagerTransformation.Rectangle]šœ_˜_Kšœ2˜2Kšœ<˜<šœD˜DKšœ„™„—K˜—K˜K˜—K˜K™#K™šž œ˜,K˜6K˜K˜—šž œ˜*K˜4K˜K˜—šž œœ)œ˜AK˜0K˜/K˜0K˜0K˜4K˜1K˜/K˜4K˜/K˜1K˜/K˜0K˜K˜—šžœ˜-šžœœ˜J˜2J˜1J˜2J˜—šœ˜J˜BJ˜J˜@J˜J˜BJ˜J˜BJ˜>J˜JJ˜FJ˜DJšœ@˜@J˜@J˜J˜EJ˜?J˜?J˜AJ˜CJ˜OJšœ˜J˜J˜——šžœ˜0Kšœ œ˜Kšœœ+˜JKšœ0˜0šœœ˜K˜EK˜KKšœœ˜—K˜K˜—šžœ˜/Kšœ œ˜Kšœœ'˜FK˜,šœœ˜K˜@K˜IK˜EKšœœ˜—K˜K˜—šžœ˜2Kšœ œ˜Kšœœ*˜IK˜/šœœ˜K˜DK˜DKšœœ˜—K˜K˜—Kšœ œ˜šžœ˜3Kšœœ@˜ešœ2œŸ˜PKšœÏiœ˜-Kšœ˜K˜—šœ˜K˜?K˜:K˜AKšœœ˜—Kšœœœ+˜JK˜XK˜K˜—šž œ˜)Kšœœ@˜eJ˜4K˜XK˜J˜—š žœœœœœ˜1Kšœœ@˜eKšœ2œœŸ6˜ƒKšœœ˜#K˜K˜—š žœœœœœ˜\KšœJ˜JK˜—K˜Kšœ#™#K˜šžœ˜$K™Gšžœœœœœ œœ ˜UK™)šž œ ˜+Kšœœ™6Kšœœ˜Kšœ˜Kšœ˜Kšœ*˜0K˜—Kšœ:˜:K˜K˜—Kšœœ˜K˜K˜)Kšœ$˜$K˜-Kšœ˜Kšœ˜K˜Kšœ œœ˜KšÐbi!™!K˜&Kšœ œœ˜Kšœ˜"Kš¢™Kšœ0¢œ˜8šœlœ œ˜„šœ"œŸ)˜TJšœ,Ÿ˜?JšœB˜BJšœG™GJšœ œ˜&J˜—Jšœ˜—š˜Kš¢)™)JšœB˜Bšœwœ œ˜Jšœ˜šœœœ˜Kšœœ1œœ˜TJš¢5™5šœ8œ˜@Jšœ)˜)Jšœ?˜?JšœS™SJšœ œ˜(JšÐbkœ˜J˜—Jš¢*™*šœ˜Jšœ2˜2J–f[traj: GGModelTypes.Traj, lineEnds: Imager.StrokeEnd _ square, fillColor: ImagerColorDefs.Color]šœS˜SJšœ?˜?Jšœ?™?Jšœ œ˜(J˜—J˜—šœhœ œ˜Kšœœ)œœ˜LJšœ*˜*J–f[traj: GGModelTypes.Traj, lineEnds: Imager.StrokeEnd _ square, fillColor: ImagerColorDefs.Color]šœS˜SJšœ?˜?Jšœ7™7Jšœ œ˜(Jšœ˜—Jšœ˜—Jš¢™Jšœ'˜'Jš¢#™#š œ œœ#œ œ˜QJšœ˜Jšœ0˜0Jšœ;œ ˜GJšœ1˜1Jšœ˜—J˜2J˜PKšœqœ œœ˜Ÿš˜šœ˜KšœJ˜JKšœ˜šœ)˜)K™—J˜——Jšœ˜—J˜J˜—J˜™Jšœ œŸ)˜˜UJšœ œŸJ˜aJšœœŸ5˜OJšœ œŸ1˜H—J˜Jšœ)˜)J˜šžœœœœ˜?Jšœ œ˜Jšœœ˜$Jšœœ˜"J˜J˜—šžœœœ˜>šžœœœœœœœœ œœœœœ7œ˜ÇJšœSœ˜[šœ¢œ˜¨Kšœœ˜:—K˜šœ œ˜¦Kšœœ˜8—J˜J˜/J˜—Jšœœœ™'Jšœœ˜Jšœ^œ˜f–ë[container: ViewerClasses.Viewer, x: NAT, y: NAT, clientData: REF ANY, handleProc: AtomButtonsTypes.HandleButtonProc, entries: LIST OF AtomButtons.ButtonLineEntry, horizontalSpace: INTEGER _ 2, lineHeight: INTEGER _ 15]šœ’œ˜—Jš œœœœœ˜w—–ë[container: ViewerClasses.Viewer, x: NAT, y: NAT, clientData: REF ANY, handleProc: AtomButtonsTypes.HandleButtonProc, entries: LIST OF AtomButtons.ButtonLineEntry, horizontalSpace: INTEGER _ 2, lineHeight: INTEGER _ 15]šœ’œ˜—Jš œœœœœ˜o—JšœSœ™[JšœQœ™YJ˜,Jšœeœœ˜£Jšœbœœ˜žJšœeœœ˜£Jšœeœœ˜£Jšœrœ œ˜¸Jšœfœœ˜¦Jšœ`œœ˜œJšœvœ œ˜¼Jšœbœœ˜žJšœfœœ˜¦Jšœ`œœ˜œJšœcœœ˜¡J˜+J˜J˜—šžœœœ˜CJšœœœ œ™Jšœœ˜ Jšœœ˜)J™fšœjœ˜oJš œ ¢œœœœ œ ˜Jš œ ¢œœœœœ˜uJš œ ¢œœœœ œ ˜}Jš œ ¢ œœœ!œ#œ%˜—J˜,Kš œëœ œœ¢ œ¢ œ˜áK˜ K˜,Kš œçœ œœ¢œ¢œ¢ œ˜ìK˜!K˜,K–ø[viewer: ViewerClasses.Viewer, x: NAT, y: NAT, maxWidth: NAT, clientData: REF ANY, handleProc: AtomButtonsTypes.HandleButtonProc, title: ROPE, default: ROPE, borderOnButtons: BOOL, style: AtomButtonsTypes.StyleChoice, allInOneRow: BOOL, buttonNames: AtomButtonsTypes.ButtonList, atom: ATOM, horizontalSpace: INTEGER _ 2, lineHeight: INTEGER _ 15]š œíœ œœ¢ œ¢ œ ˜äK˜!K˜,šœ•œ˜šKšœ ¢œœœ˜8Kšœ¢ œ˜—K–Ð[container: ViewerClasses.Viewer, x: INTEGER, y: INTEGER, w: INTEGER, h: INTEGER, clientData: REF ANY, choices: AtomButtonsTypes.GBChoiceList, handleProc: AtomButtonsTypes.HandleButtonProc, repaintProc: AtomButtonsTypes.RepaintProc, buttonData: REF ANY _ NIL, updateProc: AtomButtonsTypes.UpdateGraphicsButtonProc]š œŒœœ'œ*œ{œ7˜¤K˜,–Š[viewer: ViewerClasses.Viewer, x: NAT _ 0, y: NAT _ 0, clientData: REF ANY, handleProc: AtomButtonsTypes.HandleButtonProc, name: ROPE, border: BOOL _ TRUE, init: AtomButtonsTypes.StateType _ off, action: LIST OF REF ANY, lineHeight: INTEGER _ 15]šœ•œ˜šKšœ ¢ œœœ˜TKšœ ¢œœœ˜M—K˜,–Š[viewer: ViewerClasses.Viewer, x: NAT _ 0, y: NAT _ 0, clientData: REF ANY, handleProc: AtomButtonsTypes.HandleButtonProc, name: ROPE, border: BOOL _ TRUE, init: AtomButtonsTypes.StateType _ off, action: LIST OF REF ANY, lineHeight: INTEGER _ 15]šœ•œ˜šKšœ ¢œœœ˜JKšœ ¢œœ#œ˜e—K˜,šœ•œ˜šKš œ ¢œœœœœ˜]Kš œ ¢œœœœœ˜W—K˜,šœ•œ˜›Kš œ ¢œœœœœ˜UKš œ ¢œœœœœ˜_—J˜J˜—J™Jšœ^™^J™J˜%Jšžœ>˜PJšž œD˜MJšžœE˜TJšž œB˜NJšž œB˜NJšž œC˜PJšžœD˜RJšžœJ˜^J˜J™)J™Jšœœ˜Jšœœœ˜+šœœœ˜!Jšœ œ˜ J˜J˜—š žœœ"œœœœ˜oJšœ+™+J˜Jšœœ˜ Jšœœ˜Kšœ*˜*Kšœ˜Kšœ,˜,K˜K˜—šžœ/˜DK˜&K˜K˜—K˜K™ K™šž œ œœ˜3K˜K˜8K˜ K˜K˜—šžœ œœœ˜BK˜:K˜Kš œœœœœœ˜:K˜Kšœ)œ9˜hKšœ œœ5˜lK˜K˜—šž œœœœ˜1Kšœ ˜K˜K˜—šžœœœœ˜<šžœ˜(šœ3œœœ˜VKšœ œ ˜KšœœŸ˜'K˜—KšœœœŸ˜*K˜—Kšœ.Ÿ6˜dK˜J˜—K™Kšœ™K™šž œ˜'J˜Jšœ,Ÿ7œ˜dJšœœœœ6˜YJšœ˜J˜J˜—KšœOŸ!˜pK˜K˜.Kšœ˜K˜J˜—…—…:´